summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp18
-rw-r--r--ApiDocs.bp2
-rw-r--r--StubLibraries.bp66
-rw-r--r--apct-tests/perftests/core/src/android/os/ParcelStringPerfTest.java70
-rw-r--r--apct-tests/perftests/core/src/android/os/VibratorPerfTest.java18
-rw-r--r--apct-tests/perftests/core/src/android/util/CharsetUtilsPerfTest.java91
-rw-r--r--apct-tests/perftests/core/src/android/util/XmlPerfTest.java292
-rw-r--r--apct-tests/perftests/core/src/android/view/InputStageBenchmark.java237
-rw-r--r--apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java132
-rw-r--r--apct-tests/perftests/inputmethod/Android.bp (renamed from packages/CarSystemUI/samples/sample1/rro/Android.bp)27
-rw-r--r--apct-tests/perftests/inputmethod/AndroidManifest.xml44
-rw-r--r--apct-tests/perftests/inputmethod/AndroidTest.xml73
-rw-r--r--apct-tests/perftests/inputmethod/README.md40
-rw-r--r--apct-tests/perftests/inputmethod/res/xml/simple_method.xml (renamed from packages/CarSystemUI/samples/sample3/rro/res/values/colors.xml)6
-rw-r--r--apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java149
-rw-r--r--apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java380
-rw-r--r--apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java165
-rw-r--r--apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java13
-rw-r--r--apex/Android.bp2
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobParameters.java4
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobScheduler.java3
-rw-r--r--apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java85
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java44
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java15
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java59
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java217
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java15
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java68
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java9
-rw-r--r--apex/media/framework/TEST_MAPPING3
-rw-r--r--apex/media/framework/java/android/media/MediaParser.java9
-rw-r--r--apex/permission/Android.bp2
-rw-r--r--apex/statsd/Android.bp2
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java57
-rw-r--r--api/Android.bp23
-rw-r--r--api/current.txt133
-rw-r--r--api/system-current.txt13754
-rw-r--r--api/system-lint-baseline.txt537
-rw-r--r--api/system-removed.txt198
-rw-r--r--cmds/abx/Android.bp20
-rw-r--r--cmds/abx/MODULE_LICENSE_APACHE20
-rw-r--r--cmds/abx/NOTICE189
-rwxr-xr-xcmds/abx/abx3
-rwxr-xr-xcmds/abx/abx2xml3
-rw-r--r--cmds/abx/src/com/android/commands/abx/Abx.java119
-rwxr-xr-xcmds/abx/xml2abx3
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java2
-rw-r--r--cmds/am/src/com/android/commands/am/Instrument.java5
-rw-r--r--cmds/idmap2/idmap2/Lookup.cpp71
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.h2
-rw-r--r--cmds/idmap2/include/idmap2/ResourceMapping.h3
-rw-r--r--cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp5
-rw-r--r--cmds/idmap2/libidmap2/ResourceMapping.cpp54
-rw-r--r--cmds/idmap2/libidmap2/ResourceUtils.cpp16
-rw-r--r--cmds/idmap2/libidmap2/XmlParser.cpp11
-rw-r--r--cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java6
-rw-r--r--cmds/statsd/Android.bp1
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp9
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h8
-rw-r--r--cmds/statsd/src/atoms.proto285
-rw-r--r--cmds/statsd/src/config/ConfigListener.h2
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp196
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h23
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp48
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/config_update_utils.h7
-rw-r--r--cmds/statsd/tests/ConfigManager_test.cpp22
-rw-r--r--cmds/statsd/tests/MetricsManager_test.cpp134
-rw-r--r--cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp307
-rw-r--r--cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp51
-rw-r--r--config/hiddenapi-temp-blocklist.txt55
-rw-r--r--config/hiddenapi-unsupported.txt55
-rw-r--r--core/api/current.txt124
-rw-r--r--core/api/module-lib-current.txt20
-rw-r--r--core/api/system-current.txt215
-rw-r--r--core/api/system-lint-baseline.txt6
-rw-r--r--core/api/test-current.txt (renamed from api/test-current.txt)15
-rw-r--r--core/api/test-lint-baseline.txt (renamed from api/test-lint-baseline.txt)0
-rw-r--r--core/api/test-removed.txt (renamed from api/test-removed.txt)0
-rw-r--r--core/java/android/accounts/GrantCredentialsPermissionActivity.java37
-rw-r--r--core/java/android/app/Activity.java14
-rw-r--r--core/java/android/app/ActivityManager.java92
-rw-r--r--core/java/android/app/ActivityThread.java250
-rw-r--r--core/java/android/app/AppOpsManager.java13
-rw-r--r--core/java/android/app/AsyncNotedAppOp.java8
-rw-r--r--core/java/android/app/ContextImpl.java2
-rw-r--r--core/java/android/app/IActivityManager.aidl5
-rw-r--r--core/java/android/app/IApplicationThread.aidl5
-rw-r--r--core/java/android/app/IOnProjectionStateChangeListener.aidl22
-rw-r--r--core/java/android/app/IUiModeManager.aidl32
-rw-r--r--core/java/android/app/Instrumentation.java20
-rw-r--r--core/java/android/app/LoadedApk.java5
-rw-r--r--core/java/android/app/Notification.java54
-rw-r--r--core/java/android/app/NotificationChannel.java12
-rw-r--r--core/java/android/app/PendingIntent.java12
-rw-r--r--core/java/android/app/ProcessStateEnum.aidl100
-rw-r--r--core/java/android/app/StatusBarManager.java8
-rw-r--r--core/java/android/app/TaskInfo.java12
-rw-r--r--core/java/android/app/UiModeManager.java333
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java109
-rw-r--r--core/java/android/app/admin/DevicePolicySafetyChecker.java42
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl3
-rw-r--r--core/java/android/app/admin/PasswordMetrics.java46
-rw-r--r--core/java/android/app/admin/UnsafeStateException.java74
-rw-r--r--core/java/android/app/backup/OWNERS2
-rw-r--r--core/java/android/companion/AssociationRequest.java340
-rw-r--r--core/java/android/companion/CompanionDeviceService.java116
-rw-r--r--core/java/android/companion/ICompanionDeviceService.aidl29
-rw-r--r--core/java/android/content/ClipDescription.java4
-rw-r--r--core/java/android/content/ContentResolver.java5
-rw-r--r--core/java/android/content/Context.java28
-rw-r--r--core/java/android/content/Intent.java2
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java3
-rw-r--r--core/java/android/content/pm/LauncherActivityInfo.java20
-rw-r--r--core/java/android/content/pm/PackageManager.java98
-rw-r--r--core/java/android/content/pm/ShortcutInfo.java4
-rw-r--r--core/java/android/content/pm/parsing/ApkLiteParseUtils.java13
-rw-r--r--core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java18
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java25
-rw-r--r--core/java/android/content/pm/parsing/component/ComponentParseUtils.java18
-rw-r--r--core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java61
-rw-r--r--core/java/android/database/AbstractCursor.java8
-rw-r--r--core/java/android/database/sqlite/SQLiteCursor.java22
-rw-r--r--core/java/android/hardware/biometrics/IBiometricSysuiReceiver.aidl2
-rw-r--r--core/java/android/hardware/camera2/CameraCaptureSession.java2
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateManager.java46
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java125
-rw-r--r--core/java/android/hardware/devicestate/IDeviceStateManager.aidl6
-rw-r--r--core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl (renamed from packages/CarSystemUI/res/values/themes.xml)15
-rw-r--r--core/java/android/hardware/display/VirtualDisplayConfig.java8
-rw-r--r--core/java/android/hardware/face/FaceManager.java42
-rw-r--r--core/java/android/hardware/face/IFaceService.aidl16
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java14
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java35
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl24
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java156
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java48
-rw-r--r--core/java/android/hardware/hdmi/IHdmiControlService.aidl9
-rw-r--r--core/java/android/hardware/iris/IIrisService.aidl2
-rw-r--r--core/java/android/hardware/location/ContextHubManager.java6
-rw-r--r--core/java/android/hardware/radio/RadioTuner.java1
-rw-r--r--core/java/android/hardware/usb/UsbDeviceConnection.java2
-rw-r--r--core/java/android/inputmethodservice/AbstractInputMethodService.java1
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java15
-rw-r--r--core/java/android/net/ConnectivityManager.java5
-rw-r--r--core/java/android/net/LinkProperties.java3
-rw-r--r--core/java/android/net/MacAddress.java2
-rw-r--r--core/java/android/net/OemNetworkPreferences.aidl19
-rw-r--r--core/java/android/net/OemNetworkPreferences.java193
-rw-r--r--core/java/android/net/RouteInfo.java3
-rw-r--r--core/java/android/net/TrafficStats.java24
-rw-r--r--core/java/android/os/CombinedVibrationEffect.java412
-rw-r--r--core/java/android/os/FileUtils.java5
-rw-r--r--core/java/android/os/IBinder.java9
-rw-r--r--core/java/android/os/Parcel.java10
-rw-r--r--core/java/android/os/RecoverySystem.java2
-rw-r--r--core/java/android/os/SystemProperties.java2
-rw-r--r--core/java/android/os/UserManager.java3
-rw-r--r--core/java/android/os/WorkSource.java1
-rw-r--r--core/java/android/os/storage/StorageManager.java6
-rw-r--r--core/java/android/provider/Settings.java32
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java5
-rw-r--r--core/java/android/service/attestation/IImpressionAttestationService.aidl52
-rw-r--r--core/java/android/service/attestation/ImpressionAttestationService.java152
-rw-r--r--core/java/android/service/attestation/ImpressionToken.aidl19
-rw-r--r--core/java/android/service/attestation/ImpressionToken.java250
-rw-r--r--core/java/android/service/autofill/InlinePresentation.java8
-rw-r--r--core/java/android/service/autofill/InternalTransformation.java1
-rw-r--r--core/java/android/service/carrier/CarrierMessagingServiceWrapper.java72
-rw-r--r--core/java/android/service/persistentdata/PersistentDataBlockManager.java6
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java5
-rwxr-xr-xcore/java/android/text/format/DateFormat.java4
-rw-r--r--core/java/android/text/format/Time.java5
-rw-r--r--core/java/android/text/format/TimeFormatter.java7
-rw-r--r--core/java/android/timezone/TzDataSetVersion.java4
-rw-r--r--core/java/android/util/CharsetUtils.java78
-rw-r--r--core/java/android/util/FeatureFlagUtils.java20
-rw-r--r--core/java/android/util/TypedXmlPullParser.java186
-rw-r--r--core/java/android/util/TypedXmlSerializer.java103
-rw-r--r--core/java/android/util/Xml.java186
-rw-r--r--core/java/android/uwb/AngleMeasurement.java63
-rw-r--r--core/java/android/uwb/AngleOfArrivalMeasurement.java63
-rw-r--r--core/java/android/uwb/DistanceMeasurement.java62
-rw-r--r--core/java/android/uwb/RangingMeasurement.java70
-rw-r--r--core/java/android/uwb/RangingParams.java381
-rw-r--r--core/java/android/uwb/RangingReport.java56
-rw-r--r--core/java/android/uwb/RangingSession.java10
-rw-r--r--core/java/android/uwb/TEST_MAPPING7
-rw-r--r--core/java/android/uwb/UwbAddress.java65
-rw-r--r--core/java/android/uwb/UwbManager.java15
-rw-r--r--core/java/android/view/Display.java44
-rw-r--r--core/java/android/view/ImeInsetsSourceConsumer.java3
-rw-r--r--core/java/android/view/InputApplicationHandle.java12
-rw-r--r--core/java/android/view/InputWindowHandle.java2
-rw-r--r--core/java/android/view/InsetsController.java42
-rw-r--r--core/java/android/view/OnReceiveContentListener.java (renamed from core/java/android/view/OnReceiveContentCallback.java)166
-rw-r--r--core/java/android/view/SurfaceView.java16
-rw-r--r--core/java/android/view/VerifiedKeyEvent.java34
-rw-r--r--core/java/android/view/VerifiedMotionEvent.java31
-rw-r--r--core/java/android/view/View.java113
-rw-r--r--core/java/android/view/ViewConfiguration.java1
-rw-r--r--core/java/android/view/ViewRootImpl.java39
-rw-r--r--core/java/android/view/ViewStructure.java2
-rw-r--r--core/java/android/view/Window.java5
-rw-r--r--core/java/android/view/WindowManager.java6
-rw-r--r--core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl10
-rw-r--r--core/java/android/view/autofill/AutofillManager.java14
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java23
-rw-r--r--core/java/android/view/inputmethod/InlineSuggestionInfo.java8
-rw-r--r--core/java/android/view/inputmethod/InputConnection.java15
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java2
-rw-r--r--core/java/android/view/inputmethod/SurroundingText.java8
-rw-r--r--core/java/android/webkit/CookieManager.java4
-rw-r--r--core/java/android/webkit/WebHistoryItem.java1
-rw-r--r--core/java/android/webkit/WebIconDatabase.java1
-rw-r--r--core/java/android/webkit/WebSettings.java12
-rw-r--r--core/java/android/widget/AbsListView.java3
-rw-r--r--core/java/android/widget/AbsSpinner.java1
-rw-r--r--core/java/android/widget/Editor.java33
-rw-r--r--core/java/android/widget/FrameLayout.java2
-rw-r--r--core/java/android/widget/SelectionActionModeHelper.java10
-rw-r--r--core/java/android/widget/SmartSelectSprite.java35
-rw-r--r--core/java/android/widget/TextView.java91
-rw-r--r--core/java/android/widget/TextViewOnReceiveContentListener.java (renamed from core/java/android/widget/TextViewOnReceiveContentCallback.java)168
-rw-r--r--core/java/android/window/DisplayAreaOrganizer.java10
-rw-r--r--core/java/android/window/IDisplayAreaOrganizerController.aidl4
-rw-r--r--core/java/android/window/ITaskOrganizer.aidl15
-rw-r--r--core/java/android/window/TaskOrganizer.java28
-rw-r--r--core/java/com/android/internal/BrightnessSynchronizer.java28
-rw-r--r--core/java/com/android/internal/app/ChooserFlags.java2
-rw-r--r--core/java/com/android/internal/app/ISoundTriggerService.aidl12
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl6
-rw-r--r--core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java10
-rw-r--r--core/java/com/android/internal/inputmethod/CancellationGroup.java275
-rw-r--r--core/java/com/android/internal/inputmethod/Completable.java278
-rw-r--r--core/java/com/android/internal/inputmethod/ResultCallbacks.java47
-rw-r--r--core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java2
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java2
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java82
-rw-r--r--core/java/com/android/internal/jank/PerfettoTrigger.java52
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java38
-rw-r--r--core/java/com/android/internal/os/KernelWakelockReader.java13
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java6
-rw-r--r--core/java/com/android/internal/util/BinaryXmlPullParser.java899
-rw-r--r--core/java/com/android/internal/util/BinaryXmlSerializer.java396
-rw-r--r--core/java/com/android/internal/util/FastDataInput.java262
-rw-r--r--core/java/com/android/internal/util/FastDataOutput.java236
-rw-r--r--core/java/com/android/internal/util/LatencyTracker.java32
-rw-r--r--core/java/com/android/internal/util/XmlPullParserWrapper.java189
-rw-r--r--core/java/com/android/internal/util/XmlSerializerWrapper.java140
-rw-r--r--core/java/com/android/internal/util/XmlUtils.java189
-rw-r--r--core/java/com/android/internal/view/FloatingActionMode.java24
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java53
-rw-r--r--core/java/com/android/internal/widget/FloatingToolbar.java10
-rw-r--r--core/jni/Android.bp7
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android_content_res_ApkAssets.cpp14
-rw-r--r--core/jni/android_hardware_input_InputApplicationHandle.cpp22
-rw-r--r--core/jni/android_media_AudioFormat.h15
-rw-r--r--core/jni/android_os_Parcel.cpp61
-rw-r--r--core/jni/android_util_AssetManager.cpp417
-rw-r--r--core/jni/android_util_AssetManager_private.h54
-rw-r--r--core/jni/android_util_CharsetUtils.cpp71
-rw-r--r--core/jni/android_util_StringBlock.cpp103
-rw-r--r--core/jni/android_view_KeyCharacterMap.cpp2
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp46
-rw-r--r--core/jni/fd_utils.cpp22
-rw-r--r--core/proto/android/app/settings_enums.proto25
-rw-r--r--core/proto/android/app/tvsettings_enums.proto187
-rw-r--r--core/proto/android/providers/settings/global.proto2
-rw-r--r--core/proto/android/server/alarm/alarmmanagerservice.proto2
-rw-r--r--core/proto/android/server/jobscheduler.proto3
-rw-r--r--core/proto/android/stats/mediametrics/mediametrics.proto104
-rw-r--r--core/res/AndroidManifest.xml41
-rw-r--r--core/res/res/values-ca/strings.xml6
-rw-r--r--core/res/res/values-et/strings.xml4
-rw-r--r--core/res/res/values-fa/strings.xml6
-rw-r--r--core/res/res/values-gl/strings.xml2
-rw-r--r--core/res/res/values-gu/strings.xml22
-rw-r--r--core/res/res/values-hy/strings.xml2
-rw-r--r--core/res/res/values-in/strings.xml2
-rw-r--r--core/res/res/values-kk/strings.xml6
-rw-r--r--core/res/res/values-km/strings.xml4
-rw-r--r--core/res/res/values-kn/strings.xml2
-rw-r--r--core/res/res/values-ky/strings.xml8
-rw-r--r--core/res/res/values-mn/strings.xml20
-rw-r--r--core/res/res/values-pa/strings.xml6
-rw-r--r--core/res/res/values-ru/strings.xml2
-rw-r--r--core/res/res/values-sw/strings.xml2
-rw-r--r--core/res/res/values-te/strings.xml8
-rw-r--r--core/res/res/values-tl/strings.xml10
-rw-r--r--core/res/res/values-uk/strings.xml6
-rw-r--r--core/res/res/values-uz/strings.xml4
-rw-r--r--core/res/res/values/config.xml34
-rw-r--r--core/res/res/values/symbols.xml9
-rw-r--r--core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java1
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java29
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java6
-rw-r--r--core/tests/coretests/src/android/graphics/TypefaceTest.java27
-rw-r--r--core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java114
-rw-r--r--core/tests/coretests/src/android/util/BinaryXmlTest.java99
-rw-r--r--core/tests/coretests/src/android/util/CharsetUtilsTest.java86
-rw-r--r--core/tests/coretests/src/android/util/XmlTest.java305
-rw-r--r--core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java121
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/util/FastDataTest.java407
-rw-r--r--core/tests/devicestatetests/Android.bp (renamed from packages/CarSystemUI/samples/sample2/rro/Android.bp)23
-rw-r--r--core/tests/devicestatetests/AndroidManifest.xml (renamed from packages/CarSystemUI/res/drawable/car_add_circle_round.xml)30
-rw-r--r--core/tests/devicestatetests/AndroidTest.xml31
-rw-r--r--core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java135
-rw-r--r--core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java20
-rw-r--r--core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java11
-rw-r--r--core/tests/uwbtests/Android.bp (renamed from packages/CarSystemUI/samples/sample3/rro/Android.bp)27
-rw-r--r--core/tests/uwbtests/AndroidManifest.xml31
-rw-r--r--core/tests/uwbtests/AndroidTest.xml32
-rw-r--r--core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java85
-rw-r--r--core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java89
-rw-r--r--core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java87
-rw-r--r--core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java95
-rw-r--r--core/tests/uwbtests/src/android/uwb/RangingReportTest.java90
-rw-r--r--core/tests/uwbtests/src/android/uwb/UwbAddressTest.java79
-rw-r--r--core/tests/uwbtests/src/android/uwb/UwbTestUtils.java92
-rw-r--r--data/etc/car/com.android.car.provision.xml1
-rw-r--r--data/etc/privapp-permissions-platform.xml6
-rw-r--r--data/fonts/fonts.xml187
-rw-r--r--graphics/java/android/graphics/BLASTBufferQueue.java10
-rw-r--r--graphics/java/android/graphics/Compatibility.java4
-rw-r--r--graphics/java/android/graphics/ImageDecoder.java5
-rw-r--r--graphics/java/android/graphics/RenderEffect.java161
-rw-r--r--graphics/java/android/graphics/RenderNode.java2
-rw-r--r--graphics/java/android/graphics/Typeface.java42
-rw-r--r--graphics/java/android/graphics/fonts/Font.java146
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreProvider.java26
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java6
-rw-r--r--keystore/java/android/security/keystore/ArrayUtils.java14
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java88
-rw-r--r--keystore/java/android/security/keystore/KeyInfo.java21
-rw-r--r--keystore/java/android/security/keystore/KeyProperties.java134
-rw-r--r--libs/WindowManager/Shell/Android.bp5
-rw-r--r--libs/WindowManager/Shell/OWNERS3
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_dismiss_circle.xml (renamed from packages/CarSystemUI/res/drawable/headsup_scrim_bottom.xml)18
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_dismiss_icon.xml (renamed from packages/CarSystemUI/res/drawable/car_ic_home_selected.xml)17
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_ic_create_bubble.xml (renamed from packages/CarSystemUI/res/drawable/car_ic_user_icon.xml)10
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_ic_empty_overflow_dark.xml (renamed from packages/SystemUI/res/drawable/ic_empty_bubble_overflow_dark.xml)0
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_ic_empty_overflow_light.xml (renamed from packages/SystemUI/res/drawable/ic_empty_bubble_overflow_light.xml)0
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_ic_overflow_button.xml (renamed from packages/SystemUI/res/drawable/ic_bubble_overflow_button.xml)0
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_ic_stop_bubble.xml (renamed from packages/CarSystemUI/res/drawable/car_ic_home.xml)16
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_manage_menu_row.xml (renamed from packages/SystemUI/res/drawable/bubble_manage_menu_row.xml)2
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg.xml (renamed from packages/SystemUI/res/drawable/bubble_stack_user_education_bg.xml)0
-rw-r--r--libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg_rtl.xml (renamed from packages/SystemUI/res/drawable/bubble_stack_user_education_bg_rtl.xml)0
-rw-r--r--libs/WindowManager/Shell/res/drawable/ic_remove_no_shadow.xml28
-rw-r--r--libs/WindowManager/Shell/res/drawable/rounded_bg_full.xml (renamed from packages/CarSystemUI/res/drawable/car_rounded_bg_bottom.xml)13
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_dismiss_target.xml (renamed from packages/SystemUI/res/layout/bubble_dismiss_target.xml)0
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_expanded_view.xml (renamed from packages/SystemUI/res/layout/bubble_expanded_view.xml)12
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_flyout.xml (renamed from packages/SystemUI/res/layout/bubble_flyout.xml)2
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml (renamed from packages/SystemUI/res/layout/bubble_manage_menu.xml)6
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_menu_view.xml (renamed from packages/SystemUI/res/layout/bubble_menu_view.xml)24
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_overflow_activity.xml (renamed from packages/SystemUI/res/layout/bubble_overflow_activity.xml)0
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_overflow_button.xml (renamed from packages/SystemUI/res/layout/bubble_overflow_button.xml)8
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_overflow_view.xml (renamed from packages/SystemUI/res/layout/bubble_overflow_view.xml)2
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml (renamed from packages/SystemUI/res/layout/bubble_stack_user_education.xml)0
-rw-r--r--libs/WindowManager/Shell/res/layout/bubble_view.xml (renamed from packages/SystemUI/res/layout/bubble_view.xml)6
-rw-r--r--libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml (renamed from packages/SystemUI/res/layout/bubbles_manage_button_education.xml)8
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_menu.xml1
-rw-r--r--libs/WindowManager/Shell/res/raw/wm_shell_protolog.json56
-rw-r--r--libs/WindowManager/Shell/res/values-af/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-af/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-am/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ar/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ar/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-as/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-as/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-az/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-az/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-be/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-be/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-bg/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-bg/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-bn/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-bn/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-bs/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-bs/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ca/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ca/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-cs/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-cs/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-da/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-da/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-de/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-de/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-el/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-el/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-en-rAU/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-en-rCA/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-en-rGB/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-en-rIN/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-en-rXC/strings.xml72
-rw-r--r--libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml24
-rw-r--r--libs/WindowManager/Shell/res/values-es-rUS/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-es/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-es/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-et/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-et/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-eu/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-eu/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-fa/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-fa/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-fi/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-fi/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-fr/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-fr/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-gl/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-gl/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-gu/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-gu/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-hr/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-hr/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-hu/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-hu/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-hy/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-hy/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-in/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-in/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-is/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-is/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-it/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-it/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-iw/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-iw/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ja/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ja/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ka/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ka/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-kk/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-kk/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-km/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-km/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-kn/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-kn/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ko/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ko/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ky/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ky/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-land/dimens.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-lo/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-lo/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-lt/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-lt/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-lv/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-lv/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-mk/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-mk/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ml/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ml/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-mn/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-mn/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-mr/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-mr/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ms/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ms/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-my/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-my/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-nb/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-nb/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ne/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ne/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-night/colors.xml (renamed from packages/CarSystemUI/samples/sample3/rro/res/drawable/system_bar_background.xml)11
-rw-r--r--libs/WindowManager/Shell/res/values-nl/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-nl/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-or/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-or/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-pa/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-pa/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-pl/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-pl/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rBR/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rPT/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-pt/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-pt/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ro/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ro/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ru/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ru/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-si/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-si/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-sk/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-sk/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-sl/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-sl/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-sq/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-sq/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-sr/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-sr/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-sv/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-sv/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-sw/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-sw/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ta/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ta/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-te/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-te/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-th/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-th/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-tl/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-tl/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-tr/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-tr/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-uk/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-uk/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-ur/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-ur/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-uz/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-uz/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-vi/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-vi/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rCN/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rHK/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rTW/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values-zu/strings.xml78
-rw-r--r--libs/WindowManager/Shell/res/values-zu/strings_tv.xml25
-rw-r--r--libs/WindowManager/Shell/res/values/colors.xml10
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml92
-rw-r--r--libs/WindowManager/Shell/res/values/ids.xml17
-rw-r--r--libs/WindowManager/Shell/res/values/integers.xml (renamed from packages/CarSystemUI/samples/sample2/rro/res/values/attrs.xml)21
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml49
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellDump.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java42
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java)11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java208
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java150
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsPool.java93
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java)44
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java)6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java)49
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java)90
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt)8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java)5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleEntry.java)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java)32
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java)42
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java)7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt)103
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java)33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java272
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java)161
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java)15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt (renamed from packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt)22
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt (renamed from packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt)6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ObjectWrapper.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/ObjectWrapper.java)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt (renamed from packages/SystemUI/src/com/android/systemui/bubbles/RelativeTouchListener.kt)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt (renamed from packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt)6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/AnimatableScaleMatrix.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java)50
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OneTimeEndListener.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/animation/OneTimeEndListener.java)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java)4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java (renamed from packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java)45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt (renamed from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepository.kt (renamed from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt (renamed from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt)4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt (renamed from packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt)8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/AlphaOptimizedButton.java50
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java182
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java116
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java437
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/TriangleShape.java77
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java156
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java432
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java164
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java (renamed from packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMComponent.java)26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java101
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java330
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java37
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java318
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java467
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java279
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java51
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java67
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java314
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java223
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java216
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java55
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java90
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java343
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml13
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt36
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt103
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt45
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt90
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt29
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt82
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt7
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt32
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt153
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt183
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt101
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt63
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml33
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java98
-rw-r--r--libs/WindowManager/Shell/tests/unittest/Android.bp1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/res/layout/main.xml32
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTestCase.java)17
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java)8
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java81
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java85
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java67
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java34
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsPool.java (renamed from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt)25
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestRunningTaskInfoBuilder.java43
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java)16
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java)30
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java)12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTestActivity.java40
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/TestableBubblePositioner.java35
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java)10
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java)4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTestCase.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java)10
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java)11
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt)6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt)6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt)6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java258
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java368
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java73
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java218
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java (renamed from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java)106
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java32
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java64
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java20
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java26
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java147
-rw-r--r--libs/androidfw/Android.bp35
-rwxr-xr-xlibs/androidfw/ApkAssets.cpp82
-rw-r--r--libs/androidfw/Asset.cpp174
-rw-r--r--libs/androidfw/AssetManager.cpp16
-rw-r--r--libs/androidfw/AssetManager2.cpp682
-rw-r--r--libs/androidfw/AttributeResolution.cpp450
-rw-r--r--libs/androidfw/ChunkIterator.cpp27
-rw-r--r--libs/androidfw/Idmap.cpp12
-rw-r--r--libs/androidfw/LoadedArsc.cpp339
-rw-r--r--libs/androidfw/ResourceTypes.cpp488
-rw-r--r--libs/androidfw/ResourceUtils.cpp77
-rw-r--r--libs/androidfw/StreamingZipInflater.cpp6
-rw-r--r--libs/androidfw/ZipFileRO.cpp23
-rw-r--r--libs/androidfw/ZipUtils.cpp21
-rw-r--r--libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp4
-rw-r--r--libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp5
-rw-r--r--libs/androidfw/include/androidfw/Asset.h108
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h264
-rw-r--r--libs/androidfw/include/androidfw/AttributeResolution.h24
-rw-r--r--libs/androidfw/include/androidfw/Chunk.h23
-rw-r--r--libs/androidfw/include/androidfw/Errors.h47
-rw-r--r--libs/androidfw/include/androidfw/Idmap.h4
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h37
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h70
-rw-r--r--libs/androidfw/include/androidfw/ResourceUtils.h9
-rw-r--r--libs/androidfw/include/androidfw/StreamingZipInflater.h6
-rw-r--r--libs/androidfw/include/androidfw/Util.h8
-rw-r--r--libs/androidfw/include/androidfw/ZipFileRO.h27
-rw-r--r--libs/androidfw/include/androidfw/ZipUtils.h6
-rw-r--r--libs/androidfw/tests/AssetManager2_bench.cpp10
-rw-r--r--libs/androidfw/tests/AssetManager2_test.cpp469
-rw-r--r--libs/androidfw/tests/AttributeResolution_bench.cpp19
-rw-r--r--libs/androidfw/tests/AttributeResolution_test.cpp18
-rw-r--r--libs/androidfw/tests/BenchmarkHelpers.cpp10
-rw-r--r--libs/androidfw/tests/CommonHelpers.cpp5
-rw-r--r--libs/androidfw/tests/Idmap_test.cpp153
-rw-r--r--libs/androidfw/tests/LoadedArsc_test.cpp63
-rw-r--r--libs/androidfw/tests/ResTable_test.cpp26
-rw-r--r--libs/androidfw/tests/TestHelpers.cpp12
-rw-r--r--libs/androidfw/tests/Theme_bench.cpp5
-rw-r--r--libs/androidfw/tests/Theme_test.cpp278
-rw-r--r--libs/hwui/Android.bp3
-rw-r--r--libs/hwui/JankTracker.cpp1
-rw-r--r--libs/hwui/canvas/CanvasOpBuffer.cpp (renamed from packages/CarSystemUI/src/com/android/systemui/CarSysUIComponentModule.java)17
-rw-r--r--libs/hwui/canvas/CanvasOpBuffer.h64
-rw-r--r--libs/hwui/canvas/CanvasOpRasterizer.cpp50
-rw-r--r--libs/hwui/canvas/CanvasOpRasterizer.h64
-rw-r--r--libs/hwui/canvas/CanvasOpTypes.h64
-rw-r--r--libs/hwui/canvas/CanvasOps.h370
-rw-r--r--libs/hwui/canvas/OpBuffer.h210
-rw-r--r--libs/hwui/hwui/Bitmap.h6
-rw-r--r--libs/hwui/hwui/Typeface.h7
-rw-r--r--libs/hwui/jni/BitmapFactory.cpp2
-rw-r--r--libs/hwui/jni/RenderEffect.cpp73
-rw-r--r--libs/hwui/jni/Typeface.cpp87
-rw-r--r--libs/hwui/jni/fonts/Font.cpp64
-rw-r--r--libs/hwui/jni/fonts/Font.h40
-rw-r--r--libs/hwui/tests/common/CallCountingCanvas.h174
-rw-r--r--libs/hwui/tests/unit/CanvasOpTests.cpp617
-rw-r--r--location/java/android/location/Geocoder.java61
-rw-r--r--location/java/android/location/GeocoderParams.java92
-rw-r--r--location/java/android/location/GnssCapabilities.java21
-rw-r--r--location/java/android/location/ILocationListener.aidl5
-rw-r--r--location/java/android/location/ILocationManager.aidl10
-rw-r--r--location/java/android/location/Location.java363
-rw-r--r--location/java/android/location/LocationListener.java23
-rw-r--r--location/java/android/location/LocationManager.java313
-rw-r--r--location/java/android/location/LocationManagerInternal.java8
-rw-r--r--location/java/android/location/LocationRequest.java45
-rw-r--r--location/java/android/location/LocationResult.aidl (renamed from location/java/android/location/IBatchedLocationCallback.aidl)16
-rw-r--r--location/java/android/location/LocationResult.java273
-rw-r--r--location/java/android/location/timezone/LocationTimeZoneEvent.java43
-rw-r--r--location/java/com/android/internal/location/ILocationProvider.aidl2
-rw-r--r--location/java/com/android/internal/location/ILocationProviderManager.aidl5
-rw-r--r--location/java/com/android/internal/location/ProviderRequest.java54
-rw-r--r--location/lib/api/current.txt7
-rw-r--r--location/lib/java/com/android/location/provider/LocationProviderBase.java75
-rw-r--r--location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java20
-rw-r--r--location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java3
-rw-r--r--media/java/android/media/AudioDeviceInfo.java26
-rw-r--r--media/java/android/media/AudioFormat.java74
-rw-r--r--media/java/android/media/AudioManager.java6
-rw-r--r--media/java/android/media/AudioRecord.java32
-rw-r--r--media/java/android/media/AudioTrack.java7
-rw-r--r--media/java/android/media/ExifInterface.java19
-rw-r--r--media/java/android/media/IRemoteVolumeControllerCallback.aidl (renamed from media/java/android/media/IRemoteVolumeController.aidl)6
-rw-r--r--media/java/android/media/Image.java2
-rw-r--r--media/java/android/media/MediaCas.java89
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java4
-rw-r--r--media/java/android/media/MediaPlayer.java109
-rw-r--r--media/java/android/media/PlayerBase.java7
-rw-r--r--media/java/android/media/PlayerProxy.java3
-rw-r--r--media/java/android/media/ThumbnailUtils.java3
-rw-r--r--media/java/android/media/VolumeShaper.java270
-rw-r--r--media/java/android/media/permission/PermissionUtil.java53
-rw-r--r--media/java/android/media/session/ISessionManager.aidl6
-rw-r--r--media/java/android/media/session/MediaController.java7
-rw-r--r--media/java/android/media/session/MediaSessionManager.java123
-rw-r--r--media/java/android/media/soundtrigger/SoundTriggerManager.java5
-rw-r--r--media/java/android/media/tv/tuner/Descrambler.java7
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java84
-rw-r--r--media/java/android/media/tv/tuner/filter/Filter.java60
-rw-r--r--media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java47
-rw-r--r--media/java/android/media/tv/tuner/filter/RecordSettings.java71
-rw-r--r--media/java/android/media/tv/tuner/filter/ScramblingStatusEvent.java48
-rw-r--r--media/java/android/media/tv/tuner/filter/TsRecordEvent.java25
-rw-r--r--media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java19
-rw-r--r--media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java19
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendInfo.java32
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendSettings.java5
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendStatus.java105
-rw-r--r--media/java/android/media/tv/tuner/frontend/ScanCallback.java3
-rw-r--r--media/jni/Android.bp2
-rw-r--r--media/jni/android_media_tv_Tuner.cpp103
-rw-r--r--media/packages/BluetoothMidiService/tests/unit/Android.bp1
-rw-r--r--media/tests/MediaFrameworkTest/Android.bp1
-rw-r--r--media/tests/MediaRouter/Android.bp2
-rw-r--r--media/tests/MediaRouter/AndroidManifest.xml2
-rw-r--r--media/tests/MediaRouter/AndroidTest.xml2
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouteInfoTest.java5
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java9
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java5
-rw-r--r--media/tests/MediaTranscodingTest/Android.bp2
-rw-r--r--media/tests/TunerTest/Android.bp2
-rw-r--r--media/tests/TunerTest/AndroidManifest.xml2
-rw-r--r--media/tests/TunerTest/AndroidTest.xml2
-rw-r--r--media/tests/TunerTest/src/com/android/mediatunertest/TunerTest.java7
-rw-r--r--mime/java-res/android.mime.types1
-rw-r--r--native/android/Android.bp1
-rw-r--r--native/android/TEST_MAPPING17
-rw-r--r--native/android/libandroid.map.txt1
-rw-r--r--native/android/permission_manager.cpp43
-rw-r--r--packages/CarSystemUI/Android.bp165
-rw-r--r--packages/CarSystemUI/AndroidManifest.xml37
-rw-r--r--packages/CarSystemUI/CleanSpec.mk50
-rw-r--r--packages/CarSystemUI/TEST_MAPPING32
-rw-r--r--packages/CarSystemUI/proguard.flags7
-rw-r--r--packages/CarSystemUI/res-keyguard/drawable/ic_backspace.xml26
-rw-r--r--packages/CarSystemUI/res-keyguard/drawable/ic_done.xml26
-rw-r--r--packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml31
-rw-r--r--packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml82
-rw-r--r--packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml126
-rw-r--r--packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml31
-rw-r--r--packages/CarSystemUI/res-keyguard/layout/keyguard_container.xml25
-rw-r--r--packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml31
-rw-r--r--packages/CarSystemUI/res-keyguard/layout/keyguard_num_pad_key.xml37
-rw-r--r--packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml102
-rw-r--r--packages/CarSystemUI/res-keyguard/layout/keyguard_pattern_view.xml84
-rw-r--r--packages/CarSystemUI/res-keyguard/layout/keyguard_pin_view.xml127
-rw-r--r--packages/CarSystemUI/res-keyguard/layout/num_pad_keys.xml83
-rw-r--r--packages/CarSystemUI/res-keyguard/values-h1000dp/dimens.xml19
-rw-r--r--packages/CarSystemUI/res-keyguard/values-land/dimens.xml20
-rw-r--r--packages/CarSystemUI/res-keyguard/values/colors.xml21
-rw-r--r--packages/CarSystemUI/res-keyguard/values/dimens.xml30
-rw-r--r--packages/CarSystemUI/res-keyguard/values/integers.xml20
-rw-r--r--packages/CarSystemUI/res-keyguard/values/styles.xml53
-rw-r--r--packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_down.xml48
-rw-r--r--packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_up.xml48
-rw-r--r--packages/CarSystemUI/res/anim/car_arrow_fade_out.xml42
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_close_pod_animation.xml24
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_open_icon_animation.xml24
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_open_name_animation.xml24
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_open_pages_animation.xml24
-rw-r--r--packages/CarSystemUI/res/anim/car_user_switcher_open_pod_animation.xml33
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_add_white.xml23
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_apps.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_arrow.xml24
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_arrow_drop_up.xml24
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_hvac.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_keyboard_arrow_down.xml27
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_music.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_music_selected.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_navigation.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_navigation_selected.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_notification.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_overview.xml26
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_overview_selected.xml26
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_phone.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_phone_selected.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_selection_bg.xml28
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_settings_icon.xml26
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_unseen_indicator.xml30
-rw-r--r--packages/CarSystemUI/res/drawable/car_seekbar_thumb.xml37
-rw-r--r--packages/CarSystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml28
-rw-r--r--packages/CarSystemUI/res/drawable/hvac_decrease_button.xml53
-rw-r--r--packages/CarSystemUI/res/drawable/hvac_increase_button.xml53
-rw-r--r--packages/CarSystemUI/res/drawable/ic_mic_white.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/notification_handle_bar.xml26
-rw-r--r--packages/CarSystemUI/res/drawable/notification_material_bg.xml26
-rw-r--r--packages/CarSystemUI/res/drawable/notification_material_bg_dim.xml26
-rw-r--r--packages/CarSystemUI/res/drawable/system_bar_background_pill.xml33
-rw-r--r--packages/CarSystemUI/res/drawable/volume_dialog_background.xml26
-rw-r--r--packages/CarSystemUI/res/layout/adjustable_temperature_view.xml50
-rw-r--r--packages/CarSystemUI/res/layout/car_fullscreen_user_pod.xml46
-rw-r--r--packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml49
-rw-r--r--packages/CarSystemUI/res/layout/car_left_navigation_bar.xml112
-rw-r--r--packages/CarSystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml61
-rw-r--r--packages/CarSystemUI/res/layout/car_navigation_bar.xml122
-rw-r--r--packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml46
-rw-r--r--packages/CarSystemUI/res/layout/car_navigation_button.xml68
-rw-r--r--packages/CarSystemUI/res/layout/car_right_navigation_bar.xml115
-rw-r--r--packages/CarSystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml61
-rw-r--r--packages/CarSystemUI/res/layout/car_status_bar_header.xml30
-rw-r--r--packages/CarSystemUI/res/layout/car_top_navigation_bar.xml135
-rw-r--r--packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml135
-rw-r--r--packages/CarSystemUI/res/layout/car_user_switching_dialog.xml42
-rw-r--r--packages/CarSystemUI/res/layout/car_volume_dialog.xml22
-rw-r--r--packages/CarSystemUI/res/layout/car_volume_item.xml72
-rw-r--r--packages/CarSystemUI/res/layout/headsup_container_bottom.xml58
-rw-r--r--packages/CarSystemUI/res/layout/notification_center_activity.xml57
-rw-r--r--packages/CarSystemUI/res/layout/notification_handle_bar.xml30
-rw-r--r--packages/CarSystemUI/res/layout/notification_panel_container.xml22
-rw-r--r--packages/CarSystemUI/res/layout/rear_view_camera.xml31
-rw-r--r--packages/CarSystemUI/res/layout/status_bar_wifi_group.xml85
-rw-r--r--packages/CarSystemUI/res/layout/system_icons.xml43
-rw-r--r--packages/CarSystemUI/res/layout/sysui_overlay_window.xml51
-rw-r--r--packages/CarSystemUI/res/values-af/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-af/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-am/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-am/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ar/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-as/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-as/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-az/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-az/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-b+sr+Latn/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-b+sr+Latn/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-be/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-be/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-bg/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-bg/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-bn/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-bn/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-bs/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-bs/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ca/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-ca/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-cs/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-cs/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-da/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-da/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-de/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-de/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-el/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-el/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-en-rAU/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-en-rAU/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-en-rCA/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-en-rCA/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-en-rGB/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-en-rGB/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-en-rIN/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-en-rIN/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-en-rXC/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-en-rXC/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-es-rUS/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-es-rUS/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-es/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-es/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-et/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-et/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-eu/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-eu/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-fa/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-fa/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-fi/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-fi/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-fr-rCA/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-fr-rCA/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-fr/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-fr/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-gl/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-gl/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-gu/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-gu/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-hi/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-hi/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-hr/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-hr/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-hu/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-hu/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-hy/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-hy/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-in/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-in/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-is/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-is/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-it/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-it/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-iw/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-ja/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-ja/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ka/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-ka/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-kk/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-km/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-km/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-kn/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-kn/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ko/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-ko/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ky/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-lo/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-lt/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-lt/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-lv/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-lv/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-mk/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-mk/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ml/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-ml/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-mn/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-mn/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-mr/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-mr/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ms/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-ms/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-my/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-my/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-nb/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-nb/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ne/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-night/colors.xml27
-rw-r--r--packages/CarSystemUI/res/values-nl/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-nl/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-or/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-pa/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-pa/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-pl/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-pl/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-pt-rPT/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-pt-rPT/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-pt/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-pt/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ro/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-ro/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ru/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-ru/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-si/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-si/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-sk/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-sk/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-sl/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-sl/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-sq/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-sq/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-sr/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-sr/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-sv/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-sv/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-sw/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-sw/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ta/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-te/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-te/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-th/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-th/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-tl/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-tl/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-tr/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-tr/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-uk/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-uk/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-ur/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-uz/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-uz/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-vi/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-vi/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-zh-rCN/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-zh-rCN/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-zh-rHK/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-zh-rHK/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-zh-rTW/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-zh-rTW/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values-zu/strings.xml32
-rw-r--r--packages/CarSystemUI/res/values-zu/strings_car.xml28
-rw-r--r--packages/CarSystemUI/res/values/attrs.xml113
-rw-r--r--packages/CarSystemUI/res/values/colors.xml71
-rw-r--r--packages/CarSystemUI/res/values/config.xml166
-rw-r--r--packages/CarSystemUI/res/values/dimens.xml234
-rw-r--r--packages/CarSystemUI/res/values/ids.xml21
-rw-r--r--packages/CarSystemUI/res/values/integers.xml34
-rw-r--r--packages/CarSystemUI/res/values/strings.xml47
-rw-r--r--packages/CarSystemUI/res/values/styles.xml54
-rw-r--r--packages/CarSystemUI/res/xml/car_volume_items.xml65
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_apps.xml25
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_apps_selected.xml25
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_music.xml25
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_music_selected.xml25
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_navigation.xml25
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_navigation_selected.xml25
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_overview.xml26
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_overview_selected.xml26
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_phone.xml25
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_phone_selected.xml25
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background.xml33
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background_2.xml33
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background_3.xml33
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/layout/car_navigation_bar.xml88
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/layout/car_right_navigation_bar.xml141
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/layout/system_icons.xml34
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/values/attrs.xml44
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/values/config.xml58
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/values/dimens.xml19
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/values/styles.xml35
-rw-r--r--packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml76
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/AndroidManifest.xml24
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_apps.xml25
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_music.xml25
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_navigation.xml25
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_notification.xml25
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_overview.xml26
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_phone.xml25
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/drawable/system_bar_background.xml33
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/layout/car_left_navigation_bar.xml105
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/values/colors.xml20
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/values/config.xml57
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/values/styles.xml35
-rw-r--r--packages/CarSystemUI/samples/sample2/rro/res/xml/car_sysui_overlays.xml66
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/AndroidManifest.xml24
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_apps.xml25
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_hvac.xml25
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_music.xml25
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_navigation.xml25
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_notification.xml25
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_overview.xml26
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_phone.xml25
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/layout/car_left_navigation_bar.xml51
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/layout/car_navigation_bar.xml122
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/values/attrs.xml43
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/values/config.xml57
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/values/dimens.xml22
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/values/styles.xml30
-rw-r--r--packages/CarSystemUI/samples/sample3/rro/res/xml/car_sysui_overlays.xml75
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java53
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java45
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java181
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java60
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java176
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedController.java44
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java119
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedListener.java36
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java80
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/bluetooth/CarBatteryController.java292
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/bluetooth/ConnectedDeviceSignalController.java272
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java130
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java265
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java245
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureBackgroundAnimator.java340
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureColorStore.java202
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextAnimator.java164
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java83
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java49
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java404
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewMediator.java54
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/AssitantButton.java71
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonRoleHolderController.java142
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateController.java232
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateListener.java62
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java590
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java352
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java168
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java319
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java158
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java548
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/BottomNotificationPanelViewMediator.java62
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java110
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/CarNotificationModule.java83
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java602
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java174
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationShadeWindowControllerImpl.java46
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationVisibilityLogger.java150
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/PowerManagerHelper.java71
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/TopNotificationPanelViewMediator.java62
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/rvc/RearViewCameraViewController.java141
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/rvc/RearViewCameraViewMediator.java121
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppController.java73
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java136
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppListener.java127
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppStateController.java52
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/statusbar/DozeServiceHost.java130
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java139
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java60
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java123
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java97
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java657
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserIconProvider.java116
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java166
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java88
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifier.java95
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogComponent.java54
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogImpl.java658
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeItem.java135
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeItemAdapter.java59
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/volume/VolumeUI.java129
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java685
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java218
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java384
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java86
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java183
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowManager.java100
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java250
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java187
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsInsetsControllerHost.java173
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java49
-rw-r--r--packages/CarSystemUI/tests/Android.mk88
-rw-r--r--packages/CarSystemUI/tests/AndroidManifest.xml40
-rw-r--r--packages/CarSystemUI/tests/AndroidTest.xml30
-rw-r--r--packages/CarSystemUI/tests/res/layout/button_role_holder_controller_test.xml41
-rw-r--r--packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml55
-rw-r--r--packages/CarSystemUI/tests/res/layout/car_navigation_bar_view_test.xml58
-rw-r--r--packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml124
-rw-r--r--packages/CarSystemUI/tests/res/layout/overlay_view_controller_test.xml30
-rw-r--r--packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml43
-rw-r--r--packages/CarSystemUI/tests/res/values/config.xml23
-rw-r--r--packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java216
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java234
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java146
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java110
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java199
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java189
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java138
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java479
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java373
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java102
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java291
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java290
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java121
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java141
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/rvc/RearViewCameraViewControllerTest.java117
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/rvc/RearViewCameraViewMediatorTest.java169
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java166
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java243
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java162
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java178
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java97
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java135
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java499
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java160
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java985
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/wm/BarControlPolicyTest.java195
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java109
-rw-r--r--packages/CarrierDefaultApp/res/values-hu/strings.xml2
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java17
-rw-r--r--packages/DynamicSystemInstallationService/res/values-af/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-am/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ar/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-as/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-az/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-b+sr+Latn/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-be/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-bg/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-bn/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-bs/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ca/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-cs/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-da/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-de/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-el/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-en-rAU/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-en-rCA/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-en-rGB/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-en-rIN/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-es-rUS/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-es/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-et/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-eu/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-fa/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-fi/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-fr-rCA/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-fr/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-gl/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-gu/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-hi/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-hr/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-hu/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-hy/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-in/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-is/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-it/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-iw/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ja/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ka/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-kk/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-km/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-kn/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ko/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ky/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-lo/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-lt/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-lv/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-mk/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ml/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-mn/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-mr/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ms/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-my/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-nb/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ne/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-nl/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-or/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-pa/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-pl/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-pt-rPT/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-pt/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ro/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ru/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-si/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-sk/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-sl/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-sq/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-sr/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-sv/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-sw/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ta/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-te/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-th/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-tl/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-tr/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-uk/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-ur/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-uz/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-vi/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-zh-rCN/strings.xml5
-rw-r--r--packages/DynamicSystemInstallationService/res/values-zh-rHK/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-zh-rTW/strings.xml3
-rw-r--r--packages/DynamicSystemInstallationService/res/values-zu/strings.xml5
-rw-r--r--packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java12
-rw-r--r--packages/PackageInstaller/res/values-kn/strings.xml2
-rwxr-xr-xpackages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java4
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java3
-rw-r--r--packages/PrintSpooler/res/values-uz/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rXC/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-te/arrays.xml16
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml12
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml4
-rw-r--r--packages/SettingsLib/res/values/strings.xml14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java38
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/OWNERS2
-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.java4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java18
-rw-r--r--packages/SettingsProvider/test/src/android/provider/OWNERS2
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java3
-rw-r--r--packages/Shell/AndroidManifest.xml4
-rw-r--r--packages/Shell/src/com/android/shell/HeapDumpReceiver.java2
-rw-r--r--packages/SoundPicker/res/values-kk/strings.xml2
-rw-r--r--packages/SoundPicker/res/values-te/strings.xml4
-rw-r--r--packages/SoundPicker/res/values-uz/strings.xml2
-rw-r--r--packages/SystemUI/AndroidManifest.xml4
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationListenerController.java21
-rw-r--r--packages/SystemUI/res-keyguard/values-gl/strings.xml2
-rw-r--r--packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml (renamed from packages/CarSystemUI/res/anim/car_user_switcher_open_animation.xml)15
-rw-r--r--packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml (renamed from packages/CarSystemUI/res/anim/car_user_switcher_close_animation.xml)13
-rw-r--r--packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml (renamed from packages/CarSystemUI/res/anim/car_user_switcher_close_pages_animation.xml)16
-rw-r--r--packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml21
-rw-r--r--packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml36
-rw-r--r--packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml (renamed from packages/CarSystemUI/samples/sample1/rro/res/values/colors.xml)12
-rw-r--r--packages/SystemUI/res/drawable/bubble_dismiss_circle.xml28
-rw-r--r--packages/SystemUI/res/drawable/bubble_dismiss_icon.xml26
-rw-r--r--packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml (renamed from packages/CarSystemUI/res/anim/car_user_switcher_close_name_animation.xml)16
-rw-r--r--packages/SystemUI/res/drawable/ic_brightness.xml29
-rw-r--r--packages/SystemUI/res/drawable/ic_pause_white.xml (renamed from packages/CarSystemUI/res/drawable/stat_sys_signal_null.xml)16
-rw-r--r--packages/SystemUI/res/drawable/ic_play_arrow_white.xml (renamed from packages/SystemUI/res/drawable/ic_create_bubble.xml)16
-rw-r--r--packages/SystemUI/res/drawable/ic_screenshot_scroll.xml (renamed from packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_home.xml)12
-rw-r--r--packages/SystemUI/res/drawable/pip_icon.xml (renamed from packages/SystemUI/res/drawable/ic_stop_bubble.xml)20
-rw-r--r--packages/SystemUI/res/drawable/pip_resize_handle.xml29
-rw-r--r--packages/SystemUI/res/layout-land/global_screenshot_preview.xml2
-rw-r--r--packages/SystemUI/res/layout/auth_biometric_contents.xml60
-rw-r--r--packages/SystemUI/res/layout/auth_biometric_udfps_view.xml (renamed from packages/CarSystemUI/tests/res/layout/overlay_view_controller_stub.xml)10
-rw-r--r--packages/SystemUI/res/layout/brightness_mirror.xml9
-rw-r--r--packages/SystemUI/res/layout/global_screenshot.xml2
-rw-r--r--packages/SystemUI/res/layout/global_screenshot_preview.xml2
-rw-r--r--packages/SystemUI/res/layout/global_screenshot_static.xml3
-rw-r--r--packages/SystemUI/res/layout/pip_menu_activity.xml93
-rw-r--r--packages/SystemUI/res/layout/qs_panel.xml19
-rw-r--r--packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml54
-rw-r--r--packages/SystemUI/res/layout/quick_settings_brightness_dialog_thick.xml53
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml3
-rw-r--r--packages/SystemUI/res/layout/status_bar_toggle_slider.xml60
-rw-r--r--packages/SystemUI/res/layout/super_notification_shade.xml6
-rw-r--r--packages/SystemUI/res/values-af/strings.xml38
-rw-r--r--packages/SystemUI/res/values-af/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-am/strings.xml38
-rw-r--r--packages/SystemUI/res/values-am/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml38
-rw-r--r--packages/SystemUI/res/values-ar/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-as/strings.xml38
-rw-r--r--packages/SystemUI/res/values-as/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-az/strings.xml38
-rw-r--r--packages/SystemUI/res/values-az/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml38
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-be/strings.xml38
-rw-r--r--packages/SystemUI/res/values-be/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml38
-rw-r--r--packages/SystemUI/res/values-bg/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml47
-rw-r--r--packages/SystemUI/res/values-bn/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml38
-rw-r--r--packages/SystemUI/res/values-bs/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml44
-rw-r--r--packages/SystemUI/res/values-ca/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml38
-rw-r--r--packages/SystemUI/res/values-cs/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-da/strings.xml38
-rw-r--r--packages/SystemUI/res/values-da/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-de/strings.xml47
-rw-r--r--packages/SystemUI/res/values-de/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-el/strings.xml38
-rw-r--r--packages/SystemUI/res/values-el/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml29
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml29
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml38
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml38
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml29
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml47
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-es/strings.xml38
-rw-r--r--packages/SystemUI/res/values-es/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-et/strings.xml38
-rw-r--r--packages/SystemUI/res/values-et/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml38
-rw-r--r--packages/SystemUI/res/values-eu/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml42
-rw-r--r--packages/SystemUI/res/values-fa/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml38
-rw-r--r--packages/SystemUI/res/values-fi/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml40
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml40
-rw-r--r--packages/SystemUI/res/values-fr/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml47
-rw-r--r--packages/SystemUI/res/values-gl/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml53
-rw-r--r--packages/SystemUI/res/values-gu/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-h740dp-port/dimens.xml4
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml40
-rw-r--r--packages/SystemUI/res/values-hi/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml42
-rw-r--r--packages/SystemUI/res/values-hr/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml38
-rw-r--r--packages/SystemUI/res/values-hu/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml38
-rw-r--r--packages/SystemUI/res/values-hy/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-in/strings.xml38
-rw-r--r--packages/SystemUI/res/values-in/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-is/strings.xml38
-rw-r--r--packages/SystemUI/res/values-is/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-it/strings.xml38
-rw-r--r--packages/SystemUI/res/values-it/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml38
-rw-r--r--packages/SystemUI/res/values-iw/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml38
-rw-r--r--packages/SystemUI/res/values-ja/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml38
-rw-r--r--packages/SystemUI/res/values-ka/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml40
-rw-r--r--packages/SystemUI/res/values-kk/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-km/strings.xml38
-rw-r--r--packages/SystemUI/res/values-km/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml47
-rw-r--r--packages/SystemUI/res/values-kn/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml38
-rw-r--r--packages/SystemUI/res/values-ko/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml36
-rw-r--r--packages/SystemUI/res/values-ky/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-land/config.xml3
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml6
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml29
-rw-r--r--packages/SystemUI/res/values-lo/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml38
-rw-r--r--packages/SystemUI/res/values-lt/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml38
-rw-r--r--packages/SystemUI/res/values-lv/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml38
-rw-r--r--packages/SystemUI/res/values-mk/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml38
-rw-r--r--packages/SystemUI/res/values-ml/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml42
-rw-r--r--packages/SystemUI/res/values-mn/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml47
-rw-r--r--packages/SystemUI/res/values-mr/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml38
-rw-r--r--packages/SystemUI/res/values-ms/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-my/strings.xml38
-rw-r--r--packages/SystemUI/res/values-my/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml38
-rw-r--r--packages/SystemUI/res/values-nb/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml47
-rw-r--r--packages/SystemUI/res/values-ne/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml38
-rw-r--r--packages/SystemUI/res/values-nl/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-or/strings.xml47
-rw-r--r--packages/SystemUI/res/values-or/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml47
-rw-r--r--packages/SystemUI/res/values-pa/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml38
-rw-r--r--packages/SystemUI/res/values-pl/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml38
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml38
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml38
-rw-r--r--packages/SystemUI/res/values-pt/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml38
-rw-r--r--packages/SystemUI/res/values-ro/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml38
-rw-r--r--packages/SystemUI/res/values-ru/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-si/strings.xml38
-rw-r--r--packages/SystemUI/res/values-si/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml38
-rw-r--r--packages/SystemUI/res/values-sk/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml38
-rw-r--r--packages/SystemUI/res/values-sl/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml38
-rw-r--r--packages/SystemUI/res/values-sq/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml38
-rw-r--r--packages/SystemUI/res/values-sr/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml38
-rw-r--r--packages/SystemUI/res/values-sv/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml38
-rw-r--r--packages/SystemUI/res/values-sw/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml38
-rw-r--r--packages/SystemUI/res/values-ta/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-te/strings.xml42
-rw-r--r--packages/SystemUI/res/values-te/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-television/config.xml1
-rw-r--r--packages/SystemUI/res/values-th/strings.xml42
-rw-r--r--packages/SystemUI/res/values-th/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml62
-rw-r--r--packages/SystemUI/res/values-tl/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml38
-rw-r--r--packages/SystemUI/res/values-tr/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml38
-rw-r--r--packages/SystemUI/res/values-uk/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml47
-rw-r--r--packages/SystemUI/res/values-ur/strings_tv.xml6
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml38
-rw-r--r--packages/SystemUI/res/values-uz/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml38
-rw-r--r--packages/SystemUI/res/values-vi/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml38
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml38
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml38
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml40
-rw-r--r--packages/SystemUI/res/values-zu/strings_tv.xml3
-rw-r--r--packages/SystemUI/res/values/colors.xml4
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml104
-rw-r--r--packages/SystemUI/res/values/ids.xml17
-rw-r--r--packages/SystemUI/res/values/integers.xml11
-rw-r--r--packages/SystemUI/res/values/strings.xml70
-rw-r--r--packages/SystemUI/res/values/strings_tv.xml6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java123
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java61
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java11
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowCallbacksCompat.java109
-rw-r--r--packages/SystemUI/src/com/android/keyguard/FontInterpolator.kt222
-rw-r--r--packages/SystemUI/src/com/android/keyguard/GradientTextClock.java55
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java21
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java24
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java28
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java10
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java23
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java66
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/TextAnimator.kt141
-rw-r--r--packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt417
-rw-r--r--packages/SystemUI/src/com/android/keyguard/TimeBasedColorsClockController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java92
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java123
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java146
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java189
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java301
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubblePositioner.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java98
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java149
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java79
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetail.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooter.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java68
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java114
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java169
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java220
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java247
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java139
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java106
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java147
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java346
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java231
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java207
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java (renamed from packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java)20
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessControllerSettings.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java (renamed from packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java)30
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java282
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java206
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java (renamed from packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java)4
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java (renamed from packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java)19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt207
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java96
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt140
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java (renamed from packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java)112
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java240
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/ViewController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java155
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java41
-rw-r--r--packages/SystemUI/tests/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/FontInterpolatorTest.kt109
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java99
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt111
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt143
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java107
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/ui/ToggleRangeTemplateTest.kt54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java196
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java69
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java140
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java142
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java121
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/TestableConsumer.java33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt316
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java43
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java)53
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java173
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java65
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java (renamed from packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java)7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java61
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java32
-rw-r--r--packages/VpnDialogs/res/values-my/strings.xml2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java16
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java13
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java28
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java11
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java40
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java100
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java52
-rw-r--r--services/core/java/com/android/server/ContextHubSystemService.java2
-rw-r--r--services/core/java/com/android/server/CountryDetectorService.java11
-rw-r--r--services/core/java/com/android/server/NsdService.java2
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java137
-rw-r--r--services/core/java/com/android/server/RescueParty.java183
-rw-r--r--services/core/java/com/android/server/ServiceWatcher.java132
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java24
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java338
-rw-r--r--services/core/java/com/android/server/am/ActiveInstrumentation.java3
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java131
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java32
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java145
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java140
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java104
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java7
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java10
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java10
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java40
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java16
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java15
-rw-r--r--services/core/java/com/android/server/biometrics/AuthSession.java130
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java58
-rw-r--r--services/core/java/com/android/server/biometrics/Utils.java16
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java30
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java (renamed from packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java)20
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/LockoutCache.java (renamed from services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java)8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java24
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java124
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/UsageStats.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java221
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java120
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java61
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java63
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java67
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java57
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java580
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java59
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java79
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClient.java58
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java456
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/Face10.java)299
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java)3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java)2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClient.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java)3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java)2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceInternalCleanupClient.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java)2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceInternalEnumerateClient.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java)2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceRemovalClient.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java)2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java)2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceRevokeChallengeClient.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java)2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java)2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java (renamed from services/core/java/com/android/server/biometrics/sensors/face/FaceUpdateActiveUserClient.java)2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java23
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java113
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java2
-rw-r--r--services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java11
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkNotificationManager.java11
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java54
-rw-r--r--services/core/java/com/android/server/connectivity/VpnIkev2Utils.java2
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java2
-rw-r--r--services/core/java/com/android/server/content/SyncManager.md122
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateManagerService.java133
-rw-r--r--services/core/java/com/android/server/display/DisplayAdapter.java9
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java168
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java18
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java11
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java52
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java2
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java5
-rw-r--r--services/core/java/com/android/server/display/TEST_MAPPING12
-rw-r--r--services/core/java/com/android/server/hdmi/Constants.java182
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecConfig.java163
-rwxr-xr-xservices/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java34
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java17
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java15
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java20
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java18
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessage.java12
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java57
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java201
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java205
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiUtils.java3
-rw-r--r--services/core/java/com/android/server/hdmi/VolumeControlAction.java1
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java2
-rw-r--r--services/core/java/com/android/server/input/InputShellCommand.java44
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java91
-rw-r--r--services/core/java/com/android/server/lights/LightsService.java4
-rw-r--r--services/core/java/com/android/server/location/AbstractLocationProvider.java55
-rw-r--r--services/core/java/com/android/server/location/GeocoderProxy.java6
-rw-r--r--services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java6
-rw-r--r--services/core/java/com/android/server/location/LocationFudger.java30
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java141
-rw-r--r--services/core/java/com/android/server/location/LocationProviderManager.java387
-rw-r--r--services/core/java/com/android/server/location/MockLocationProvider.java (renamed from services/core/java/com/android/server/location/MockProvider.java)12
-rw-r--r--services/core/java/com/android/server/location/MockableLocationProvider.java32
-rw-r--r--services/core/java/com/android/server/location/PassiveLocationProvider.java (renamed from services/core/java/com/android/server/location/PassiveProvider.java)15
-rw-r--r--services/core/java/com/android/server/location/PassiveLocationProviderManager.java14
-rw-r--r--services/core/java/com/android/server/location/ProxyLocationProvider.java (renamed from services/core/java/com/android/server/location/LocationProviderProxy.java)83
-rw-r--r--services/core/java/com/android/server/location/contexthub/ConcurrentLinkedEvictingDeque.java (renamed from services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java)4
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java (renamed from services/core/java/com/android/server/location/ContextHubClientBroker.java)6
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java (renamed from services/core/java/com/android/server/location/ContextHubClientManager.java)6
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubService.java (renamed from services/core/java/com/android/server/location/ContextHubService.java)5
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubServiceTransaction.java (renamed from services/core/java/com/android/server/location/ContextHubServiceTransaction.java)4
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java (renamed from services/core/java/com/android/server/location/ContextHubServiceUtil.java)4
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java (renamed from services/core/java/com/android/server/location/ContextHubTransactionManager.java)4
-rw-r--r--services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java (renamed from services/core/java/com/android/server/location/IContextHubWrapper.java)2
-rw-r--r--services/core/java/com/android/server/location/contexthub/NanoAppStateManager.java (renamed from services/core/java/com/android/server/location/NanoAppStateManager.java)4
-rw-r--r--services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java (renamed from services/core/java/com/android/server/location/ComprehensiveCountryDetector.java)6
-rw-r--r--services/core/java/com/android/server/location/countrydetector/CountryDetectorBase.java (renamed from services/core/java/com/android/server/location/CountryDetectorBase.java)6
-rw-r--r--services/core/java/com/android/server/location/countrydetector/LocationBasedCountryDetector.java (renamed from services/core/java/com/android/server/location/LocationBasedCountryDetector.java)6
-rw-r--r--services/core/java/com/android/server/location/geofence/GeofenceManager.java8
-rw-r--r--services/core/java/com/android/server/location/geofence/GeofenceProxy.java8
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssBatchingProvider.java161
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java6
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssConfiguration.java44
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java607
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssManagerService.java156
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssSatelliteBlocklistHelper.java (renamed from services/core/java/com/android/server/location/gnss/GnssSatelliteBlacklistHelper.java)56
-rw-r--r--services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java3
-rw-r--r--services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java35
-rw-r--r--services/core/java/com/android/server/location/listeners/ListenerRegistration.java5
-rw-r--r--services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java2
-rw-r--r--services/core/java/com/android/server/location/timezone/ControllerImpl.java11
-rw-r--r--services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java2
-rw-r--r--services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java8
-rw-r--r--services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java5
-rw-r--r--services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java56
-rw-r--r--services/core/java/com/android/server/location/util/LocationEventLog.java35
-rw-r--r--services/core/java/com/android/server/media/MediaServerUtils.java43
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java24
-rw-r--r--services/core/java/com/android/server/net/LockdownVpnTracker.java5
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java26
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java115
-rw-r--r--services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java6
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java4
-rw-r--r--services/core/java/com/android/server/notification/NotificationChannelLogger.java7
-rw-r--r--services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java13
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java13
-rw-r--r--services/core/java/com/android/server/pm/IncrementalStates.java83
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java238
-rw-r--r--services/core/java/com/android/server/pm/Settings.java2
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java6
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/UserSystemPackageInstaller.java2
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageCacher.java11
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java8
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageParser2.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java9
-rw-r--r--services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java10
-rw-r--r--services/core/java/com/android/server/pm/permission/LegacyPermissionState.java15
-rw-r--r--services/core/java/com/android/server/pm/permission/Permission.java6
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java106
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java114
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java48
-rw-r--r--services/core/java/com/android/server/power/AmbientDisplaySuppressionController.java20
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java16
-rw-r--r--services/core/java/com/android/server/power/PowerManagerShellCommand.java49
-rw-r--r--services/core/java/com/android/server/power/ThermalManagerService.java3
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java109
-rw-r--r--services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java4
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java7
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java23
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputManagerService.java85
-rw-r--r--services/core/java/com/android/server/utils/Watchable.java51
-rw-r--r--services/core/java/com/android/server/utils/WatchableImpl.java87
-rw-r--r--services/core/java/com/android/server/utils/WatchedArrayMap.java389
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseArray.java401
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java236
-rw-r--r--services/core/java/com/android/server/utils/Watcher.java (renamed from packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java)24
-rw-r--r--services/core/java/com/android/server/utils/quota/QuotaTracker.java13
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java13
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java164
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java32
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java78
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java99
-rw-r--r--services/core/java/com/android/server/wm/AppTaskImpl.java8
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java10
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaGroup.java44
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicy.java9
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java24
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java99
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettings.java845
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java549
-rw-r--r--services/core/java/com/android/server/wm/DragDropController.java9
-rw-r--r--services/core/java/com/android/server/wm/DragState.java10
-rw-r--r--services/core/java/com/android/server/wm/EmbeddedWindowController.java4
-rw-r--r--services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java12
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java4
-rw-r--r--services/core/java/com/android/server/wm/InputConsumerImpl.java13
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java216
-rw-r--r--services/core/java/com/android/server/wm/InputWindowHandleWrapper.java278
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java45
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java6
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java48
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java104
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java20
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java61
-rw-r--r--services/core/java/com/android/server/wm/Session.java56
-rw-r--r--services/core/java/com/android/server/wm/SplashScreenStartingData.java7
-rw-r--r--services/core/java/com/android/server/wm/StartingSurfaceController.java69
-rw-r--r--services/core/java/com/android/server/wm/Task.java247
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java32
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java77
-rw-r--r--services/core/java/com/android/server/wm/TaskPersister.java4
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java46
-rw-r--r--services/core/java/com/android/server/wm/VisibleActivityProcessTracker.java122
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java23
-rw-r--r--services/core/java/com/android/server/wm/WindowFrames.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerDebugConfig.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java71
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java24
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java144
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java160
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java5
-rw-r--r--services/core/jni/Android.bp3
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp2
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp60
-rw-r--r--services/core/jni/com_android_server_net_NetworkStatsService.cpp15
-rw-r--r--services/core/jni/com_android_server_power_PowerManagerService.cpp19
-rw-r--r--services/core/xsd/cec-config/cec-config.xsd2
-rw-r--r--services/core/xsd/cec-config/schema/current.txt4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java16
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java15
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java3
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java443
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java2
-rw-r--r--services/incremental/IncrementalService.cpp30
-rw-r--r--services/incremental/IncrementalService.h1
-rw-r--r--services/incremental/ServiceWrappers.cpp1
-rw-r--r--services/incremental/ServiceWrappers.h1
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp1
-rw-r--r--services/java/com/android/server/SystemServer.java30
-rw-r--r--services/net/Android.bp5
-rw-r--r--services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java25
-rw-r--r--services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java5
-rw-r--r--services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java120
-rw-r--r--services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlocklistHelperTest.java (renamed from services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlacklistHelperTest.java)78
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt8
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt61
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt8
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt12
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemAppScanPriorityTest.kt272
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt9
-rw-r--r--services/tests/inprocesstests/Android.bp12
-rw-r--r--services/tests/inprocesstests/AndroidManifest.xml (renamed from packages/CarSystemUI/samples/sample1/rro/AndroidManifest.xml)20
-rw-r--r--services/tests/inprocesstests/AndroidTest.xml36
-rw-r--r--services/tests/inprocesstests/src/com/android/frameworks/inprocesstests/InstrumentSystemServerTest.java52
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java238
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java39
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java55
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java121
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java6
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java3
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java11
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java144
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/LocationUtils.java20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java28
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java184
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java14
-rw-r--r--services/tests/servicestests/AndroidManifest.xml2
-rw-r--r--services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java27
-rw-r--r--services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java103
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java85
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java92
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java145
-rw-r--r--services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java56
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java78
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java658
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java223
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java56
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java98
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java159
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java81
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java76
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/location/countrydetector/ComprehensiveCountryDetectorTest.java (renamed from services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java)6
-rw-r--r--services/tests/servicestests/src/com/android/server/location/countrydetector/CustomCountryDetectorTestClass.java (renamed from services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java)4
-rw-r--r--services/tests/servicestests/src/com/android/server/location/countrydetector/LocationBasedCountryDetectorTest.java (renamed from services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java)6
-rw-r--r--services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java103
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java29
-rw-r--r--services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/utils/WatcherTest.java304
-rw-r--r--services/tests/uiservicestests/Android.bp3
-rw-r--r--services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java426
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java53
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java21
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java112
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java58
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java31
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java116
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java367
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java467
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java61
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java80
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java37
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java31
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java58
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java13
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java37
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java69
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java69
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java8
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java21
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java7
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java57
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java5
-rwxr-xr-xtelecomm/java/android/telecom/Call.java7
-rw-r--r--telecomm/java/android/telecom/Connection.java13
-rw-r--r--telecomm/java/android/telecom/InCallService.java1
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java49
-rw-r--r--telephony/common/com/android/internal/telephony/CarrierAppUtils.java3
-rw-r--r--telephony/common/com/android/internal/telephony/util/TelephonyUtils.java3
-rw-r--r--telephony/java/android/telephony/CarrierBandwidth.aidl17
-rw-r--r--telephony/java/android/telephony/CarrierBandwidth.java208
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java2
-rw-r--r--telephony/java/android/telephony/CellLocation.java3
-rw-r--r--telephony/java/android/telephony/ImsManager.java49
-rw-r--r--telephony/java/android/telephony/NetworkRegistrationInfo.java4
-rw-r--r--telephony/java/android/telephony/PinResult.java63
-rw-r--r--telephony/java/android/telephony/ServiceState.java3
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java3
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java335
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java117
-rw-r--r--telephony/java/android/telephony/data/DataCallResponse.java32
-rw-r--r--telephony/java/android/telephony/ims/AudioCodecAttributes.aidl20
-rw-r--r--telephony/java/android/telephony/ims/AudioCodecAttributes.java131
-rw-r--r--telephony/java/android/telephony/ims/DelegateMessageCallback.java59
-rw-r--r--telephony/java/android/telephony/ims/DelegateRegistrationState.aidl19
-rw-r--r--telephony/java/android/telephony/ims/DelegateRegistrationState.java327
-rw-r--r--telephony/java/android/telephony/ims/DelegateRequest.aidl19
-rw-r--r--telephony/java/android/telephony/ims/DelegateRequest.java101
-rw-r--r--telephony/java/android/telephony/ims/DelegateStateCallback.java101
-rw-r--r--telephony/java/android/telephony/ims/FeatureTagState.aidl19
-rw-r--r--telephony/java/android/telephony/ims/FeatureTagState.java131
-rw-r--r--telephony/java/android/telephony/ims/ImsCallProfile.java43
-rwxr-xr-xtelephony/java/android/telephony/ims/ImsCallSession.java74
-rw-r--r--telephony/java/android/telephony/ims/ImsCallSessionListener.java57
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java14
-rw-r--r--telephony/java/android/telephony/ims/ImsRcsManager.java6
-rw-r--r--telephony/java/android/telephony/ims/ImsStreamMediaProfile.java37
-rw-r--r--telephony/java/android/telephony/ims/RtpHeaderExtension.aidl19
-rw-r--r--telephony/java/android/telephony/ims/RtpHeaderExtension.java137
-rw-r--r--telephony/java/android/telephony/ims/RtpHeaderExtensionType.aidl19
-rw-r--r--telephony/java/android/telephony/ims/RtpHeaderExtensionType.java136
-rw-r--r--telephony/java/android/telephony/ims/SipDelegateConnection.java73
-rw-r--r--telephony/java/android/telephony/ims/SipDelegateImsConfiguration.aidl19
-rw-r--r--telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java499
-rw-r--r--telephony/java/android/telephony/ims/SipDelegateManager.java329
-rw-r--r--telephony/java/android/telephony/ims/SipMessage.aidl19
-rw-r--r--telephony/java/android/telephony/ims/SipMessage.java155
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl11
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl4
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl11
-rw-r--r--telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl32
-rw-r--r--telephony/java/android/telephony/ims/aidl/ISipDelegateConnectionStateCallback.aidl34
-rw-r--r--telephony/java/android/telephony/ims/aidl/ISipDelegateMessageCallback.aidl (renamed from packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java)23
-rw-r--r--telephony/java/android/telephony/ims/aidl/ISipDelegateStateCallback.aidl33
-rw-r--r--telephony/java/android/telephony/ims/aidl/ISipTransport.aidl10
-rw-r--r--telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java192
-rw-r--r--telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java260
-rwxr-xr-xtelephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java12
-rw-r--r--telephony/java/android/telephony/ims/feature/ImsFeature.java2
-rw-r--r--telephony/java/android/telephony/ims/feature/MmTelFeature.java35
-rw-r--r--telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java54
-rw-r--r--telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java147
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java29
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java53
-rw-r--r--telephony/java/android/telephony/ims/stub/SipDelegate.java91
-rw-r--r--telephony/java/android/telephony/ims/stub/SipTransportImplBase.java131
-rw-r--r--telephony/java/com/android/ims/internal/IImsCallSession.aidl8
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl15
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java1
-rw-r--r--tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java6
-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.java8
-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.java13
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt75
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt122
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt83
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt7
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt126
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt9
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt14
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt9
-rw-r--r--tests/GamePerformance/Android.bp2
-rw-r--r--tests/Input/Android.bp1
-rw-r--r--tests/NullHomeTest/Android.bp2
-rw-r--r--tests/NullHomeTest/AndroidManifest.xml2
-rw-r--r--tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java3
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java49
-rw-r--r--tests/net/common/java/android/net/NetworkCapabilitiesTest.java2
-rw-r--r--tests/net/common/java/android/net/OemNetworkPreferencesTest.java104
-rw-r--r--tests/net/java/android/net/MacAddressTest.java4
-rw-r--r--tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java10
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java82
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java50
-rw-r--r--tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java41
-rw-r--r--tests/vcn/Android.bp27
-rw-r--r--tests/vcn/AndroidManifest.xml (renamed from packages/CarSystemUI/res/anim/car_user_switcher_close_icon_animation.xml)24
-rw-r--r--tests/vcn/AndroidTest.xml28
-rw-r--r--tests/vcn/TEST_MAPPING7
-rw-r--r--tools/aapt/Resource.cpp2
-rw-r--r--tools/aapt/ResourceTable.cpp4
-rw-r--r--tools/aapt/StringPool.cpp8
-rw-r--r--tools/aapt2/Debug.cpp8
-rw-r--r--tools/aapt2/ResourceUtils.cpp6
-rw-r--r--tools/aapt2/StringPool_test.cpp40
-rw-r--r--tools/aapt2/cmd/Compile_test.cpp6
-rw-r--r--tools/aapt2/cmd/Link.cpp24
-rw-r--r--tools/aapt2/format/binary/TableFlattener_test.cpp30
-rw-r--r--tools/aapt2/process/SymbolTable.cpp51
-rw-r--r--tools/aapt2/util/Util.cpp12
-rw-r--r--tools/codegen/src/com/android/codegen/ClassInfo.kt2
-rw-r--r--tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt3
-rw-r--r--tools/codegen/src/com/android/codegen/SharedConstants.kt2
-rw-r--r--tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt14
-rw-r--r--tools/split-select/Main.cpp18
-rw-r--r--tools/stats_log_api_gen/Android.bp3
-rw-r--r--tools/validatekeymaps/Android.bp11
-rw-r--r--tools/validatekeymaps/Main.cpp104
-rw-r--r--wifi/TEST_MAPPING13
-rw-r--r--wifi/api/current.txt9
-rw-r--r--wifi/api/system-current.txt1
-rw-r--r--wifi/jarjar-rules.txt2
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl2
-rw-r--r--wifi/java/android/net/wifi/RttManager.java2
-rw-r--r--wifi/java/android/net/wifi/SoftApConfiguration.java14
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java103
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java69
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSpecifier.java16
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java16
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java12
-rw-r--r--wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java3
-rw-r--r--wifi/tests/Android.bp2
-rw-r--r--wifi/tests/AndroidTest.xml2
-rw-r--r--wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java15
-rw-r--r--wifi/tests/src/android/net/wifi/WifiConfigurationTest.java207
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java9
2314 files changed, 69532 insertions, 66189 deletions
diff --git a/Android.bp b/Android.bp
index 6b55cc9f5ea8..6b39b514a2df 100644
--- a/Android.bp
+++ b/Android.bp
@@ -485,7 +485,6 @@ java_library {
name: "framework-internal-utils",
static_libs: [
"apex_aidl_interface-java",
- "suspend_control_aidl_interface-java",
"framework-protos",
"updatable-driver-protos",
"android.hidl.base-V1.0-java",
@@ -520,6 +519,8 @@ java_library {
"android.hardware.vibrator-V1.1-java",
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
+ "android.system.keystore2-java",
+ "android.system.suspend.control.internal-java",
"devicepolicyprotosnano",
"com.android.sysprop.apex",
@@ -580,6 +581,7 @@ java_defaults {
aidl: {
generate_get_transaction_name: true,
local_include_dirs: ["media/aidl"],
+ include_dirs: ["frameworks/av/aidl"],
},
dxflags: [
"--core-library",
@@ -596,6 +598,7 @@ java_defaults {
"framework-platform-compat-config",
// TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly.
"gps_debug.conf",
+ "icu4j-platform-compat-config",
"libcore-platform-compat-config",
"protolog.conf.json.gz",
"services-platform-compat-config",
@@ -614,6 +617,7 @@ java_defaults {
// If MimeMap ever becomes its own APEX, then this dependency would need to be removed
// in favor of an API stubs dependency in java_library "framework" below.
"mimemap",
+ "av-types-aidl-java",
"mediatranscoding_aidl_interface-java",
"soundtrigger_middleware-aidl-java",
],
@@ -782,6 +786,7 @@ filegroup {
"core/java/android/annotation/RequiresPermission.java",
"core/java/android/annotation/SdkConstant.java",
"core/java/android/annotation/StringDef.java",
+ "core/java/android/annotation/SuppressLint.java",
"core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/SystemService.java",
"core/java/android/annotation/TestApi.java",
@@ -1088,6 +1093,14 @@ filegroup {
path: "core/java",
}
+filegroup {
+ name: "activity_manager_procstate_aidl",
+ srcs: [
+ "core/java/android/app/ProcessStateEnum.aidl",
+ ],
+ path: "core/java",
+}
+
aidl_interface {
name: "libincremental_aidl",
unstable: true,
@@ -1295,7 +1308,8 @@ filegroup {
// into wifi-service
java_library {
name: "framework-wifi-util-lib",
- sdk_version: "module_30",
+ sdk_version: "module_current",
+ min_sdk_version: "30",
srcs: [
"core/java/android/content/pm/BaseParceledListSlice.java",
"core/java/android/content/pm/ParceledListSlice.java",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index faa0e5dba997..7ed7ec526686 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -86,6 +86,7 @@ stubs_defaults {
// TODO(b/169090544): remove below aidl includes.
aidl: {
local_include_dirs: ["media/aidl"],
+ include_dirs: ["frameworks/av/aidl"],
},
}
@@ -157,6 +158,7 @@ doc_defaults {
// TODO(b/169090544): remove below aidl includes.
aidl: {
local_include_dirs: ["media/aidl"],
+ include_dirs: ["frameworks/av/aidl"],
},
}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 8090bec24fdb..a245bcefbca9 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -57,6 +57,7 @@ stubs_defaults {
"telephony/java",
"media/aidl",
],
+ include_dirs: ["frameworks/av/aidl"],
},
// These are libs from framework-internal-utils that are required (i.e. being referenced)
// from framework-non-updatable-sources. Add more here when there's a need.
@@ -181,31 +182,6 @@ module_libs = " " +
"\\) "
droidstubs {
- name: "system-api-stubs-docs",
- defaults: ["metalava-full-api-stubs-default"],
- arg_files: [
- "core/res/AndroidManifest.xml",
- ],
- args: metalava_framework_docs_args + priv_apps,
- check_api: {
- current: {
- api_file: "api/system-current.txt",
- removed_api_file: "api/system-removed.txt",
- },
- last_released: {
- api_file: ":android.api.system.latest",
- removed_api_file: ":removed.api.system.latest",
- baseline_file: ":system-api-incompatibilities-with-last-released"
- },
- api_lint: {
- enabled: true,
- new_since: ":android.api.system.latest",
- baseline_file: "api/system-lint-baseline.txt",
- },
- },
-}
-
-droidstubs {
name: "system-api-stubs-docs-non-updatable",
defaults: ["metalava-non-updatable-api-stubs-default"],
arg_files: ["core/res/AndroidManifest.xml"],
@@ -229,7 +205,7 @@ droidstubs {
}
droidstubs {
- name: "test-api-stubs-docs",
+ name: "test-api-stubs-docs-non-updatable",
defaults: ["metalava-non-updatable-api-stubs-default"],
arg_files: [
"core/res/AndroidManifest.xml",
@@ -241,12 +217,12 @@ droidstubs {
+ "\\)",
check_api: {
current: {
- api_file: "api/test-current.txt",
- removed_api_file: "api/test-removed.txt",
+ api_file: "core/api/test-current.txt",
+ removed_api_file: "core/api/test-removed.txt",
},
api_lint: {
enabled: true,
- baseline_file: "api/test-lint-baseline.txt",
+ baseline_file: "core/api/test-lint-baseline.txt",
},
},
dist: {
@@ -316,14 +292,7 @@ java_defaults {
}
java_library_static {
- name: "android_monolith_stubs_current",
- srcs: [ ":api-stubs-docs" ],
- static_libs: [ "private-stub-annotations-jar" ],
- defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
- name: "android_merged_stubs_current",
+ name: "android_stubs_current",
srcs: [ ":api-stubs-docs-non-updatable" ],
static_libs: [
"conscrypt.module.public.api.stubs",
@@ -338,19 +307,6 @@ java_library_static {
"framework-wifi.stubs",
"private-stub-annotations-jar",
],
- defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
- name: "android_stubs_current",
- static_libs: ["android_merged_stubs_current"],
- defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
- name: "android_system_monolith_stubs_current",
- srcs: [ ":system-api-stubs-docs" ],
- static_libs: [ "private-stub-annotations-jar" ],
defaults: [
"android_defaults_stubs_current",
"android_stubs_dists_default",
@@ -369,7 +325,7 @@ java_library_static {
}
java_library_static {
- name: "android_system_merged_stubs_current",
+ name: "android_system_stubs_current",
srcs: [ ":system-api-stubs-docs-non-updatable" ],
static_libs: [
"conscrypt.module.public.api.stubs",
@@ -388,14 +344,8 @@ java_library_static {
}
java_library_static {
- name: "android_system_stubs_current",
- static_libs: ["android_system_merged_stubs_current"],
- defaults: ["android_defaults_stubs_current"],
-}
-
-java_library_static {
name: "android_test_stubs_current",
- srcs: [ ":test-api-stubs-docs" ],
+ srcs: [ ":test-api-stubs-docs-non-updatable" ],
static_libs: [
// Modules do not have test APIs, but we want to include their SystemApis, like we include
// the SystemApi of framework-non-updatable-sources.
diff --git a/apct-tests/perftests/core/src/android/os/ParcelStringPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelStringPerfTest.java
new file mode 100644
index 000000000000..2b861cb66890
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/ParcelStringPerfTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.os;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class ParcelStringPerfTest {
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameterized.Parameter(0)
+ public String mName;
+ @Parameterized.Parameter(1)
+ public String mValue;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Collection<Object[]> getParameters() {
+ return Arrays.asList(new Object[][] {
+ { "simple", "com.example.typical_package_name" },
+ { "complex", "從不喜歡孤單一個 - 蘇永康/吳雨霏" },
+ });
+ }
+
+ @Test
+ public void timeWriteString8() {
+ final Parcel parcel = Parcel.obtain();
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ parcel.setDataPosition(0);
+ parcel.writeString8(mValue);
+ }
+ }
+
+ @Test
+ public void timeWriteString16() {
+ final Parcel parcel = Parcel.obtain();
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ parcel.setDataPosition(0);
+ parcel.writeString16(mValue);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/os/VibratorPerfTest.java b/apct-tests/perftests/core/src/android/os/VibratorPerfTest.java
index d78c8b4702c1..0efe8cf85dba 100644
--- a/apct-tests/perftests/core/src/android/os/VibratorPerfTest.java
+++ b/apct-tests/perftests/core/src/android/os/VibratorPerfTest.java
@@ -19,9 +19,9 @@ package android.os;
import static java.util.concurrent.TimeUnit.SECONDS;
import android.content.Context;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
+import androidx.benchmark.BenchmarkState;
+import androidx.benchmark.junit4.BenchmarkRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
@@ -32,7 +32,7 @@ import org.junit.Test;
@LargeTest
public class VibratorPerfTest {
@Rule
- public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ public final BenchmarkRule mBenchmarkRule = new BenchmarkRule();
private Vibrator mVibrator;
@@ -44,7 +44,7 @@ public class VibratorPerfTest {
@Test
public void testEffectClick() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final BenchmarkState state = mBenchmarkRule.getState();
while (state.keepRunning()) {
mVibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
}
@@ -52,7 +52,7 @@ public class VibratorPerfTest {
@Test
public void testOneShot() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final BenchmarkState state = mBenchmarkRule.getState();
while (state.keepRunning()) {
mVibrator.vibrate(VibrationEffect.createOneShot(SECONDS.toMillis(2),
VibrationEffect.DEFAULT_AMPLITUDE));
@@ -61,7 +61,7 @@ public class VibratorPerfTest {
@Test
public void testWaveform() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final BenchmarkState state = mBenchmarkRule.getState();
long[] timings = new long[]{SECONDS.toMillis(1), SECONDS.toMillis(2), SECONDS.toMillis(1)};
while (state.keepRunning()) {
mVibrator.vibrate(VibrationEffect.createWaveform(timings, -1));
@@ -70,7 +70,7 @@ public class VibratorPerfTest {
@Test
public void testCompose() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final BenchmarkState state = mBenchmarkRule.getState();
while (state.keepRunning()) {
mVibrator.vibrate(
VibrationEffect.startComposition()
@@ -82,7 +82,7 @@ public class VibratorPerfTest {
@Test
public void testAreEffectsSupported() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final BenchmarkState state = mBenchmarkRule.getState();
int[] effects = new int[]{VibrationEffect.EFFECT_CLICK, VibrationEffect.EFFECT_TICK};
while (state.keepRunning()) {
mVibrator.areEffectsSupported(effects);
@@ -91,7 +91,7 @@ public class VibratorPerfTest {
@Test
public void testArePrimitivesSupported() {
- final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final BenchmarkState state = mBenchmarkRule.getState();
int[] primitives = new int[]{VibrationEffect.Composition.PRIMITIVE_CLICK,
VibrationEffect.Composition.PRIMITIVE_TICK};
while (state.keepRunning()) {
diff --git a/apct-tests/perftests/core/src/android/util/CharsetUtilsPerfTest.java b/apct-tests/perftests/core/src/android/util/CharsetUtilsPerfTest.java
new file mode 100644
index 000000000000..e2c580ce8eae
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/util/CharsetUtilsPerfTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.util;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+
+import dalvik.system.VMRuntime;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collection;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class CharsetUtilsPerfTest {
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameterized.Parameter(0)
+ public String mName;
+ @Parameterized.Parameter(1)
+ public String mValue;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Collection<Object[]> getParameters() {
+ return Arrays.asList(new Object[][] {
+ { "simple", "com.example.typical_package_name" },
+ { "complex", "從不喜歡孤單一個 - 蘇永康/吳雨霏" },
+ });
+ }
+
+ @Test
+ public void timeUpstream() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mValue.getBytes(StandardCharsets.UTF_8);
+ }
+ }
+
+ /**
+ * Measure performance of writing into a small buffer where bounds checking
+ * requires careful measurement of encoded size.
+ */
+ @Test
+ public void timeLocal_SmallBuffer() {
+ final byte[] dest = (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, 64);
+ final long destPtr = VMRuntime.getRuntime().addressOf(dest);
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ CharsetUtils.toModifiedUtf8Bytes(mValue, destPtr, 0, dest.length);
+ }
+ }
+
+ /**
+ * Measure performance of writing into a large buffer where bounds checking
+ * only needs a simple worst-case 4-bytes-per-char check.
+ */
+ @Test
+ public void timeLocal_LargeBuffer() {
+ final byte[] dest = (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, 1024);
+ final long destPtr = VMRuntime.getRuntime().addressOf(dest);
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ CharsetUtils.toModifiedUtf8Bytes(mValue, destPtr, 0, dest.length);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/util/XmlPerfTest.java b/apct-tests/perftests/core/src/android/util/XmlPerfTest.java
new file mode 100644
index 000000000000..e05bd2aad20e
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/util/XmlPerfTest.java
@@ -0,0 +1,292 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Bundle;
+import android.os.Debug;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.HexDump;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.function.Supplier;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class XmlPerfTest {
+ /**
+ * Since allocation measurement adds overhead, it's disabled by default for
+ * performance runs. It can be manually enabled to compare GC behavior.
+ */
+ private static final boolean MEASURE_ALLOC = false;
+
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeWrite_Fast() throws Exception {
+ doWrite(() -> Xml.newFastSerializer());
+ }
+
+ @Test
+ public void timeWrite_Binary() throws Exception {
+ doWrite(() -> Xml.newBinarySerializer());
+ }
+
+ private void doWrite(Supplier<TypedXmlSerializer> outFactory) throws Exception {
+ if (MEASURE_ALLOC) {
+ Debug.startAllocCounting();
+ }
+
+ int iterations = 0;
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ iterations++;
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+ final TypedXmlSerializer out = outFactory.get();
+ out.setOutput(os, StandardCharsets.UTF_8.name());
+ write(out);
+ }
+ }
+
+ if (MEASURE_ALLOC) {
+ Debug.stopAllocCounting();
+ final Bundle results = new Bundle();
+ results.putLong("threadAllocCount_mean", Debug.getThreadAllocCount() / iterations);
+ results.putLong("threadAllocSize_mean", Debug.getThreadAllocSize() / iterations);
+ InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
+ }
+ }
+
+ @Test
+ public void timeRead_Fast() throws Exception {
+ doRead(() -> Xml.newFastSerializer(), () -> Xml.newFastPullParser());
+ }
+
+ @Test
+ public void timeRead_Binary() throws Exception {
+ doRead(() -> Xml.newBinarySerializer(), () -> Xml.newBinaryPullParser());
+ }
+
+ private void doRead(Supplier<TypedXmlSerializer> outFactory,
+ Supplier<TypedXmlPullParser> inFactory) throws Exception {
+ final byte[] raw;
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+ TypedXmlSerializer out = outFactory.get();
+ out.setOutput(os, StandardCharsets.UTF_8.name());
+ write(out);
+ raw = os.toByteArray();
+ }
+
+ if (MEASURE_ALLOC) {
+ Debug.startAllocCounting();
+ }
+
+ int iterations = 0;
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ iterations++;
+ try (ByteArrayInputStream is = new ByteArrayInputStream(raw)) {
+ TypedXmlPullParser xml = inFactory.get();
+ xml.setInput(is, StandardCharsets.UTF_8.name());
+ read(xml);
+ }
+ }
+
+ if (MEASURE_ALLOC) {
+ Debug.stopAllocCounting();
+ final Bundle results = new Bundle();
+ results.putLong("sizeBytes", raw.length);
+ results.putLong("threadAllocCount_mean", Debug.getThreadAllocCount() / iterations);
+ results.putLong("threadAllocSize_mean", Debug.getThreadAllocSize() / iterations);
+ InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
+ } else {
+ final Bundle results = new Bundle();
+ results.putLong("sizeBytes", raw.length);
+ InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
+ }
+ }
+
+ /**
+ * Not even joking, this is a typical public key blob stored in
+ * {@code packages.xml}.
+ */
+ private static final byte[] KEY_BLOB = HexDump.hexStringToByteArray(""
+ + "308204a830820390a003020102020900a1573d0f45bea193300d06092a864886f70d010105050030819"
+ + "4310b3009060355040613025553311330110603550408130a43616c69666f726e696131163014060355"
+ + "0407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e06035"
+ + "5040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d"
+ + "0109011613616e64726f696440616e64726f69642e636f6d301e170d3131303931393138343232355a1"
+ + "70d3339303230343138343232355a308194310b3009060355040613025553311330110603550408130a"
+ + "43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e0603550"
+ + "40a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e"
+ + "64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d3"
+ + "0820120300d06092a864886f70d01010105000382010d00308201080282010100de1b51336afc909d8b"
+ + "cca5920fcdc8940578ec5c253898930e985481cfdea75ba6fc54b1f7bb492a03d98db471ab4200103a8"
+ + "314e60ee25fef6c8b83bc1b2b45b084874cffef148fa2001bb25c672b6beba50b7ac026b546da762ea2"
+ + "23829a22b80ef286131f059d2c9b4ca71d54e515a8a3fd6bf5f12a2493dfc2619b337b032a7cf8bbd34"
+ + "b833f2b93aeab3d325549a93272093943bb59dfc0197ae4861ff514e019b73f5cf10023ad1a032adb4b"
+ + "9bbaeb4debecb4941d6a02381f1165e1ac884c1fca9525c5854dce2ad8ec839b8ce78442c16367efc07"
+ + "778a337d3ca2cdf9792ac722b95d67c345f1c00976ec372f02bfcbef0262cc512a6845e71cfea0d0201"
+ + "03a381fc3081f9301d0603551d0e0416041478a0fc4517fb70ff52210df33c8d32290a44b2bb3081c90"
+ + "603551d230481c13081be801478a0fc4517fb70ff52210df33c8d32290a44b2bba1819aa48197308194"
+ + "310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550"
+ + "407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355"
+ + "040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0"
+ + "109011613616e64726f696440616e64726f69642e636f6d820900a1573d0f45bea193300c0603551d13"
+ + "040530030101ff300d06092a864886f70d01010505000382010100977302dfbf668d7c61841c9c78d25"
+ + "63bcda1b199e95e6275a799939981416909722713531157f3cdcfea94eea7bb79ca3ca972bd8058a36a"
+ + "d1919291df42d7190678d4ea47a4b9552c9dfb260e6d0d9129b44615cd641c1080580e8a990dd768c6a"
+ + "b500c3b964e185874e4105109d94c5bd8c405deb3cf0f7960a563bfab58169a956372167a7e2674a04c"
+ + "4f80015d8f7869a7a4139aecbbdca2abc294144ee01e4109f0e47a518363cf6e9bf41f7560e94bdd4a5"
+ + "d085234796b05c7a1389adfd489feec2a107955129d7991daa49afb3d327dc0dc4fe959789372b093a8"
+ + "9c8dbfa41554f771c18015a6cb242a17e04d19d55d3b4664eae12caf2a11cd2b836e");
+
+ /**
+ * Typical list of permissions referenced in {@code packages.xml}.
+ */
+ private static final String[] PERMS = new String[] {
+ "android.permission.ACCESS_CACHE_FILESYSTEM",
+ "android.permission.WRITE_SETTINGS",
+ "android.permission.MANAGE_EXTERNAL_STORAGE",
+ "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS",
+ "android.permission.FOREGROUND_SERVICE",
+ "android.permission.RECEIVE_BOOT_COMPLETED",
+ "android.permission.WRITE_MEDIA_STORAGE",
+ "android.permission.INTERNET",
+ "android.permission.UPDATE_DEVICE_STATS",
+ "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY",
+ "android.permission.MANAGE_USB",
+ "android.permission.ACCESS_ALL_DOWNLOADS",
+ "android.permission.ACCESS_DOWNLOAD_MANAGER",
+ "android.permission.MANAGE_USERS",
+ "android.permission.ACCESS_NETWORK_STATE",
+ "android.permission.ACCESS_MTP",
+ "android.permission.INTERACT_ACROSS_USERS",
+ "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS",
+ "android.permission.CLEAR_APP_CACHE",
+ "android.permission.CONNECTIVITY_INTERNAL",
+ "android.permission.START_ACTIVITIES_FROM_BACKGROUND",
+ "android.permission.QUERY_ALL_PACKAGES",
+ "android.permission.WAKE_LOCK",
+ "android.permission.UPDATE_APP_OPS_STATS",
+ };
+
+ /**
+ * Write a typical {@code packages.xml} file containing 100 applications,
+ * each of which defines signing key and permission information.
+ */
+ private static void write(TypedXmlSerializer out) throws IOException {
+ out.startDocument(null, true);
+ out.startTag(null, "packages");
+ for (int i = 0; i < 100; i++) {
+ out.startTag(null, "package");
+ out.attribute(null, "name", "com.android.providers.media");
+ out.attribute(null, "codePath", "/system/priv-app/MediaProviderLegacy");
+ out.attribute(null, "nativeLibraryPath", "/system/priv-app/MediaProviderLegacy/lib");
+ out.attributeLong(null, "publicFlags", 944258629L);
+ out.attributeLong(null, "privateFlags", -1946152952L);
+ out.attributeLong(null, "ft", 1603899064000L);
+ out.attributeLong(null, "it", 1603899064000L);
+ out.attributeLong(null, "ut", 1603899064000L);
+ out.attributeInt(null, "version", 1024);
+ out.attributeInt(null, "sharedUserId", 10100);
+ out.attributeBoolean(null, "isOrphaned", true);
+
+ out.startTag(null, "sigs");
+ out.startTag(null, "cert");
+ out.attributeInt(null, "index", 10);
+ out.attributeBytesHex(null, "key", KEY_BLOB);
+ out.endTag(null, "cert");
+ out.endTag(null, "sigs");
+
+ out.startTag(null, "perms");
+ for (String perm : PERMS) {
+ out.startTag(null, "item");
+ out.attributeInterned(null, "name", perm);
+ out.attributeBoolean(null, "granted", true);
+ out.attributeInt(null, "flags", 0);
+ out.endTag(null, "item");
+ }
+ out.endTag(null, "perms");
+
+ out.endTag(null, "package");
+ }
+ out.endTag(null, "packages");
+ out.endDocument();
+ }
+
+ /**
+ * Read a typical {@code packages.xml} file containing 100 applications, and
+ * verify that data passes smell test.
+ */
+ private static void read(TypedXmlPullParser xml) throws Exception {
+ int type;
+ int packages = 0;
+ int certs = 0;
+ int perms = 0;
+ while ((type = xml.next()) != XmlPullParser.END_DOCUMENT) {
+ final String tag = xml.getName();
+ if (type == XmlPullParser.START_TAG) {
+ if ("package".equals(tag)) {
+ xml.getAttributeValue(null, "name");
+ xml.getAttributeValue(null, "codePath");
+ xml.getAttributeValue(null, "nativeLibraryPath");
+ xml.getAttributeLong(null, "publicFlags");
+ assertEquals(-1946152952L, xml.getAttributeLong(null, "privateFlags"));
+ xml.getAttributeLong(null, "ft");
+ xml.getAttributeLong(null, "it");
+ xml.getAttributeLong(null, "ut");
+ xml.getAttributeInt(null, "version");
+ xml.getAttributeInt(null, "sharedUserId");
+ xml.getAttributeBoolean(null, "isOrphaned");
+ packages++;
+ } else if ("cert".equals(tag)) {
+ xml.getAttributeInt(null, "index");
+ xml.getAttributeBytesHex(null, "key");
+ certs++;
+ } else if ("item".equals(tag)) {
+ xml.getAttributeValue(null, "name");
+ xml.getAttributeBoolean(null, "granted");
+ xml.getAttributeInt(null, "flags");
+ perms++;
+ }
+ } else if (type == XmlPullParser.TEXT) {
+ xml.getText();
+ }
+ }
+
+ assertEquals(100, packages);
+ assertEquals(packages * 1, certs);
+ assertEquals(packages * PERMS.length, perms);
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/view/InputStageBenchmark.java b/apct-tests/perftests/core/src/android/view/InputStageBenchmark.java
new file mode 100644
index 000000000000..b45dbcf559c9
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/view/InputStageBenchmark.java
@@ -0,0 +1,237 @@
+/*
+ * 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.view;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.perftests.utils.PerfTestActivity;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class InputStageBenchmark {
+ @Parameterized.Parameters(name = "mShowIme({0}), mHandlePreIme({1})")
+ public static Collection cases() {
+ return Arrays.asList(new Object[][] {
+ { false /* no ime */, false /* skip preime */},
+ { true /* show ime */, false /* skip preime */},
+ { true /* show ime */, true /* handle preime */}
+ });
+ }
+
+ @Rule
+ public final ActivityTestRule<PerfTestActivity> mActivityRule =
+ new ActivityTestRule<>(PerfTestActivity.class);
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Parameterized.Parameter(0)
+ public boolean mShowIme;
+ @Parameterized.Parameter(1)
+ public boolean mHandlePreIme;
+
+ private Instrumentation mInstrumentation;
+ private Window mWindow;
+ private CountDownLatch mWaitForReceiveInput;
+ private static final long TIMEOUT_MS = 5000;
+
+ class InstrumentedView extends View {
+ InstrumentedView(Context context) {
+ super(context);
+ setFocusable(true);
+ }
+
+ @Override
+ public boolean dispatchKeyEventPreIme(KeyEvent event) {
+ if (mHandlePreIme) {
+ mWaitForReceiveInput.countDown();
+ }
+ return mHandlePreIme;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ mWaitForReceiveInput.countDown();
+ return true;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ mWaitForReceiveInput.countDown();
+ return true;
+ }
+ }
+
+ class InstrumentedEditText extends EditText {
+ InstrumentedEditText(Context context) {
+ super(context);
+ setFocusable(true);
+ }
+
+ @Override
+ public boolean dispatchKeyEventPreIme(KeyEvent event) {
+ if (mHandlePreIme) {
+ mWaitForReceiveInput.countDown();
+ }
+ return mHandlePreIme;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ mWaitForReceiveInput.countDown();
+ return true;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ mWaitForReceiveInput.countDown();
+ return true;
+ }
+ }
+
+ private CountDownLatch showSoftKeyboard(View view) {
+ final CountDownLatch waitForIme = new CountDownLatch(1);
+ view.setOnApplyWindowInsetsListener((v, insets) -> {
+ if (insets.isVisible(WindowInsets.Type.ime())) {
+ waitForIme.countDown();
+ }
+ return insets;
+ });
+
+ assertTrue("Failed to request focus.", view.requestFocus());
+ final InputMethodManager imm =
+ mActivityRule.getActivity().getSystemService(InputMethodManager.class);
+ imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
+
+ return waitForIme;
+ }
+
+ @Before
+ public void setUp() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ final Activity activity = mActivityRule.getActivity();
+
+ final CountDownLatch[] waitForIme = new CountDownLatch[1];
+ mInstrumentation.runOnMainSync(() -> {
+ mWindow = mActivityRule.getActivity().getWindow();
+
+ if (mShowIme) {
+ final EditText edit = new InstrumentedEditText(activity);
+ mWindow.setContentView(edit);
+ waitForIme[0] = showSoftKeyboard(edit);
+ } else {
+ final View v = new InstrumentedView(activity);
+ // set FLAG_LOCAL_FOCUS_MODE to prevent delivering input events to the ime
+ // in ImeInputStage.
+ mWindow.addFlags(WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE);
+ mWindow.setContentView(v);
+ assertTrue("Failed to request focus.", v.requestFocus());
+ }
+ });
+ if (waitForIme[0] != null) {
+ try {
+ assertTrue("Failed to show InputMethod.",
+ waitForIme[0].await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ mInstrumentation.waitForIdleSync();
+ }
+
+ private void injectInputEvent(InputEvent event) {
+ mWaitForReceiveInput = new CountDownLatch(1);
+ mInstrumentation.runOnMainSync(() -> mWindow.injectInputEvent(event));
+ try {
+ mWaitForReceiveInput.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void testKeyEvent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ final KeyEvent eventDown =
+ new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACKSLASH);
+ injectInputEvent(eventDown);
+
+ state.pauseTiming();
+ final KeyEvent eventUp =
+ new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACKSLASH);
+ injectInputEvent(eventUp);
+ state.resumeTiming();
+ }
+ }
+
+ @Test
+ public void testMotionEvent() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final Rect contentFrame = new Rect();
+ mInstrumentation.runOnMainSync(() ->
+ mWindow.getDecorView().getBoundsOnScreen(contentFrame));
+ final int x = contentFrame.centerX();
+ final int y = contentFrame.centerY();
+ final long eventTime = SystemClock.uptimeMillis();
+
+ while (state.keepRunning()) {
+ final MotionEvent eventDown = MotionEvent.obtain(eventTime, eventTime,
+ MotionEvent.ACTION_DOWN, x, y,
+ 1.0f /* pressure */, 1.0f /* size */, 0 /* metaState */,
+ 1.0f /* xPrecision */, 1.0f /* yPrecision */,
+ 0 /* deviceId */, 0 /* edgeFlags */,
+ InputDevice.SOURCE_TOUCHSCREEN, DEFAULT_DISPLAY);
+ injectInputEvent(eventDown);
+
+ state.pauseTiming();
+ final MotionEvent eventUp = MotionEvent.obtain(eventTime, eventTime,
+ MotionEvent.ACTION_UP, x, y,
+ 1.0f /* pressure */, 1.0f /* size */, 0 /* metaState */,
+ 1.0f /* xPrecision */, 1.0f /* yPrecision */,
+ 0 /* deviceId */, 0 /* edgeFlags */,
+ InputDevice.SOURCE_TOUCHSCREEN, DEFAULT_DISPLAY);
+ injectInputEvent(eventUp);
+ state.resumeTiming();
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java
new file mode 100644
index 000000000000..2700fff4cba1
--- /dev/null
+++ b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.util;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class FastDataPerfTest {
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ private static final int OUTPUT_SIZE = 64000;
+ private static final int BUFFER_SIZE = 4096;
+
+ @Test
+ public void timeWrite_Upstream() throws IOException {
+ final ByteArrayOutputStream os = new ByteArrayOutputStream(OUTPUT_SIZE);
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ os.reset();
+ final BufferedOutputStream bos = new BufferedOutputStream(os, BUFFER_SIZE);
+ final DataOutput out = new DataOutputStream(bos);
+ doWrite(out);
+ bos.flush();
+ }
+ }
+
+ @Test
+ public void timeWrite_Local() throws IOException {
+ final ByteArrayOutputStream os = new ByteArrayOutputStream(OUTPUT_SIZE);
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ os.reset();
+ final FastDataOutput out = new FastDataOutput(os, BUFFER_SIZE);
+ doWrite(out);
+ out.flush();
+ }
+ }
+
+ @Test
+ public void timeRead_Upstream() throws Exception {
+ final ByteArrayInputStream is = new ByteArrayInputStream(doWrite());
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ is.reset();
+ final BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
+ final DataInput in = new DataInputStream(bis);
+ doRead(in);
+ }
+ }
+
+ @Test
+ public void timeRead_Local() throws Exception {
+ final ByteArrayInputStream is = new ByteArrayInputStream(doWrite());
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ is.reset();
+ final DataInput in = new FastDataInput(is, BUFFER_SIZE);
+ doRead(in);
+ }
+ }
+
+ /**
+ * Since each iteration is around 64 bytes, we need to iterate many times to
+ * exercise the buffer logic.
+ */
+ private static final int REPEATS = 1000;
+
+ private static byte[] doWrite() throws IOException {
+ final ByteArrayOutputStream os = new ByteArrayOutputStream(OUTPUT_SIZE);
+ final DataOutput out = new DataOutputStream(os);
+ doWrite(out);
+ return os.toByteArray();
+ }
+
+ private static void doWrite(DataOutput out) throws IOException {
+ for (int i = 0; i < REPEATS; i++) {
+ out.writeByte(Byte.MAX_VALUE);
+ out.writeShort(Short.MAX_VALUE);
+ out.writeInt(Integer.MAX_VALUE);
+ out.writeLong(Long.MAX_VALUE);
+ out.writeFloat(Float.MAX_VALUE);
+ out.writeDouble(Double.MAX_VALUE);
+ out.writeUTF("com.example.typical_package_name");
+ }
+ }
+
+ private static void doRead(DataInput in) throws IOException {
+ for (int i = 0; i < REPEATS; i++) {
+ in.readByte();
+ in.readShort();
+ in.readInt();
+ in.readLong();
+ in.readFloat();
+ in.readDouble();
+ in.readUTF();
+ }
+ }
+}
diff --git a/packages/CarSystemUI/samples/sample1/rro/Android.bp b/apct-tests/perftests/inputmethod/Android.bp
index 5b0347ff73fd..463ac9b8b0c8 100644
--- a/packages/CarSystemUI/samples/sample1/rro/Android.bp
+++ b/apct-tests/perftests/inputmethod/Android.bp
@@ -1,4 +1,3 @@
-//
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,16 +11,20 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
-android_app {
- name: "CarSystemUISampleOneRRO",
- resource_dirs: ["res"],
- certificate: "platform",
+android_test {
+ name: "ImePerfTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.annotation_annotation",
+ "apct-perftests-utils",
+ "collector-device-lib",
+ "compatibility-device-util-axt",
+ "platform-test-annotations",
+ ],
+ test_suites: ["device-tests"],
+ data: [":perfetto_artifacts"],
platform_apis: true,
- manifest: "AndroidManifest.xml",
- aaptflags: [
- "--no-resource-deduping",
- "--no-resource-removal",
- ]
-} \ No newline at end of file
+ certificate: "platform",
+}
diff --git a/apct-tests/perftests/inputmethod/AndroidManifest.xml b/apct-tests/perftests/inputmethod/AndroidManifest.xml
new file mode 100644
index 000000000000..1fb0b880953b
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?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.perftests.inputmethod">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.perftests.utils.PerfTestActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.perftests.core.PERFTEST" />
+ </intent-filter>
+ </activity>
+ <service android:name="android.inputmethod.ImePerfTest$BaselineIme"
+ android:process=":BaselineIME"
+ android:label="Baseline IME"
+ android:permission="android.permission.BIND_INPUT_METHOD"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.view.InputMethod"/>
+ </intent-filter>
+ <meta-data android:name="android.view.im"
+ android:resource="@xml/simple_method"/>
+ </service>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.perftests.inputmethod">
+ <meta-data android:name="listener" android:value="android.inputmethod.ImePerfRunPrecondition" />
+ </instrumentation>
+</manifest>
diff --git a/apct-tests/perftests/inputmethod/AndroidTest.xml b/apct-tests/perftests/inputmethod/AndroidTest.xml
new file mode 100644
index 000000000000..1ec0cbadb6bd
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/AndroidTest.xml
@@ -0,0 +1,73 @@
+<?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.
+-->
+<configuration description="Runs ImePerfTests metric instrumentation.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-metric-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="ImePerfTests.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" />
+ <option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
+ <option name="run-command" value="cmd window dismiss-keyguard" />
+ <option name="run-command" value="cmd package compile -m speed com.android.perftests.inputmethod" />
+ </target_preparer>
+
+ <!-- Needed for pushing the trace config file -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+ <!--Install the content provider automatically when we push some file in sdcard folder.-->
+ <!--Needed to avoid the installation during the test suite.-->
+ <option name="push-file" key="trace_config_detailed.textproto" value="/sdcard/sample.textproto" />
+ </target_preparer>
+
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false" />
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.perftests.inputmethod" />
+ <option name="hidden-api-checks" value="false"/>
+
+ <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+ <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+
+ <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+ <!-- Kill background operations -->
+ <option name="instrumentation-arg" key="kill-bg" value="true" />
+
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+ <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+ </test>
+
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/data/local/tmp/ImePerfTests" />
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+</configuration>
diff --git a/apct-tests/perftests/inputmethod/README.md b/apct-tests/perftests/inputmethod/README.md
new file mode 100644
index 000000000000..8ba20879591b
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/README.md
@@ -0,0 +1,40 @@
+## IMF performance tests
+
+These tests are adaptation of Window Manager perf tests (apct-tests/perftests/windowmanager).
+
+### Precondition
+To reduce the variance of the test, if `perf-setup` (platform_testing/scripts/perf-setup)
+is available, it is better to use the following instructions to lock CPU and GPU frequencies.
+```
+m perf-setup
+PERF_SETUP_PATH=/data/local/tmp/perf-setup.sh
+adb push $OUT/$PERF_SETUP_PATH $PERF_SETUP_PATH
+adb shell chmod +x $PERF_SETUP_PATH
+adb shell $PERF_SETUP_PATH
+```
+
+### Example to run
+Use `atest`
+```
+atest ImePerfTests:ImePerfTest -- \
+ --module-arg ImePerfTests:instrumentation-arg:profiling-iterations:=20
+
+```
+Note: `instrumentation-arg:kill-bg:=true` is already defined in the AndroidText.xml
+
+Use `am instrument`
+```
+adb shell am instrument -w -r -e class android.inputmethod.ImePerfTest \
+ -e listener android.inputmethod.ImePerfRunPrecondition \
+ -e kill-bg true \
+ com.android.perftests.inputmethod/androidx.test.runner.AndroidJUnitRunner
+```
+* `kill-bg` is optional.
+
+Test arguments
+ - kill-bg
+ * boolean: Kill background process before running test.
+ - profiling-iterations
+ * int: Run the extra iterations with enabling method profiling.
+ - profiling-sampling
+ * int: The interval (0=trace each method, default is 10) of sample profiling in microseconds.
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/values/colors.xml b/apct-tests/perftests/inputmethod/res/xml/simple_method.xml
index f98cb96e76e8..87cb1ad205a0 100644
--- a/packages/CarSystemUI/samples/sample3/rro/res/values/colors.xml
+++ b/apct-tests/perftests/inputmethod/res/xml/simple_method.xml
@@ -14,6 +14,6 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <color name="car_nav_icon_fill_color">#8F8F8F</color>
-</resources>
+
+<!-- Configuration info for an input method -->
+<input-method xmlns:android="http://schemas.android.com/apk/res/android" />
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java
new file mode 100644
index 000000000000..fc48fd5271a8
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfRunPrecondition.java
@@ -0,0 +1,149 @@
+/*
+ * 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.inputmethod;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.inputmethod.ImePerfTestBase.executeShellCommand;
+import static android.inputmethod.ImePerfTestBase.runWithShellPermissionIdentity;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.inputmethod.ImePerfTestBase.SettingsSession;
+import android.os.BatteryManager;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.WindowManagerPolicyConstants;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.policy.PhoneWindow;
+
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+import org.junit.runner.notification.RunListener;
+
+import java.util.List;
+
+/** Prepare the preconditions before running performance test. */
+public class ImePerfRunPrecondition extends RunListener {
+ private static final String TAG = ImePerfRunPrecondition.class.getSimpleName();
+
+ private static final String ARGUMENT_LOG_ONLY = "log";
+ private static final String ARGUMENT_KILL_BACKGROUND = "kill-bg";
+ private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations";
+ private static final String ARGUMENT_PROFILING_SAMPLING = "profiling-sampling";
+ private static final String DEFAULT_PROFILING_ITERATIONS = "10";
+ private static final String DEFAULT_PROFILING_SAMPLING_US = "10";
+ private static final long KILL_BACKGROUND_WAIT_MS = 3000;
+
+ /** The requested iterations to run with method profiling. */
+ static int sProfilingIterations;
+
+ /** The interval of sample profiling in microseconds. */
+ static int sSamplingIntervalUs;
+
+ private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ private long mWaitPreconditionDoneMs = 500;
+
+ private final SettingsSession<Integer> mStayOnWhilePluggedInSetting = new SettingsSession<>(
+ Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0),
+ value -> executeShellCommand(String.format("settings put global %s %d",
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value)));
+
+ private final SettingsSession<Integer> mNavigationModeSetting = new SettingsSession<>(
+ mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_navBarInteractionMode),
+ value -> {
+ final String navOverlay;
+ switch (value) {
+ case WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL:
+ default:
+ navOverlay = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
+ break;
+ }
+ executeShellCommand("cmd overlay enable-exclusive " + navOverlay);
+ });
+
+ /** It only executes once before all tests. */
+ @Override
+ public void testRunStarted(Description description) {
+ final Bundle arguments = InstrumentationRegistry.getArguments();
+ // If true, it only logs the method names without running.
+ final boolean skip = Boolean.parseBoolean(arguments.getString(ARGUMENT_LOG_ONLY, "false"));
+ Log.i(TAG, "arguments=" + arguments);
+ if (skip) {
+ return;
+ }
+ sProfilingIterations = Integer.parseInt(
+ arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
+ sSamplingIntervalUs = Integer.parseInt(
+ arguments.getString(ARGUMENT_PROFILING_SAMPLING, DEFAULT_PROFILING_SAMPLING_US));
+
+ // Use same navigation mode (gesture navigation) across all devices and tests
+ // for consistency.
+ mNavigationModeSetting.set(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL);
+ // Keep the device awake during testing.
+ mStayOnWhilePluggedInSetting.set(BatteryManager.BATTERY_PLUGGED_ANY);
+
+ runWithShellPermissionIdentity(() -> {
+ final ActivityTaskManager atm = mContext.getSystemService(ActivityTaskManager.class);
+ atm.removeAllVisibleRecentTasks();
+ atm.removeRootTasksWithActivityTypes(new int[] { ACTIVITY_TYPE_STANDARD,
+ ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, ACTIVITY_TYPE_UNDEFINED });
+ });
+ PhoneWindow.sendCloseSystemWindows(mContext, "ImePerfTests");
+
+ if (Boolean.parseBoolean(arguments.getString(ARGUMENT_KILL_BACKGROUND))) {
+ runWithShellPermissionIdentity(this::killBackgroundProcesses);
+ mWaitPreconditionDoneMs = KILL_BACKGROUND_WAIT_MS;
+ }
+ // Wait a while for the precondition setup to complete.
+ SystemClock.sleep(mWaitPreconditionDoneMs);
+ }
+
+ private void killBackgroundProcesses() {
+ Log.i(TAG, "Killing background processes...");
+ final ActivityManager am = mContext.getSystemService(ActivityManager.class);
+ final List<RunningAppProcessInfo> processes = am.getRunningAppProcesses();
+ if (processes == null) {
+ return;
+ }
+ for (RunningAppProcessInfo processInfo : processes) {
+ if (processInfo.importanceReasonCode == RunningAppProcessInfo.REASON_UNKNOWN
+ && processInfo.importance > RunningAppProcessInfo.IMPORTANCE_SERVICE) {
+ for (String pkg : processInfo.pkgList) {
+ am.forceStopPackage(pkg);
+ }
+ }
+ }
+ }
+
+ /** It only executes once after all tests. */
+ @Override
+ public void testRunFinished(Result result) {
+ mNavigationModeSetting.close();
+ mStayOnWhilePluggedInSetting.close();
+ }
+}
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
new file mode 100644
index 000000000000..303c667351d1
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTest.java
@@ -0,0 +1,380 @@
+/*
+ * 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.inputmethod;
+
+import static android.perftests.utils.ManualBenchmarkState.StatsReport;
+import static android.perftests.utils.PerfTestActivity.ID_EDITOR;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.inputmethodservice.InputMethodService;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.perftests.utils.ManualBenchmarkState;
+import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest;
+import android.perftests.utils.PerfManualStatusReporter;
+import android.perftests.utils.TraceMarkParser;
+import android.perftests.utils.TraceMarkParser.TraceMarkSlice;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
+import android.view.WindowInsetsController;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.filters.LargeTest;
+
+import com.android.compatibility.common.util.PollingCheck;
+
+import junit.framework.Assert;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+/** Measure the performance of internal methods in Input Method framework by trace tag. */
+@LargeTest
+public class ImePerfTest extends ImePerfTestBase
+ implements ManualBenchmarkState.CustomizedIterationListener {
+ private static final String TAG = ImePerfTest.class.getSimpleName();
+
+ @Rule
+ public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
+
+ @Rule
+ public final PerfTestActivityRule mActivityRule = new PerfTestActivityRule();
+
+ /**
+ * IMF common methods to log for show/hide in trace.
+ */
+ private String[] mCommonMethods = {
+ "IC.pendingAnim",
+ "IMMS.applyImeVisibility",
+ "applyPostLayoutPolicy",
+ "applyWindowSurfaceChanges",
+ "ISC.onPostLayout"
+ };
+
+ /** IMF show methods to log in trace. */
+ private String[] mShowMethods = {
+ "IC.showRequestFromIme",
+ "IC.showRequestFromApi",
+ "IC.showRequestFromApiToImeReady",
+ "IC.pendingAnim",
+ "IMMS.applyImeVisibility",
+ "IMMS.showMySoftInput",
+ "IMMS.showSoftInput",
+ "IMS.showSoftInput",
+ "IMS.startInput",
+ "WMS.showImePostLayout"
+ };
+
+ /** IMF hide lifecycle methods to log in trace. */
+ private String[] mHideMethods = {
+ "IC.hideRequestFromIme",
+ "IC.hideRequestFromApi",
+ "IMMS.hideMySoftInput",
+ "IMMS.hideSoftInput",
+ "IMS.hideSoftInput",
+ "WMS.hideIme"
+ };
+
+ /**
+ * IMF methods to log in trace.
+ */
+ private TraceMarkParser mTraceMethods;
+
+ private boolean mIsTraceStarted;
+
+ /**
+ * Ime Session for {@link BaselineIme}.
+ */
+ private static class ImeSession implements AutoCloseable {
+
+ private static final long TIMEOUT = 2000;
+ private final ComponentName mImeName;
+ private Context mContext = getInstrumentation().getContext();
+
+ ImeSession(ComponentName ime) throws Exception {
+ mImeName = ime;
+ // using adb, enable and set Baseline IME.
+ executeShellCommand("ime reset");
+ executeShellCommand("ime enable " + ime.flattenToShortString());
+ executeShellCommand("ime set " + ime.flattenToShortString());
+ PollingCheck.check("Make sure that BaselineIme becomes available "
+ + getCurrentInputMethodId(), TIMEOUT,
+ () -> ime.equals(getCurrentInputMethodId()));
+ }
+
+ @Override
+ public void close() throws Exception {
+ executeShellCommand("ime reset");
+ PollingCheck.check("Make sure that Baseline IME becomes unavailable", TIMEOUT, () ->
+ mContext.getSystemService(InputMethodManager.class)
+ .getEnabledInputMethodList()
+ .stream()
+ .noneMatch(info -> mImeName.equals(info.getComponent())));
+ }
+
+ @Nullable
+ private ComponentName getCurrentInputMethodId() {
+ return ComponentName.unflattenFromString(
+ Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD));
+ }
+ }
+
+ /**
+ * A minimal baseline IME (that has a single static view) used to measure IMF latency.
+ */
+ public static class BaselineIme extends InputMethodService {
+
+ public static final int HEIGHT_DP = 100;
+
+ @Override
+ public View onCreateInputView() {
+ final ViewGroup view = new FrameLayout(this);
+ final View inner = new View(this);
+ final float density = getResources().getDisplayMetrics().density;
+ final int height = (int) (HEIGHT_DP * density);
+ view.setPadding(0, 0, 0, 0);
+ view.addView(inner, new FrameLayout.LayoutParams(MATCH_PARENT, height));
+ inner.setBackgroundColor(0xff01fe10); // green
+ return view;
+ }
+
+ static ComponentName getName(Context context) {
+ return new ComponentName(context, BaselineIme.class);
+ }
+ }
+
+ @Test
+ @ManualBenchmarkTest(
+ targetTestDurationNs = 10 * TIME_1_S_IN_NS,
+ statsReport = @StatsReport(
+ flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
+ | StatsReport.FLAG_MIN | StatsReport.FLAG_MAX
+ | StatsReport.FLAG_COEFFICIENT_VAR))
+ public void testShowIme() throws Throwable {
+ testShowOrHideIme(true /* show */);
+ }
+
+ @Test
+ @ManualBenchmarkTest(
+ targetTestDurationNs = 10 * TIME_1_S_IN_NS,
+ statsReport = @StatsReport(
+ flags = StatsReport.FLAG_ITERATION | StatsReport.FLAG_MEAN
+ | StatsReport.FLAG_MIN | StatsReport.FLAG_MAX
+ | StatsReport.FLAG_COEFFICIENT_VAR))
+ public void testHideIme() throws Throwable {
+ testShowOrHideIme(false /* show */);
+ }
+
+ private void testShowOrHideIme(final boolean show) throws Throwable {
+ mTraceMethods = new TraceMarkParser(buildArray(
+ mCommonMethods, show ? mShowMethods : mHideMethods));
+ final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ state.setCustomizedIterations(getProfilingIterations(), this);
+ long measuredTimeNs = 0;
+ try (ImeSession imeSession = new ImeSession(BaselineIme.getName(
+ getInstrumentation().getContext()))) {
+ final AtomicReference<CountDownLatch> latchStart = new AtomicReference<>();
+ final AtomicReference<CountDownLatch> latchEnd = new AtomicReference<>();
+ final Activity activity = getActivityWithFocus();
+
+ // call IME show/hide
+ final WindowInsetsController controller =
+ activity.getWindow().getDecorView().getWindowInsetsController();
+
+ while (state.keepRunning(measuredTimeNs)) {
+ setImeListener(activity, latchStart, latchEnd);
+ latchStart.set(new CountDownLatch(show ? 1 : 2));
+ latchEnd.set(new CountDownLatch(2));
+ // For measuring hide, lets show IME first.
+ if (!show) {
+ activity.runOnUiThread(() -> {
+ controller.show(WindowInsets.Type.ime());
+ });
+ PollingCheck.check("IME show animation should finish ", TIMEOUT_1_S_IN_MS,
+ () -> latchStart.get().getCount() == 1
+ && latchEnd.get().getCount() == 1);
+ }
+ if (!mIsTraceStarted && !state.isWarmingUp()) {
+ startAsyncAtrace();
+ mIsTraceStarted = true;
+ }
+
+ AtomicLong startTime = new AtomicLong();
+ activity.runOnUiThread(() -> {
+ startTime.set(SystemClock.elapsedRealtimeNanos());
+ if (show) {
+ controller.show(WindowInsets.Type.ime());
+ } else {
+ controller.hide(WindowInsets.Type.ime());
+ }
+ });
+
+ measuredTimeNs = waitForAnimationStart(latchStart, startTime);
+
+ // hide IME before next iteration.
+ if (show) {
+ activity.runOnUiThread(() -> controller.hide(WindowInsets.Type.ime()));
+ try {
+ latchEnd.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS);
+ if (latchEnd.get().getCount() != 0) {
+ Assert.fail("IME hide animation should finish.");
+ }
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ } finally {
+ if (mIsTraceStarted) {
+ stopAsyncAtrace();
+ }
+ }
+ mActivityRule.finishActivity();
+
+ addResultToState(state);
+ }
+
+ private long waitForAnimationStart(
+ AtomicReference<CountDownLatch> latchStart, AtomicLong startTime) {
+ try {
+ latchStart.get().await(TIMEOUT_1_S_IN_MS * 5, TimeUnit.MILLISECONDS);
+ if (latchStart.get().getCount() != 0) {
+ Assert.fail("IME animation should start " + latchStart.get().getCount());
+ }
+ } catch (InterruptedException e) { }
+
+ return SystemClock.elapsedRealtimeNanos() - startTime.get();
+ }
+
+ private void addResultToState(ManualBenchmarkState state) {
+ mTraceMethods.forAllSlices((key, slices) -> {
+ for (TraceMarkSlice slice : slices) {
+ state.addExtraResult(key, (long) (slice.getDurationInSeconds() * NANOS_PER_S));
+ }
+ });
+ Log.i(TAG, String.valueOf(mTraceMethods));
+ }
+
+ private Activity getActivityWithFocus() throws Exception {
+ final Activity activity = mActivityRule.launchActivity();
+ PollingCheck.check("Activity onResume()", TIMEOUT_1_S_IN_MS,
+ () -> activity.isResumed());
+
+ View editor = activity.findViewById(ID_EDITOR);
+ editor.requestFocus();
+
+ // wait till editor is focused so we don't count activity/view latency.
+ PollingCheck.check("Editor is focused", TIMEOUT_1_S_IN_MS,
+ () -> editor.isFocused());
+ getInstrumentation().waitForIdleSync();
+
+ return activity;
+ }
+
+ private void setImeListener(Activity activity,
+ @NonNull AtomicReference<CountDownLatch> latchStart,
+ @Nullable AtomicReference<CountDownLatch> latchEnd) {
+ // set IME animation listener
+ activity.getWindow().getDecorView().setWindowInsetsAnimationCallback(
+ new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
+ @NonNull
+ @Override
+ public WindowInsetsAnimation.Bounds onStart(
+ @NonNull WindowInsetsAnimation animation,
+ @NonNull WindowInsetsAnimation.Bounds bounds) {
+ latchStart.get().countDown();
+ return super.onStart(animation, bounds);
+ }
+
+ @NonNull
+ @Override
+ public WindowInsets onProgress(@NonNull WindowInsets insets,
+ @NonNull List<WindowInsetsAnimation> runningAnimations) {
+ return insets;
+ }
+
+ @Override
+ public void onEnd(@NonNull WindowInsetsAnimation animation) {
+ super.onEnd(animation);
+ if (latchEnd != null) {
+ latchEnd.get().countDown();
+ }
+ }
+ });
+ }
+
+ private void startAsyncAtrace() throws IOException {
+ mIsTraceStarted = true;
+ // IMF uses 'wm' component for trace in InputMethodService, InputMethodManagerService,
+ // WindowManagerService and 'view' for client window (InsetsController).
+ // TODO(b/167947940): Consider a separate input_method atrace
+ UI_AUTOMATION.executeShellCommand("atrace -b 32768 --async_start wm view");
+ // Avoid atrace isn't ready immediately.
+ SystemClock.sleep(TimeUnit.NANOSECONDS.toMillis(TIME_1_S_IN_NS));
+ }
+
+ private void stopAsyncAtrace() {
+ if (!mIsTraceStarted) {
+ return;
+ }
+ final ParcelFileDescriptor pfd = UI_AUTOMATION.executeShellCommand("atrace --async_stop");
+ mIsTraceStarted = false;
+ final InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ mTraceMethods.visit(line);
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to read the result of stopped atrace", e);
+ }
+ }
+
+ @Override
+ public void onStart(int iteration) {
+ // Do not capture trace when profiling because the result will be much slower.
+ stopAsyncAtrace();
+ }
+
+ @Override
+ public void onFinished(int iteration) {
+ // do nothing.
+ }
+}
diff --git a/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java
new file mode 100644
index 000000000000..1a861d7ba87b
--- /dev/null
+++ b/apct-tests/perftests/inputmethod/src/android/inputmethod/ImePerfTestBase.java
@@ -0,0 +1,165 @@
+/*
+ * 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.inputmethod;
+
+import static android.perftests.utils.PerfTestActivity.INTENT_EXTRA_ADD_EDIT_TEXT;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.app.KeyguardManager;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.Intent;
+import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
+import android.perftests.utils.PerfTestActivity;
+
+
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.BeforeClass;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Objects;
+import java.util.function.Consumer;
+
+public class ImePerfTestBase {
+ static final UiAutomation UI_AUTOMATION = getInstrumentation().getUiAutomation();
+ static final long NANOS_PER_S = 1000L * 1000 * 1000;
+ static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S;
+ static final long TIMEOUT_1_S_IN_MS = 1 * 1000L;
+
+ @BeforeClass
+ public static void setUpOnce() {
+ final Context context = getInstrumentation().getContext();
+
+ if (!context.getSystemService(PowerManager.class).isInteractive()
+ || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) {
+ executeShellCommand("input keyevent KEYCODE_WAKEUP");
+ executeShellCommand("wm dismiss-keyguard");
+ }
+ context.startActivity(new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ }
+
+ /**
+ * Executes shell command with reading the output. It may also used to block until the current
+ * command is completed.
+ */
+ static ByteArrayOutputStream executeShellCommand(String command) {
+ final ParcelFileDescriptor pfd = UI_AUTOMATION.executeShellCommand(command);
+ final byte[] buf = new byte[512];
+ final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ int bytesRead;
+ try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+ while ((bytesRead = fis.read(buf)) != -1) {
+ bytes.write(buf, 0, bytesRead);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return bytes;
+ }
+
+ /** Returns how many iterations should run with method tracing. */
+ static int getProfilingIterations() {
+ return ImePerfRunPrecondition.sProfilingIterations;
+ }
+
+ static void runWithShellPermissionIdentity(Runnable runnable) {
+ UI_AUTOMATION.adoptShellPermissionIdentity();
+ try {
+ runnable.run();
+ } finally {
+ UI_AUTOMATION.dropShellPermissionIdentity();
+ }
+ }
+
+ static class SettingsSession<T> implements AutoCloseable {
+ private final Consumer<T> mSetter;
+ private final T mOriginalValue;
+ private boolean mChanged;
+
+ SettingsSession(T originalValue, Consumer<T> setter) {
+ mOriginalValue = originalValue;
+ mSetter = setter;
+ }
+
+ void set(T value) {
+ if (Objects.equals(value, mOriginalValue)) {
+ mChanged = false;
+ return;
+ }
+ mSetter.accept(value);
+ mChanged = true;
+ }
+
+ @Override
+ public void close() {
+ if (mChanged) {
+ mSetter.accept(mOriginalValue);
+ }
+ }
+ }
+
+ /**
+ * Provides an activity that keeps screen on and is able to wait for a stable lifecycle stage.
+ */
+ static class PerfTestActivityRule extends ActivityTestRule<PerfTestActivity> {
+ private final Intent mStartIntent =
+ new Intent(getInstrumentation().getTargetContext(), PerfTestActivity.class);
+
+ PerfTestActivityRule() {
+ this(false /* launchActivity */);
+ }
+
+ PerfTestActivityRule(boolean launchActivity) {
+ super(PerfTestActivity.class, false /* initialTouchMode */, launchActivity);
+ }
+
+ @Override
+ protected Intent getActivityIntent() {
+ return mStartIntent;
+ }
+
+ @Override
+ public PerfTestActivity launchActivity(Intent intent) {
+ intent.putExtra(INTENT_EXTRA_ADD_EDIT_TEXT, true);
+ return super.launchActivity(intent);
+ }
+
+ PerfTestActivity launchActivity() {
+ return launchActivity(mStartIntent);
+ }
+ }
+
+ static String[] buildArray(String[]... arrays) {
+ int length = 0;
+ for (String[] array : arrays) {
+ length += array.length;
+ }
+ String[] newArray = new String[length];
+ int offset = 0;
+ for (String[] array : arrays) {
+ System.arraycopy(array, 0, newArray, offset, array.length);
+ offset += array.length;
+ }
+ return newArray;
+ }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java
index e934feb01a84..f3bea17b2f0d 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfTestActivity.java
@@ -21,6 +21,8 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
/**
* A simple activity used for testing, e.g. performance of activity switching, or as a base
@@ -28,6 +30,8 @@ import android.view.WindowManager;
*/
public class PerfTestActivity extends Activity {
public static final String INTENT_EXTRA_KEEP_SCREEN_ON = "keep_screen_on";
+ public static final String INTENT_EXTRA_ADD_EDIT_TEXT = "add_edit_text";
+ public static final int ID_EDITOR = 3252356;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -35,6 +39,15 @@ public class PerfTestActivity extends Activity {
if (getIntent().getBooleanExtra(INTENT_EXTRA_KEEP_SCREEN_ON, false)) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
+ if (getIntent().getBooleanExtra(INTENT_EXTRA_ADD_EDIT_TEXT, false)) {
+ final LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ final EditText editText = new EditText(this);
+ editText.setId(ID_EDITOR);
+ layout.addView(editText);
+ setContentView(layout);
+ }
}
public static Intent createLaunchIntent(Context context) {
diff --git a/apex/Android.bp b/apex/Android.bp
index c5b4901a9b79..0a535a8fe9b9 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -112,6 +112,8 @@ java_defaults {
],
stubs_source_visibility: ["//visibility:private"],
+ defaults_visibility: ["//visibility:private"],
+
// Collates API usages from each module for further analysis.
plugins: ["java_api_finder"],
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index 62c90dfa8a86..e251ff00a47d 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.net.Network;
+import android.net.NetworkRequest;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
@@ -242,8 +243,9 @@ public class JobParameters implements Parcelable {
*
* @return the network that should be used to perform any network requests
* for this job, or {@code null} if this job didn't set any required
- * network type.
+ * network type or if the job executed when there was no available network to use.
* @see JobInfo.Builder#setRequiredNetworkType(int)
+ * @see JobInfo.Builder#setRequiredNetwork(NetworkRequest)
*/
public @Nullable Network getNetwork() {
return network;
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
index bf5781beb52b..361325dae7fd 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
@@ -169,6 +169,7 @@ public abstract class JobScheduler {
* @param tag Debugging tag for dumps associated with this job (instead of the service class)
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public abstract @Result int scheduleAsPackage(@NonNull JobInfo job, @NonNull String packageName,
@@ -211,6 +212,7 @@ public abstract class JobScheduler {
* Returns a list of all currently-executing jobs.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract List<JobInfo> getStartedJobs();
/**
@@ -220,5 +222,6 @@ public abstract class JobScheduler {
* <p class="note">This is a slow operation, so it should be called sparingly.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract List<JobSnapshot> getAllJobSnapshots();
} \ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 81f22fe36ea1..9835e18d0bfd 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -27,6 +27,7 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -76,6 +77,7 @@ import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
@@ -273,6 +275,7 @@ public class DeviceIdleController extends SystemService
private ActivityManagerInternal mLocalActivityManager;
private ActivityTaskManagerInternal mLocalActivityTaskManager;
private DeviceIdleInternal mLocalService;
+ private PackageManagerInternal mPackageManagerInternal;
private PowerManagerInternal mLocalPowerManager;
private PowerManager mPowerManager;
private INetworkPolicyManager mNetworkPolicyManager;
@@ -1736,27 +1739,33 @@ public class DeviceIdleController extends SystemService
}
public String[] getRemovedSystemPowerWhitelistApps() {
- return getRemovedSystemPowerWhitelistAppsInternal();
+ return getRemovedSystemPowerWhitelistAppsInternal(
+ Binder.getCallingUid(), UserHandle.getCallingUserId());
}
@Override public String[] getSystemPowerWhitelistExceptIdle() {
- return getSystemPowerWhitelistExceptIdleInternal();
+ return getSystemPowerWhitelistExceptIdleInternal(
+ Binder.getCallingUid(), UserHandle.getCallingUserId());
}
@Override public String[] getSystemPowerWhitelist() {
- return getSystemPowerWhitelistInternal();
+ return getSystemPowerWhitelistInternal(
+ Binder.getCallingUid(), UserHandle.getCallingUserId());
}
@Override public String[] getUserPowerWhitelist() {
- return getUserPowerWhitelistInternal();
+ return getUserPowerWhitelistInternal(
+ Binder.getCallingUid(), UserHandle.getCallingUserId());
}
@Override public String[] getFullPowerWhitelistExceptIdle() {
- return getFullPowerWhitelistExceptIdleInternal();
+ return getFullPowerWhitelistExceptIdleInternal(
+ Binder.getCallingUid(), UserHandle.getCallingUserId());
}
@Override public String[] getFullPowerWhitelist() {
- return getFullPowerWhitelistInternal();
+ return getFullPowerWhitelistInternal(
+ Binder.getCallingUid(), UserHandle.getCallingUserId());
}
@Override public int[] getAppIdWhitelistExceptIdle() {
@@ -1776,10 +1785,18 @@ public class DeviceIdleController extends SystemService
}
@Override public boolean isPowerSaveWhitelistExceptIdleApp(String name) {
+ if (mPackageManagerInternal
+ .filterAppAccess(name, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+ return false;
+ }
return isPowerSaveWhitelistExceptIdleAppInternal(name);
}
@Override public boolean isPowerSaveWhitelistApp(String name) {
+ if (mPackageManagerInternal
+ .filterAppAccess(name, Binder.getCallingUid(), UserHandle.getCallingUserId())) {
+ return false;
+ }
return isPowerSaveWhitelistAppInternal(name);
}
@@ -2159,6 +2176,7 @@ public class DeviceIdleController extends SystemService
mBatteryStats = BatteryStatsService.getService();
mLocalActivityManager = getLocalService(ActivityManagerInternal.class);
mLocalActivityTaskManager = getLocalService(ActivityTaskManagerInternal.class);
+ mPackageManagerInternal = getLocalService(PackageManagerInternal.class);
mLocalPowerManager = getLocalService(PowerManagerInternal.class);
mPowerManager = mInjector.getPowerManager();
mActiveIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -2466,54 +2484,68 @@ public class DeviceIdleController extends SystemService
}
}
- public String[] getSystemPowerWhitelistExceptIdleInternal() {
+ private String[] getSystemPowerWhitelistExceptIdleInternal(final int callingUid,
+ final int callingUserId) {
+ final String[] apps;
synchronized (this) {
int size = mPowerSaveWhitelistAppsExceptIdle.size();
- String[] apps = new String[size];
+ apps = new String[size];
for (int i = 0; i < size; i++) {
apps[i] = mPowerSaveWhitelistAppsExceptIdle.keyAt(i);
}
- return apps;
}
+ return ArrayUtils.filter(apps, String[]::new,
+ (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
}
- public String[] getSystemPowerWhitelistInternal() {
+ private String[] getSystemPowerWhitelistInternal(final int callingUid,
+ final int callingUserId) {
+ final String[] apps;
synchronized (this) {
int size = mPowerSaveWhitelistApps.size();
- String[] apps = new String[size];
+ apps = new String[size];
for (int i = 0; i < size; i++) {
apps[i] = mPowerSaveWhitelistApps.keyAt(i);
}
- return apps;
}
+ return ArrayUtils.filter(apps, String[]::new,
+ (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
}
- public String[] getRemovedSystemPowerWhitelistAppsInternal() {
+ private String[] getRemovedSystemPowerWhitelistAppsInternal(final int callingUid,
+ final int callingUserId) {
+ final String[] apps;
synchronized (this) {
int size = mRemovedFromSystemWhitelistApps.size();
- final String[] apps = new String[size];
+ apps = new String[size];
for (int i = 0; i < size; i++) {
apps[i] = mRemovedFromSystemWhitelistApps.keyAt(i);
}
- return apps;
}
+ return ArrayUtils.filter(apps, String[]::new,
+ (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
}
- public String[] getUserPowerWhitelistInternal() {
+ private String[] getUserPowerWhitelistInternal(final int callingUid, final int callingUserId) {
+ final String[] apps;
synchronized (this) {
int size = mPowerSaveWhitelistUserApps.size();
- String[] apps = new String[size];
+ apps = new String[size];
for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) {
apps[i] = mPowerSaveWhitelistUserApps.keyAt(i);
}
- return apps;
}
+ return ArrayUtils.filter(apps, String[]::new,
+ (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
}
- public String[] getFullPowerWhitelistExceptIdleInternal() {
+ private String[] getFullPowerWhitelistExceptIdleInternal(final int callingUid,
+ final int callingUserId) {
+ final String[] apps;
synchronized (this) {
- int size = mPowerSaveWhitelistAppsExceptIdle.size() + mPowerSaveWhitelistUserApps.size();
- String[] apps = new String[size];
+ int size =
+ mPowerSaveWhitelistAppsExceptIdle.size() + mPowerSaveWhitelistUserApps.size();
+ apps = new String[size];
int cur = 0;
for (int i = 0; i < mPowerSaveWhitelistAppsExceptIdle.size(); i++) {
apps[cur] = mPowerSaveWhitelistAppsExceptIdle.keyAt(i);
@@ -2523,14 +2555,16 @@ public class DeviceIdleController extends SystemService
apps[cur] = mPowerSaveWhitelistUserApps.keyAt(i);
cur++;
}
- return apps;
}
+ return ArrayUtils.filter(apps, String[]::new,
+ (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
}
- public String[] getFullPowerWhitelistInternal() {
+ private String[] getFullPowerWhitelistInternal(final int callingUid, final int callingUserId) {
+ final String[] apps;
synchronized (this) {
int size = mPowerSaveWhitelistApps.size() + mPowerSaveWhitelistUserApps.size();
- String[] apps = new String[size];
+ apps = new String[size];
int cur = 0;
for (int i = 0; i < mPowerSaveWhitelistApps.size(); i++) {
apps[cur] = mPowerSaveWhitelistApps.keyAt(i);
@@ -2540,8 +2574,9 @@ public class DeviceIdleController extends SystemService
apps[cur] = mPowerSaveWhitelistUserApps.keyAt(i);
cur++;
}
- return apps;
}
+ return ArrayUtils.filter(apps, String[]::new,
+ (pkg) -> !mPackageManagerInternal.filterAppAccess(pkg, callingUid, callingUserId));
}
public boolean isPowerSaveWhitelistExceptIdleAppInternal(String packageName) {
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index c8a04d674739..d4ea7af06ed1 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -268,6 +268,7 @@ public class AlarmManagerService extends SystemService {
*/
Bundle mIdleOptions;
+ // TODO(b/172085676): Move inside alarm store.
private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser =
new SparseArray<>();
private final SparseArray<AlarmManager.AlarmClockInfo> mTmpSparseAlarmClockArray =
@@ -276,6 +277,9 @@ public class AlarmManagerService extends SystemService {
new SparseBooleanArray();
private boolean mNextAlarmClockMayChange;
+ @GuardedBy("mLock")
+ private final Runnable mAlarmClockUpdater = () -> mNextAlarmClockMayChange = true;
+
// May only use on mHandler's thread, locking not required.
private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
new SparseArray<>();
@@ -410,6 +414,9 @@ public class AlarmManagerService extends SystemService {
private static final String KEY_APP_STANDBY_RESTRICTED_WINDOW =
"app_standby_restricted_window";
+ @VisibleForTesting
+ static final String KEY_LAZY_BATCHING = "lazy_batching";
+
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS;
@@ -432,6 +439,8 @@ public class AlarmManagerService extends SystemService {
private static final int DEFAULT_APP_STANDBY_RESTRICTED_QUOTA = 1;
private static final long DEFAULT_APP_STANDBY_RESTRICTED_WINDOW = MILLIS_IN_DAY;
+ private static final boolean DEFAULT_LAZY_BATCHING = true;
+
// Minimum futurity of a new alarm
public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
@@ -460,6 +469,8 @@ public class AlarmManagerService extends SystemService {
public int APP_STANDBY_RESTRICTED_QUOTA = DEFAULT_APP_STANDBY_RESTRICTED_QUOTA;
public long APP_STANDBY_RESTRICTED_WINDOW = DEFAULT_APP_STANDBY_RESTRICTED_WINDOW;
+ public boolean LAZY_BATCHING = DEFAULT_LAZY_BATCHING;
+
private long mLastAllowWhileIdleWhitelistDuration = -1;
Constants() {
@@ -538,6 +549,14 @@ public class AlarmManagerService extends SystemService {
case KEY_APP_STANDBY_RESTRICTED_WINDOW:
updateStandbyWindowsLocked();
break;
+ case KEY_LAZY_BATCHING:
+ final boolean oldLazyBatching = LAZY_BATCHING;
+ LAZY_BATCHING = properties.getBoolean(
+ KEY_LAZY_BATCHING, DEFAULT_LAZY_BATCHING);
+ if (oldLazyBatching != LAZY_BATCHING) {
+ migrateAlarmsToNewStoreLocked();
+ }
+ break;
default:
if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {
// The quotas need to be updated in order, so we can't just rely
@@ -551,6 +570,15 @@ public class AlarmManagerService extends SystemService {
}
}
+ private void migrateAlarmsToNewStoreLocked() {
+ final AlarmStore newStore = LAZY_BATCHING ? new LazyAlarmStore()
+ : new BatchingAlarmStore();
+ final ArrayList<Alarm> allAlarms = mAlarmStore.remove((unused) -> true);
+ newStore.addAll(allAlarms);
+ mAlarmStore = newStore;
+ mAlarmStore.setAlarmClockRemovalListener(mAlarmClockUpdater);
+ }
+
private void updateStandbyQuotasLocked() {
// The bucket quotas need to be read as an atomic unit but the properties passed to
// onPropertiesChanged may only have one key populated at a time.
@@ -659,6 +687,9 @@ public class AlarmManagerService extends SystemService {
TimeUtils.formatDuration(APP_STANDBY_RESTRICTED_WINDOW, pw);
pw.println();
+ pw.print(KEY_LAZY_BATCHING, LAZY_BATCHING);
+ pw.println();
+
pw.decreaseIndent();
}
@@ -770,7 +801,7 @@ public class AlarmManagerService extends SystemService {
// minimum recurrence period or alarm futurity for us to be able to fuzz it
static final long MIN_FUZZABLE_INTERVAL = 10000;
@GuardedBy("mLock")
- final AlarmStore mAlarmStore;
+ AlarmStore mAlarmStore;
// set to non-null if in idle mode; while in this mode, any alarms we don't want
// to run during this time are rescehduled to go off after this alarm.
@@ -781,7 +812,6 @@ public class AlarmManagerService extends SystemService {
AlarmManagerService(Context context, Injector injector) {
super(context);
mInjector = injector;
- mAlarmStore = new BatchingAlarmStore(() -> mNextAlarmClockMayChange = true);
}
public AlarmManagerService(Context context) {
@@ -1219,6 +1249,11 @@ public class AlarmManagerService extends SystemService {
synchronized (mLock) {
mHandler = new AlarmHandler();
mConstants = new Constants();
+
+ mAlarmStore = mConstants.LAZY_BATCHING ? new LazyAlarmStore()
+ : new BatchingAlarmStore();
+ mAlarmStore.setAlarmClockRemovalListener(mAlarmClockUpdater);
+
mAppWakeupHistory = new AppWakeupHistory(Constants.DEFAULT_APP_STANDBY_WINDOW);
mNextWakeup = mNextNonWakeup = 0;
@@ -3055,12 +3090,13 @@ public class AlarmManagerService extends SystemService {
static final void dumpAlarmList(IndentingPrintWriter ipw, ArrayList<Alarm> list,
long nowELAPSED, SimpleDateFormat sdf) {
- for (int i = list.size() - 1; i >= 0; i--) {
+ final int n = list.size();
+ for (int i = n - 1; i >= 0; i--) {
final Alarm a = list.get(i);
final String label = Alarm.typeToString(a.type);
ipw.print(label);
ipw.print(" #");
- ipw.print(i);
+ ipw.print(n - i);
ipw.print(": ");
ipw.println(a);
ipw.increaseIndent();
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
index 7a846b9b82db..0e442d09d5a5 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmStore.java
@@ -40,6 +40,13 @@ public interface AlarmStore {
void add(Alarm a);
/**
+ * Adds all the given alarms to this store.
+ *
+ * @param alarms The alarms to add.
+ */
+ void addAll(ArrayList<Alarm> alarms);
+
+ /**
* Removes alarms that pass the given predicate.
*
* @param whichAlarms The predicate describing the alarms to remove.
@@ -48,11 +55,17 @@ public interface AlarmStore {
ArrayList<Alarm> remove(Predicate<Alarm> whichAlarms);
/**
+ * Set a listener to be invoked whenever an alarm clock is removed by a call to
+ * {@link #remove(Predicate) remove} from this store.
+ */
+ void setAlarmClockRemovalListener(Runnable listener);
+
+ /**
* Gets the earliest alarm with the flag {@link android.app.AlarmManager#FLAG_WAKE_FROM_IDLE}
* based on {@link Alarm#getWhenElapsed()}.
*
* @return An alarm object matching the description above or {@code null} if no such alarm was
- * found.
+ * found.
*/
Alarm getNextWakeFromIdleAlarm();
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
index cbfe80bdce24..e7edfb7b56b9 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/BatchingAlarmStore.java
@@ -41,45 +41,22 @@ import java.util.function.Predicate;
*/
public class BatchingAlarmStore implements AlarmStore {
- private ArrayList<Batch> mAlarmBatches = new ArrayList<>();
+ private final ArrayList<Batch> mAlarmBatches = new ArrayList<>();
private int mSize;
- private AlarmClockRemovalListener mAlarmClockRemovalListener;
+ private Runnable mOnAlarmClockRemoved;
interface Stats {
int REBATCH_ALL_ALARMS = 0;
}
- final StatLogger mStatLogger = new StatLogger("Alarm store stats", new String[]{
+ final StatLogger mStatLogger = new StatLogger("BatchingAlarmStore stats", new String[]{
"REBATCH_ALL_ALARMS",
});
- private static final Comparator<Batch> sBatchOrder = (b1, b2) -> {
- long when1 = b1.mStart;
- long when2 = b2.mStart;
- if (when1 > when2) {
- return 1;
- }
- if (when1 < when2) {
- return -1;
- }
- return 0;
- };
+ private static final Comparator<Batch> sBatchOrder = Comparator.comparingLong(b -> b.mStart);
- private static final Comparator<Alarm> sIncreasingTimeOrder = (a1, a2) -> {
- long when1 = a1.getWhenElapsed();
- long when2 = a2.getWhenElapsed();
- if (when1 > when2) {
- return 1;
- }
- if (when1 < when2) {
- return -1;
- }
- return 0;
- };
-
- BatchingAlarmStore(AlarmClockRemovalListener listener) {
- mAlarmClockRemovalListener = listener;
- }
+ private static final Comparator<Alarm> sIncreasingTimeOrder = Comparator.comparingLong(
+ Alarm::getWhenElapsed);
@Override
public void add(Alarm a) {
@@ -88,6 +65,16 @@ public class BatchingAlarmStore implements AlarmStore {
}
@Override
+ public void addAll(ArrayList<Alarm> alarms) {
+ if (alarms == null) {
+ return;
+ }
+ for (final Alarm a : alarms) {
+ add(a);
+ }
+ }
+
+ @Override
public ArrayList<Alarm> remove(Predicate<Alarm> whichAlarms) {
final ArrayList<Alarm> removed = new ArrayList<>();
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
@@ -106,6 +93,11 @@ public class BatchingAlarmStore implements AlarmStore {
}
@Override
+ public void setAlarmClockRemovalListener(Runnable listener) {
+ mOnAlarmClockRemoved = listener;
+ }
+
+ @Override
public Alarm getNextWakeFromIdleAlarm() {
for (final Batch batch : mAlarmBatches) {
if ((batch.mFlags & AlarmManager.FLAG_WAKE_FROM_IDLE) == 0) {
@@ -317,8 +309,8 @@ public class BatchingAlarmStore implements AlarmStore {
Alarm alarm = mAlarms.get(i);
if (predicate.test(alarm)) {
removed.add(mAlarms.remove(i));
- if (alarm.alarmClock != null && mAlarmClockRemovalListener != null) {
- mAlarmClockRemovalListener.onRemoved();
+ if (alarm.alarmClock != null && mOnAlarmClockRemoved != null) {
+ mOnAlarmClockRemoved.run();
}
if (isTimeTickAlarm(alarm)) {
// This code path is not invoked when delivering alarms, only when removing
@@ -388,9 +380,4 @@ public class BatchingAlarmStore implements AlarmStore {
proto.end(token);
}
}
-
- @FunctionalInterface
- interface AlarmClockRemovalListener {
- void onRemoved();
- }
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
new file mode 100644
index 000000000000..8ca14463a3b5
--- /dev/null
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/LazyAlarmStore.java
@@ -0,0 +1,217 @@
+/*
+ * 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.alarm;
+
+import static com.android.server.alarm.AlarmManagerService.TAG;
+import static com.android.server.alarm.AlarmManagerService.dumpAlarmList;
+import static com.android.server.alarm.AlarmManagerService.isTimeTickAlarm;
+
+import android.app.AlarmManager;
+import android.util.IndentingPrintWriter;
+import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.StatLogger;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.function.Predicate;
+
+/**
+ * Lazy implementation of an alarm store.
+ * This keeps the alarms in a sorted list, and only batches them at the time of delivery.
+ */
+public class LazyAlarmStore implements AlarmStore {
+
+ private final ArrayList<Alarm> mAlarms = new ArrayList<>();
+ private Runnable mOnAlarmClockRemoved;
+
+ interface Stats {
+ int GET_NEXT_DELIVERY_TIME = 0;
+ int GET_NEXT_WAKEUP_DELIVERY_TIME = 1;
+ }
+
+ final StatLogger mStatLogger = new StatLogger("LazyAlarmStore stats", new String[]{
+ "GET_NEXT_DELIVERY_TIME",
+ "GET_NEXT_WAKEUP_DELIVERY_TIME",
+ });
+
+ // Decreasing time order because it is more efficient to remove from the tail of an array list.
+ private static final Comparator<Alarm> sDecreasingTimeOrder = Comparator.comparingLong(
+ Alarm::getWhenElapsed).reversed();
+
+ @Override
+ public void add(Alarm a) {
+ int index = Collections.binarySearch(mAlarms, a, sDecreasingTimeOrder);
+ if (index < 0) {
+ index = 0 - index - 1;
+ }
+ mAlarms.add(index, a);
+ }
+
+ @Override
+ public void addAll(ArrayList<Alarm> alarms) {
+ if (alarms == null) {
+ return;
+ }
+ mAlarms.addAll(alarms);
+ Collections.sort(alarms, sDecreasingTimeOrder);
+ }
+
+ @Override
+ public ArrayList<Alarm> remove(Predicate<Alarm> whichAlarms) {
+ final ArrayList<Alarm> removedAlarms = new ArrayList<>();
+ for (int i = mAlarms.size() - 1; i >= 0; i--) {
+ if (whichAlarms.test(mAlarms.get(i))) {
+ final Alarm removed = mAlarms.remove(i);
+ if (removed.alarmClock != null && mOnAlarmClockRemoved != null) {
+ mOnAlarmClockRemoved.run();
+ }
+ if (isTimeTickAlarm(removed)) {
+ // This code path is not invoked when delivering alarms, only when removing
+ // alarms due to the caller cancelling it or getting uninstalled, etc.
+ Slog.wtf(TAG, "Removed TIME_TICK alarm");
+ }
+ removedAlarms.add(removed);
+ }
+ }
+ return removedAlarms;
+ }
+
+ @Override
+ public void setAlarmClockRemovalListener(Runnable listener) {
+ mOnAlarmClockRemoved = listener;
+ }
+
+ @Override
+ public Alarm getNextWakeFromIdleAlarm() {
+ for (int i = mAlarms.size() - 1; i >= 0; i--) {
+ final Alarm alarm = mAlarms.get(i);
+ if ((alarm.flags & AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
+ return alarm;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return mAlarms.size();
+ }
+
+ @Override
+ public long getNextWakeupDeliveryTime() {
+ final long start = mStatLogger.getTime();
+ long nextWakeup = 0;
+ for (int i = mAlarms.size() - 1; i >= 0; i--) {
+ final Alarm a = mAlarms.get(i);
+ if (!a.wakeup) {
+ continue;
+ }
+ if (nextWakeup == 0) {
+ nextWakeup = a.getMaxWhenElapsed();
+ } else {
+ if (a.getWhenElapsed() > nextWakeup) {
+ break;
+ }
+ nextWakeup = Math.min(nextWakeup, a.getMaxWhenElapsed());
+ }
+ }
+ mStatLogger.logDurationStat(Stats.GET_NEXT_WAKEUP_DELIVERY_TIME, start);
+ return nextWakeup;
+ }
+
+ @Override
+ public long getNextDeliveryTime() {
+ final long start = mStatLogger.getTime();
+ final int n = mAlarms.size();
+ if (n == 0) {
+ return 0;
+ }
+ long nextDelivery = mAlarms.get(n - 1).getMaxWhenElapsed();
+ for (int i = n - 2; i >= 0; i--) {
+ final Alarm a = mAlarms.get(i);
+ if (a.getWhenElapsed() > nextDelivery) {
+ break;
+ }
+ nextDelivery = Math.min(nextDelivery, a.getMaxWhenElapsed());
+ }
+ mStatLogger.logDurationStat(Stats.GET_NEXT_DELIVERY_TIME, start);
+ return nextDelivery;
+ }
+
+ @Override
+ public ArrayList<Alarm> removePendingAlarms(long nowElapsed) {
+ final ArrayList<Alarm> pending = new ArrayList<>();
+ final ArrayList<Alarm> standAlones = new ArrayList<>();
+
+ for (int i = mAlarms.size() - 1; i >= 0; i--) {
+ final Alarm alarm = mAlarms.get(i);
+ if (alarm.getWhenElapsed() > nowElapsed) {
+ break;
+ }
+ pending.add(alarm);
+ if ((alarm.flags & AlarmManager.FLAG_STANDALONE) != 0) {
+ standAlones.add(alarm);
+ }
+ }
+ if (!standAlones.isEmpty()) {
+ // If there are deliverable standalone alarms, others must not go out yet.
+ mAlarms.removeAll(standAlones);
+ return standAlones;
+ }
+ mAlarms.removeAll(pending);
+ return pending;
+ }
+
+ @Override
+ public boolean updateAlarmDeliveries(AlarmDeliveryCalculator deliveryCalculator) {
+ boolean changed = false;
+ for (final Alarm alarm : mAlarms) {
+ changed |= deliveryCalculator.updateAlarmDelivery(alarm);
+ }
+ if (changed) {
+ Collections.sort(mAlarms, sDecreasingTimeOrder);
+ }
+ return changed;
+ }
+
+ @Override
+ public ArrayList<Alarm> asList() {
+ final ArrayList<Alarm> copy = new ArrayList<>(mAlarms);
+ Collections.reverse(copy);
+ return copy;
+ }
+
+ @Override
+ public void dump(IndentingPrintWriter ipw, long nowElapsed, SimpleDateFormat sdf) {
+ ipw.println(mAlarms.size() + " pending alarms: ");
+ ipw.increaseIndent();
+ dumpAlarmList(ipw, mAlarms, nowElapsed, sdf);
+ ipw.decreaseIndent();
+ mStatLogger.dump(ipw);
+ }
+
+ @Override
+ public void dumpProto(ProtoOutputStream pos, long nowElapsed) {
+ for (final Alarm a : mAlarms) {
+ a.dumpDebug(pos, AlarmManagerServiceDumpProto.PENDING_ALARMS, nowElapsed);
+ }
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 34e82b0ce45e..ca002ec992e2 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -3139,7 +3139,9 @@ public class JobSchedulerService extends com.android.server.SystemService
}
void resetExecutionQuota(@NonNull String pkgName, int userId) {
- mQuotaController.clearAppStats(userId, pkgName);
+ synchronized (mLock) {
+ mQuotaController.clearAppStatsLocked(userId, pkgName);
+ }
}
void resetScheduleQuota() {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index b7ace70f0cd4..7d7de3be8249 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -576,7 +576,7 @@ public final class QuotaController extends StateController {
Slog.wtf(TAG, "Told app removed but given null package name.");
return;
}
- clearAppStats(UserHandle.getUserId(uid), packageName);
+ clearAppStatsLocked(UserHandle.getUserId(uid), packageName);
mForegroundUids.delete(uid);
mUidToPackageCache.remove(uid);
}
@@ -592,7 +592,7 @@ public final class QuotaController extends StateController {
}
/** Drop all historical stats and stop tracking any active sessions for the specified app. */
- public void clearAppStats(int userId, @NonNull String packageName) {
+ public void clearAppStatsLocked(int userId, @NonNull String packageName) {
mTrackedJobs.delete(userId, packageName);
Timer timer = mPkgTimers.get(userId, packageName);
if (timer != null) {
@@ -1008,7 +1008,7 @@ public final class QuotaController extends StateController {
}
@VisibleForTesting
- void incrementJobCount(final int userId, @NonNull final String packageName, int count) {
+ void incrementJobCountLocked(final int userId, @NonNull final String packageName, int count) {
final long now = sElapsedRealtimeClock.millis();
ExecutionStats[] appStats = mExecutionStatsCache.get(userId, packageName);
if (appStats == null) {
@@ -1029,7 +1029,8 @@ public final class QuotaController extends StateController {
}
}
- private void incrementTimingSessionCount(final int userId, @NonNull final String packageName) {
+ private void incrementTimingSessionCountLocked(final int userId,
+ @NonNull final String packageName) {
final long now = sElapsedRealtimeClock.millis();
ExecutionStats[] appStats = mExecutionStatsCache.get(userId, packageName);
if (appStats == null) {
@@ -1481,7 +1482,7 @@ public final class QuotaController extends StateController {
mRunningBgJobs.add(jobStatus);
if (shouldTrackLocked()) {
mBgJobCount++;
- incrementJobCount(mPkg.userId, mPkg.packageName, 1);
+ incrementJobCountLocked(mPkg.userId, mPkg.packageName, 1);
if (mRunningBgJobs.size() == 1) {
// Started tracking the first job.
mStartTimeElapsed = sElapsedRealtimeClock.millis();
@@ -1534,7 +1535,7 @@ public final class QuotaController extends StateController {
// of jobs.
// However, cancel the currently scheduled cutoff since it's not currently useful.
cancelCutoff();
- incrementTimingSessionCount(mPkg.userId, mPkg.packageName);
+ incrementTimingSessionCountLocked(mPkg.userId, mPkg.packageName);
}
/**
@@ -1581,7 +1582,7 @@ public final class QuotaController extends StateController {
// repeatedly plugged in and unplugged, or an app changes foreground state
// very frequently, the job count for a package may be artificially high.
mBgJobCount = mRunningBgJobs.size();
- incrementJobCount(mPkg.userId, mPkg.packageName, mBgJobCount);
+ incrementJobCountLocked(mPkg.userId, mPkg.packageName, mBgJobCount);
// Starting the timer means that all cached execution stats are now
// incorrect.
invalidateAllExecutionStatsLocked(mPkg.userId, mPkg.packageName);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
index e2c8f649fdb7..3c4961ab6825 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/idle/DeviceIdlenessTracker.java
@@ -16,6 +16,8 @@
package com.android.server.job.controllers.idle;
+import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
+
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import android.app.AlarmManager;
@@ -34,7 +36,9 @@ import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateControllerProto;
import java.io.PrintWriter;
+import java.util.Set;
+/** Class to track device idle state. */
public final class DeviceIdlenessTracker extends BroadcastReceiver implements IdlenessTracker {
private static final String TAG = "JobScheduler.DeviceIdlenessTracker";
private static final boolean DEBUG = JobSchedulerService.DEBUG
@@ -50,8 +54,10 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
private boolean mIdle;
private boolean mScreenOn;
private boolean mDockIdle;
- private boolean mInCarMode;
+ private boolean mProjectionActive;
private IdlenessListener mIdleListener;
+ private final UiModeManager.OnProjectionStateChangeListener mOnProjectionStateChangeListener =
+ this::onProjectionStateChanged;
private AlarmManager.OnAlarmListener mIdleAlarmListener = () -> {
handleIdleTrigger();
@@ -60,10 +66,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
public DeviceIdlenessTracker() {
// At boot we presume that the user has just "interacted" with the
// device in some meaningful way.
- mIdle = false;
mScreenOn = true;
- mDockIdle = false;
- mInCarMode = false;
}
@Override
@@ -98,11 +101,34 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
filter.addAction(Intent.ACTION_DOCK_IDLE);
filter.addAction(Intent.ACTION_DOCK_ACTIVE);
- // Car mode
- filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
- filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
-
context.registerReceiver(this, filter);
+
+ // TODO(b/172579710): Move the callbacks off the main executor and on to
+ // JobSchedulerBackgroundThread.getExecutor() once synchronization is fixed in this class.
+ context.getSystemService(UiModeManager.class).addOnProjectionStateChangeListener(
+ UiModeManager.PROJECTION_TYPE_ALL, context.getMainExecutor(),
+ mOnProjectionStateChangeListener);
+ }
+
+ private void onProjectionStateChanged(@UiModeManager.ProjectionType int activeProjectionTypes,
+ Set<String> projectingPackages) {
+ boolean projectionActive = activeProjectionTypes != PROJECTION_TYPE_NONE;
+ if (mProjectionActive == projectionActive) {
+ return;
+ }
+ if (DEBUG) {
+ Slog.v(TAG, "Projection state changed: " + projectionActive);
+ }
+ mProjectionActive = projectionActive;
+ if (mProjectionActive) {
+ cancelIdlenessCheck();
+ if (mIdle) {
+ mIdle = false;
+ mIdleListener.reportNewIdleState(mIdle);
+ }
+ } else {
+ maybeScheduleIdlenessCheck("Projection ended");
+ }
}
@Override
@@ -110,8 +136,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
pw.print(" mIdle: "); pw.println(mIdle);
pw.print(" mScreenOn: "); pw.println(mScreenOn);
pw.print(" mDockIdle: "); pw.println(mDockIdle);
- pw.print(" mInCarMode: ");
- pw.println(mInCarMode);
+ pw.print(" mProjectionActive: "); pw.println(mProjectionActive);
}
@Override
@@ -129,8 +154,9 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
StateControllerProto.IdleController.IdlenessTracker.DeviceIdlenessTracker.IS_DOCK_IDLE,
mDockIdle);
proto.write(
- StateControllerProto.IdleController.IdlenessTracker.DeviceIdlenessTracker.IN_CAR_MODE,
- mInCarMode);
+ StateControllerProto.IdleController.IdlenessTracker.DeviceIdlenessTracker
+ .PROJECTION_ACTIVE,
+ mProjectionActive);
proto.end(diToken);
proto.end(token);
@@ -186,18 +212,6 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
}
maybeScheduleIdlenessCheck(action);
break;
- case UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED:
- mInCarMode = true;
- cancelIdlenessCheck();
- if (mIdle) {
- mIdle = false;
- mIdleListener.reportNewIdleState(mIdle);
- }
- break;
- case UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED:
- mInCarMode = false;
- maybeScheduleIdlenessCheck(action);
- break;
case ActivityManagerService.ACTION_TRIGGER_IDLE:
handleIdleTrigger();
break;
@@ -205,7 +219,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
}
private void maybeScheduleIdlenessCheck(String reason) {
- if ((!mScreenOn || mDockIdle) && !mInCarMode) {
+ if ((!mScreenOn || mDockIdle) && !mProjectionActive) {
final long nowElapsed = sElapsedRealtimeClock.millis();
final long when = nowElapsed + mInactivityIdleThreshold;
if (DEBUG) {
@@ -222,7 +236,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
private void handleIdleTrigger() {
// idle time starts now. Do not set mIdle if screen is on.
- if (!mIdle && (!mScreenOn || mDockIdle) && !mInCarMode) {
+ if (!mIdle && (!mScreenOn || mDockIdle) && !mProjectionActive) {
if (DEBUG) {
Slog.v(TAG, "Idle trigger fired @ " + sElapsedRealtimeClock.millis());
}
@@ -231,7 +245,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
} else {
if (DEBUG) {
Slog.v(TAG, "TRIGGER_IDLE received but not changing state; idle="
- + mIdle + " screen=" + mScreenOn + " car=" + mInCarMode);
+ + mIdle + " screen=" + mScreenOn + " projection=" + mProjectionActive);
}
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 6f7dde292c56..1157ee905b86 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -2390,7 +2390,8 @@ public class AppStandbyController implements AppStandbyInternal {
false, this);
mInjector.registerDeviceConfigPropertiesChangedListener(this);
// Load all the constants.
- onPropertiesChanged(mInjector.getDeviceConfigProperties());
+ // postOneTimeCheckIdleStates() doesn't need to be called on boot.
+ processProperties(mInjector.getDeviceConfigProperties());
updateSettings();
}
@@ -2402,6 +2403,11 @@ public class AppStandbyController implements AppStandbyInternal {
@Override
public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ processProperties(properties);
+ postOneTimeCheckIdleStates();
+ }
+
+ private void processProperties(DeviceConfig.Properties properties) {
boolean timeThresholdsUpdated = false;
synchronized (mAppIdleLock) {
for (String name : properties.getKeyset()) {
@@ -2482,7 +2488,6 @@ public class AppStandbyController implements AppStandbyInternal {
}
}
}
- postOneTimeCheckIdleStates();
}
private void updateTimeThresholds() {
diff --git a/apex/media/framework/TEST_MAPPING b/apex/media/framework/TEST_MAPPING
index ec2d2e2e756c..70c908787472 100644
--- a/apex/media/framework/TEST_MAPPING
+++ b/apex/media/framework/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "CtsMediaParserTestCases"
+ },
+ {
+ "name": "CtsMediaParserHostSideTestCases"
}
]
}
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 045b4136a710..8bdca766e0dd 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -1186,11 +1186,10 @@ public final class MediaParser {
// TODO: For efficiency, the same implementation should be used, by providing a
// clearBuffers() method, or similar.
long resourceLength = seekableInputReader.getLength();
- if (resourceLength == -1) {
- mResourceByteCount = -1;
- }
- if (mResourceByteCount != -1) {
- mResourceByteCount += resourceLength;
+ if (mResourceByteCount == 0) {
+ // For resource byte count metric collection, we only take into account the length
+ // of the first provided input reader.
+ mResourceByteCount = resourceLength;
}
mExtractorInput =
new DefaultExtractorInput(
diff --git a/apex/permission/Android.bp b/apex/permission/Android.bp
index 71a52bb216ea..e30df05b2340 100644
--- a/apex/permission/Android.bp
+++ b/apex/permission/Android.bp
@@ -21,7 +21,7 @@ apex {
apex_defaults {
name: "com.android.permission-defaults",
updatable: true,
- min_sdk_version: "R",
+ min_sdk_version: "30",
key: "com.android.permission.key",
certificate: ":com.android.permission.certificate",
java_libs: [
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index ede8852c5905..f13861e7ee85 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -35,7 +35,7 @@ apex_defaults {
prebuilts: ["com.android.os.statsd.init.rc"],
name: "com.android.os.statsd-defaults",
updatable: true,
- min_sdk_version: "R",
+ min_sdk_version: "30",
key: "com.android.os.statsd.key",
certificate: ":com.android.os.statsd.certificate",
}
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 b5e72247a4a3..fbda86f9ce22 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;
@@ -194,40 +195,38 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
int numRecords = 0;
// Add in all the apps for every user/profile.
for (UserHandle userHandle : users) {
- List<PackageInfo> pi =
- pm.getInstalledPackagesAsUser(PackageManager.MATCH_UNINSTALLED_PACKAGES
- | PackageManager.MATCH_ANY_USER
- | PackageManager.MATCH_APEX,
- userHandle.getIdentifier());
- for (int j = 0; j < pi.size(); j++) {
- if (pi.get(j).applicationInfo != null) {
+ List<PackageInfo> packagesPlusApex = getAllPackagesWithApex(pm, userHandle);
+ for (int j = 0; j < packagesPlusApex.size(); j++) {
+ if (packagesPlusApex.get(j).applicationInfo != null) {
String installer;
try {
- installer = pm.getInstallerPackageName(pi.get(j).packageName);
+ installer = pm.getInstallerPackageName(
+ packagesPlusApex.get(j).packageName);
} catch (IllegalArgumentException e) {
installer = "";
}
long applicationInfoToken =
output.start(ProtoOutputStream.FIELD_TYPE_MESSAGE
| ProtoOutputStream.FIELD_COUNT_REPEATED
- | APPLICATION_INFO_FIELD_ID);
+ | APPLICATION_INFO_FIELD_ID);
output.write(ProtoOutputStream.FIELD_TYPE_INT32
- | ProtoOutputStream.FIELD_COUNT_SINGLE | UID_FIELD_ID,
- pi.get(j).applicationInfo.uid);
+ | ProtoOutputStream.FIELD_COUNT_SINGLE | UID_FIELD_ID,
+ packagesPlusApex.get(j).applicationInfo.uid);
output.write(ProtoOutputStream.FIELD_TYPE_INT64
- | ProtoOutputStream.FIELD_COUNT_SINGLE
- | VERSION_FIELD_ID, pi.get(j).getLongVersionCode());
+ | ProtoOutputStream.FIELD_COUNT_SINGLE
+ | VERSION_FIELD_ID,
+ packagesPlusApex.get(j).getLongVersionCode());
output.write(ProtoOutputStream.FIELD_TYPE_STRING
- | ProtoOutputStream.FIELD_COUNT_SINGLE
- | VERSION_STRING_FIELD_ID,
- pi.get(j).versionName);
+ | ProtoOutputStream.FIELD_COUNT_SINGLE
+ | VERSION_STRING_FIELD_ID,
+ packagesPlusApex.get(j).versionName);
output.write(ProtoOutputStream.FIELD_TYPE_STRING
| ProtoOutputStream.FIELD_COUNT_SINGLE
- | PACKAGE_NAME_FIELD_ID, pi.get(j).packageName);
+ | PACKAGE_NAME_FIELD_ID, packagesPlusApex.get(j).packageName);
output.write(ProtoOutputStream.FIELD_TYPE_STRING
- | ProtoOutputStream.FIELD_COUNT_SINGLE
+ | ProtoOutputStream.FIELD_COUNT_SINGLE
| INSTALLER_FIELD_ID,
- installer == null ? "" : installer);
+ installer == null ? "" : installer);
numRecords++;
output.end(applicationInfoToken);
}
@@ -245,6 +244,26 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
});
}
+ private static List<PackageInfo> getAllPackagesWithApex(PackageManager pm,
+ UserHandle userHandle) {
+ // We want all the uninstalled packages because uninstalled package uids can still be logged
+ // to statsd.
+ List<PackageInfo> allPackages = new ArrayList<>(
+ pm.getInstalledPackagesAsUser(PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_ANY_USER,
+ userHandle.getIdentifier()));
+ // We make a second query to package manager for the apex modules because package manager
+ // returns both installed and uninstalled apexes with
+ // PackageManager.MATCH_UNINSTALLED_PACKAGES flag. We only want active apexes because
+ // inactive apexes can conflict with active ones.
+ for (PackageInfo packageInfo : pm.getInstalledPackages(PackageManager.MATCH_APEX)) {
+ if (packageInfo.isApex) {
+ allPackages.add(packageInfo);
+ }
+ }
+ return allPackages;
+ }
+
private static class WakelockThread extends Thread {
private final PowerManager.WakeLock mWl;
private final Runnable mRunnable;
diff --git a/api/Android.bp b/api/Android.bp
index 28b75944072f..5ee41b79b58c 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -19,7 +19,7 @@ package {
genrule {
name: "current-api-xml",
tools: ["metalava"],
- srcs: ["current.txt"],
+ srcs: [":frameworks-base-api-current.txt"],
out: ["current.api"],
cmd: "$(location metalava) --no-banner -convert2xmlnostrip $(in) $(out)",
visibility: ["//visibility:public"],
@@ -59,6 +59,27 @@ genrule {
}
genrule {
+ name: "frameworks-base-api-current.srcjar",
+ srcs: [
+ ":api-stubs-docs-non-updatable",
+ ":conscrypt.module.public.api{.public.stubs.source}",
+ ":framework-appsearch{.public.stubs.source}",
+ ":framework-graphics{.public.stubs.source}",
+ ":framework-media{.public.stubs.source}",
+ ":framework-mediaprovider{.public.stubs.source}",
+ ":framework-permission{.public.stubs.source}",
+ ":framework-sdkextensions{.public.stubs.source}",
+ ":framework-statsd{.public.stubs.source}",
+ ":framework-tethering{.public.stubs.source}",
+ ":framework-wifi{.public.stubs.source}",
+ ],
+ out: ["current.srcjar"],
+ tools: ["merge_zips"],
+ cmd: "$(location merge_zips) $(out) $(in)",
+ visibility: ["//visibility:private"], // Used by make module in //development, mind.
+}
+
+genrule {
name: "frameworks-base-api-removed.txt",
srcs: [
":conscrypt.module.public.api{.public.removed-api.txt}",
diff --git a/api/current.txt b/api/current.txt
index 6459eb4c548a..659e8af54b02 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31,6 +31,7 @@ package android {
field @Deprecated public static final String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
field public static final String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
field @Deprecated public static final String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+ field public static final String BIND_COMPANION_DEVICE_SERVICE = "android.permission.BIND_COMPANION_DEVICE_SERVICE";
field public static final String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
field public static final String BIND_CONTROLS = "android.permission.BIND_CONTROLS";
field public static final String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
@@ -133,6 +134,7 @@ package android {
field public static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
field public static final String REORDER_TASKS = "android.permission.REORDER_TASKS";
+ field public static final String REQUEST_COMPANION_PROFILE_WATCH = "android.permission.REQUEST_COMPANION_PROFILE_WATCH";
field public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
field public static final String REQUEST_COMPANION_USE_DATA_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND";
field public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
@@ -5489,7 +5491,9 @@ package android.app {
field public static final String CATEGORY_EMAIL = "email";
field public static final String CATEGORY_ERROR = "err";
field public static final String CATEGORY_EVENT = "event";
+ field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
field public static final String CATEGORY_MESSAGE = "msg";
+ field public static final String CATEGORY_MISSED_CALL = "missed_call";
field public static final String CATEGORY_NAVIGATION = "navigation";
field public static final String CATEGORY_PROGRESS = "progress";
field public static final String CATEGORY_PROMO = "promo";
@@ -5498,8 +5502,10 @@ package android.app {
field public static final String CATEGORY_SERVICE = "service";
field public static final String CATEGORY_SOCIAL = "social";
field public static final String CATEGORY_STATUS = "status";
+ field public static final String CATEGORY_STOPWATCH = "stopwatch";
field public static final String CATEGORY_SYSTEM = "sys";
field public static final String CATEGORY_TRANSPORT = "transport";
+ field public static final String CATEGORY_WORKOUT = "workout";
field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification> CREATOR;
field public static final int DEFAULT_ALL = -1; // 0xffffffff
@@ -5528,6 +5534,7 @@ package android.app {
field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
field public static final String EXTRA_PICTURE = "android.picture";
+ field public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION = "android.pictureContentDescription";
field public static final String EXTRA_PROGRESS = "android.progress";
field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
@@ -5673,6 +5680,7 @@ package android.app {
method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon);
method public android.app.Notification.BigPictureStyle bigPicture(android.graphics.Bitmap);
+ method @NonNull public android.app.Notification.BigPictureStyle bigPictureContentDescription(@Nullable CharSequence);
method public android.app.Notification.BigPictureStyle setBigContentTitle(CharSequence);
method public android.app.Notification.BigPictureStyle setSummaryText(CharSequence);
}
@@ -5972,6 +5980,7 @@ package android.app {
method public long[] getVibrationPattern();
method public boolean hasUserSetImportance();
method public boolean hasUserSetSound();
+ method public boolean isConversation();
method public boolean isDemoted();
method public boolean isImportantConversation();
method public void setAllowBubbles(boolean);
@@ -6138,6 +6147,7 @@ package android.app {
method public android.content.IntentSender getIntentSender();
method public static android.app.PendingIntent getService(android.content.Context, int, @NonNull android.content.Intent, int);
method @Deprecated public String getTargetPackage();
+ method public boolean isImmutable();
method @Nullable public static android.app.PendingIntent readPendingIntentOrNullFromParcel(@NonNull android.os.Parcel);
method public void send() throws android.app.PendingIntent.CanceledException;
method public void send(int) throws android.app.PendingIntent.CanceledException;
@@ -6940,6 +6950,7 @@ package android.app.admin {
method @Nullable public java.util.List<java.lang.String> getPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName);
method @Nullable public java.util.List<java.lang.String> getPermittedInputMethods(@NonNull android.content.ComponentName);
method public int getPersonalAppsSuspendedReasons(@NonNull android.content.ComponentName);
+ method public int getRequiredPasswordComplexity();
method public long getRequiredStrongAuthTimeout(@Nullable android.content.ComponentName);
method public boolean getScreenCaptureDisabled(@Nullable android.content.ComponentName);
method public java.util.List<android.os.UserHandle> getSecondaryUsers(@NonNull android.content.ComponentName);
@@ -7071,6 +7082,7 @@ package android.app.admin {
method public void setProfileEnabled(@NonNull android.content.ComponentName);
method public void setProfileName(@NonNull android.content.ComponentName, String);
method public void setRecommendedGlobalProxy(@NonNull android.content.ComponentName, @Nullable android.net.ProxyInfo);
+ method public void setRequiredPasswordComplexity(int);
method public void setRequiredStrongAuthTimeout(@NonNull android.content.ComponentName, long);
method public boolean setResetPasswordToken(android.content.ComponentName, byte[]);
method public void setRestrictionsProvider(@NonNull android.content.ComponentName, @Nullable android.content.ComponentName);
@@ -7393,6 +7405,12 @@ package android.app.admin {
field public static final int ERROR_UNKNOWN = 1; // 0x1
}
+ public final class UnsafeStateException extends java.lang.IllegalStateException implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.UnsafeStateException> CREATOR;
+ }
+
}
package android.app.assist {
@@ -9430,14 +9448,16 @@ package android.companion {
public final class AssociationRequest implements android.os.Parcelable {
method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.companion.AssociationRequest> CREATOR;
+ field public static final String DEVICE_PROFILE_WATCH = "android.app.role.COMPANION_DEVICE_WATCH";
}
public static final class AssociationRequest.Builder {
ctor public AssociationRequest.Builder();
method @NonNull public android.companion.AssociationRequest.Builder addDeviceFilter(@Nullable android.companion.DeviceFilter<?>);
method @NonNull public android.companion.AssociationRequest build();
+ method @NonNull public android.companion.AssociationRequest.Builder setDeviceProfile(@NonNull String);
method @NonNull public android.companion.AssociationRequest.Builder setSingleDevice(boolean);
}
@@ -9487,6 +9507,14 @@ package android.companion {
method public abstract void onFailure(CharSequence);
}
+ public abstract class CompanionDeviceService extends android.app.Service {
+ ctor public CompanionDeviceService();
+ method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
+ method @MainThread public abstract void onDeviceAppeared(@NonNull String);
+ method @MainThread public abstract void onDeviceDisappeared(@NonNull String);
+ field public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService";
+ }
+
public interface DeviceFilter<D extends android.os.Parcelable> extends android.os.Parcelable {
}
@@ -10679,8 +10707,6 @@ package android.content {
field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
- field public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
- field public static final String ACTION_PACKAGE_UNSTARTABLE = "android.intent.action.PACKAGE_UNSTARTABLE";
field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
field public static final String ACTION_PASTE = "android.intent.action.PASTE";
field public static final String ACTION_PICK = "android.intent.action.PICK";
@@ -11718,10 +11744,9 @@ package android.content.pm {
method public long getFirstInstallTime();
method public android.graphics.drawable.Drawable getIcon(int);
method public CharSequence getLabel();
- method public float getLoadingProgress();
+ method @FloatRange(from=0.0, to=1.0) public float getLoadingProgress();
method public String getName();
method public android.os.UserHandle getUser();
- method public boolean isStartable();
}
public class LauncherApps {
@@ -12308,9 +12333,6 @@ package android.content.pm {
field public static final int SYNCHRONOUS = 2; // 0x2
field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
- field public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1; // 0x1
- field public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2; // 0x2
- field public static final int UNSTARTABLE_REASON_UNKNOWN = 0; // 0x0
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
@@ -15599,6 +15621,19 @@ package android.graphics {
method public final boolean next(android.graphics.Rect);
}
+ public final class RenderEffect {
+ method @NonNull public static android.graphics.RenderEffect createBitmapEffect(@NonNull android.graphics.Bitmap);
+ method @NonNull public static android.graphics.RenderEffect createBitmapEffect(@NonNull android.graphics.Bitmap, @Nullable android.graphics.Rect, @NonNull android.graphics.Rect);
+ method @NonNull public static android.graphics.RenderEffect createBlendModeEffect(@NonNull android.graphics.RenderEffect, @NonNull android.graphics.RenderEffect, @NonNull android.graphics.BlendMode);
+ method @NonNull public static android.graphics.RenderEffect createBlurEffect(float, float, @NonNull android.graphics.RenderEffect, @NonNull android.graphics.Shader.TileMode);
+ method @NonNull public static android.graphics.RenderEffect createBlurEffect(float, float, @NonNull android.graphics.Shader.TileMode);
+ method @NonNull public static android.graphics.RenderEffect createChainEffect(@NonNull android.graphics.RenderEffect, @NonNull android.graphics.RenderEffect);
+ method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter, @NonNull android.graphics.RenderEffect);
+ method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter);
+ method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float);
+ method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float, @NonNull android.graphics.RenderEffect);
+ }
+
public final class RenderNode {
ctor public RenderNode(@Nullable String);
method @NonNull public android.graphics.RecordingCanvas beginRecording(int, int);
@@ -15658,6 +15693,7 @@ package android.graphics {
method public boolean setPosition(@NonNull android.graphics.Rect);
method public boolean setProjectBackwards(boolean);
method public boolean setProjectionReceiver(boolean);
+ method public void setRenderEffect(@Nullable android.graphics.RenderEffect);
method public boolean setRotationX(float);
method public boolean setRotationY(float);
method public boolean setRotationZ(float);
@@ -16425,6 +16461,7 @@ package android.graphics.fonts {
method public float getGlyphBounds(@IntRange(from=0) int, @NonNull android.graphics.Paint, @Nullable android.graphics.RectF);
method @NonNull public android.os.LocaleList getLocaleList();
method public void getMetrics(@NonNull android.graphics.Paint, @Nullable android.graphics.Paint.FontMetrics);
+ method public int getSourceIdentifier();
method @NonNull public android.graphics.fonts.FontStyle getStyle();
method @IntRange(from=0) public int getTtcIndex();
}
@@ -23939,7 +23976,7 @@ package android.location {
method public float getBearingAccuracyDegrees();
method public long getElapsedRealtimeNanos();
method public double getElapsedRealtimeUncertaintyNanos();
- method public android.os.Bundle getExtras();
+ method @Deprecated public android.os.Bundle getExtras();
method public double getLatitude();
method public double getLongitude();
method public String getProvider();
@@ -23968,7 +24005,7 @@ package android.location {
method public void setBearingAccuracyDegrees(float);
method public void setElapsedRealtimeNanos(long);
method public void setElapsedRealtimeUncertaintyNanos(double);
- method public void setExtras(android.os.Bundle);
+ method @Deprecated public void setExtras(android.os.Bundle);
method public void setLatitude(double);
method public void setLongitude(double);
method public void setProvider(String);
@@ -23984,7 +24021,9 @@ package android.location {
}
public interface LocationListener {
+ method public default void onFlushComplete(int);
method public void onLocationChanged(@NonNull android.location.Location);
+ method public default void onLocationChanged(@NonNull android.location.LocationResult);
method public default void onProviderDisabled(@NonNull String);
method public default void onProviderEnabled(@NonNull String);
method @Deprecated public default void onStatusChanged(String, int, android.os.Bundle);
@@ -24032,6 +24071,8 @@ package android.location {
method public void removeTestProvider(@NonNull String);
method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeUpdates(@NonNull android.location.LocationListener);
method public void removeUpdates(@NonNull android.app.PendingIntent);
+ method public void requestFlush(@NonNull String, @NonNull android.location.LocationListener, int);
+ method public void requestFlush(@NonNull String, @NonNull android.app.PendingIntent, int);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
@@ -24057,7 +24098,9 @@ package android.location {
field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
field public static final String GPS_PROVIDER = "gps";
+ field public static final String KEY_FLUSH_COMPLETE = "flushComplete";
field public static final String KEY_LOCATION_CHANGED = "location";
+ field public static final String KEY_LOCATION_RESULT = "locationResult";
field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
field public static final String KEY_PROXIMITY_ENTERING = "entering";
field @Deprecated public static final String KEY_STATUS_CHANGED = "status";
@@ -24088,6 +24131,7 @@ package android.location {
method public int describeContents();
method @IntRange(from=1) public long getDurationMillis();
method @IntRange(from=0) public long getIntervalMillis();
+ method @IntRange(from=0) public long getMaxUpdateDelayMillis();
method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
method @IntRange(from=0) public long getMinUpdateIntervalMillis();
@@ -24107,12 +24151,25 @@ package android.location {
method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+ method @NonNull public android.location.LocationRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
method @NonNull public android.location.LocationRequest.Builder setQuality(int);
}
+ public final class LocationResult implements android.os.Parcelable {
+ method @NonNull public java.util.List<android.location.Location> asList();
+ method @NonNull public static android.location.LocationResult create(@NonNull android.location.Location);
+ method @NonNull public static android.location.LocationResult create(@NonNull java.util.List<android.location.Location>);
+ method public int describeContents();
+ method @NonNull public android.location.Location get(@IntRange(from=0) int);
+ method @NonNull public android.location.Location getLastLocation();
+ method @IntRange(from=1) public int size();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationResult> CREATOR;
+ }
+
public interface OnNmeaMessageListener {
method public void onNmeaMessage(String, long);
}
@@ -24333,6 +24390,8 @@ package android.media {
field public static final int ENCODING_MP3 = 9; // 0x9
field public static final int ENCODING_OPUS = 20; // 0x14
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
+ field public static final int ENCODING_PCM_24BIT_PACKED = 21; // 0x15
+ field public static final int ENCODING_PCM_32BIT = 22; // 0x16
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
@@ -25274,6 +25333,7 @@ package android.media {
public final class MediaCas implements java.lang.AutoCloseable {
ctor public MediaCas(int) throws android.media.MediaCasException.UnsupportedCasException;
ctor public MediaCas(@NonNull android.content.Context, int, @Nullable String, int) throws android.media.MediaCasException.UnsupportedCasException;
+ ctor public MediaCas(@NonNull android.content.Context, int, @Nullable String, int, @Nullable android.os.Handler, @Nullable android.media.MediaCas.EventListener) throws android.media.MediaCasException.UnsupportedCasException;
method public void close();
method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
method protected void finalize();
@@ -28809,7 +28869,6 @@ package android.media.session {
public final class MediaController {
ctor public MediaController(@NonNull android.content.Context, @NonNull android.media.session.MediaSession.Token);
method public void adjustVolume(int, int);
- method @Deprecated public boolean controlsSameSession(@Nullable android.media.session.MediaController);
method public boolean dispatchMediaButtonEvent(@NonNull android.view.KeyEvent);
method @Nullable public android.os.Bundle getExtras();
method public long getFlags();
@@ -31405,6 +31464,8 @@ package android.net.wifi {
field @Deprecated public String FQDN;
field @Deprecated public static final int SECURITY_TYPE_EAP = 3; // 0x3
field @Deprecated public static final int SECURITY_TYPE_EAP_SUITE_B = 5; // 0x5
+ field @Deprecated public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE = 9; // 0x9
+ field @Deprecated public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT = 5; // 0x5
field @Deprecated public static final int SECURITY_TYPE_OPEN = 0; // 0x0
field @Deprecated public static final int SECURITY_TYPE_OWE = 6; // 0x6
field @Deprecated public static final int SECURITY_TYPE_PSK = 2; // 0x2
@@ -31621,6 +31682,7 @@ package android.net.wifi {
method public android.net.DhcpInfo getDhcpInfo();
method public int getMaxNumberOfNetworkSuggestionsPerApp();
method @IntRange(from=0) public int getMaxSignalLevel();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getNetworkSuggestionUserApprovalStatus();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions();
method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_SETUP_WIZARD"}) public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
@@ -31642,6 +31704,7 @@ package android.net.wifi {
method public boolean isWapiSupported();
method public boolean isWifiEnabled();
method public boolean isWifiStandardSupported(int);
+ method public boolean isWpa3ApValidationSupported();
method public boolean isWpa3SaeSupported();
method public boolean isWpa3SuiteBSupported();
method @Deprecated public boolean pingSupplicant();
@@ -31690,6 +31753,11 @@ package android.net.wifi {
field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1; // 0x1
field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5; // 0x5
field public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0; // 0x0
+ field public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE = 4; // 0x4
+ field public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER = 2; // 0x2
+ field public static final int STATUS_SUGGESTION_APPROVAL_PENDING = 1; // 0x1
+ field public static final int STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER = 3; // 0x3
+ field public static final int STATUS_SUGGESTION_APPROVAL_UNKNOWN = 0; // 0x0
field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION = 1; // 0x1
field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION = 2; // 0x2
field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING = 3; // 0x3
@@ -43074,10 +43142,11 @@ package android.security.keystore {
method public String getKeystoreAlias();
method public int getOrigin();
method public int getPurposes();
+ method public int getSecurityLevel();
method @NonNull public String[] getSignaturePaddings();
method public int getUserAuthenticationType();
method public int getUserAuthenticationValidityDurationSeconds();
- method public boolean isInsideSecureHardware();
+ method @Deprecated public boolean isInsideSecureHardware();
method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isTrustedUserPresenceRequired();
method public boolean isUserAuthenticationRequired();
@@ -43134,6 +43203,11 @@ package android.security.keystore {
field public static final int PURPOSE_SIGN = 4; // 0x4
field public static final int PURPOSE_VERIFY = 8; // 0x8
field public static final int PURPOSE_WRAP_KEY = 32; // 0x20
+ field public static final int SECURITY_LEVEL_SOFTWARE = 0; // 0x0
+ field public static final int SECURITY_LEVEL_STRONGBOX = 2; // 0x2
+ field public static final int SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1; // 0x1
+ field public static final int SECURITY_LEVEL_UNKNOWN = -2; // 0xfffffffe
+ field public static final int SECURITY_LEVEL_UNKNOWN_SECURE = -1; // 0xffffffff
field public static final String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
field public static final String SIGNATURE_PADDING_RSA_PSS = "PSS";
}
@@ -46074,6 +46148,8 @@ package android.telecom {
field public static final String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
field public static final String EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME = "android.telecom.extra.ANSWERING_DROPS_FG_CALL_APP_NAME";
field public static final String EXTRA_AUDIO_CODEC = "android.telecom.extra.AUDIO_CODEC";
+ field public static final String EXTRA_AUDIO_CODEC_BANDWIDTH_KHZ = "android.telecom.extra.AUDIO_CODEC_BANDWIDTH_KHZ";
+ field public static final String EXTRA_AUDIO_CODEC_BITRATE_KBPS = "android.telecom.extra.AUDIO_CODEC_BITRATE_KBPS";
field public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final String EXTRA_IS_RTT_AUDIO_PRESENT = "android.telecom.extra.IS_RTT_AUDIO_PRESENT";
@@ -52659,6 +52735,7 @@ package android.view {
public static final class Display.Mode implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public float[] getAlternativeRefreshRates();
method public int getModeId();
method public int getPhysicalHeight();
method public int getPhysicalWidth();
@@ -53789,16 +53866,17 @@ package android.view {
field public int toolType;
}
- public interface OnReceiveContentCallback<T extends android.view.View> {
- method public boolean onReceiveContent(@NonNull T, @NonNull android.view.OnReceiveContentCallback.Payload);
+ public interface OnReceiveContentListener {
+ method @Nullable public android.view.OnReceiveContentListener.Payload onReceiveContent(@NonNull android.view.View, @NonNull android.view.OnReceiveContentListener.Payload);
}
- public static final class OnReceiveContentCallback.Payload {
+ public static final class OnReceiveContentListener.Payload {
method @NonNull public android.content.ClipData getClip();
method @Nullable public android.os.Bundle getExtras();
method public int getFlags();
method @Nullable public android.net.Uri getLinkUri();
method public int getSource();
+ method @NonNull public java.util.Map<java.lang.Boolean,android.view.OnReceiveContentListener.Payload> partition(@NonNull java.util.function.Predicate<android.content.ClipData.Item>);
field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
field public static final int SOURCE_APP = 0; // 0x0
field public static final int SOURCE_AUTOFILL = 4; // 0x4
@@ -53808,12 +53886,15 @@ package android.view {
field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
}
- public static final class OnReceiveContentCallback.Payload.Builder {
- ctor public OnReceiveContentCallback.Payload.Builder(@NonNull android.content.ClipData, int);
- method @NonNull public android.view.OnReceiveContentCallback.Payload build();
- method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setExtras(@Nullable android.os.Bundle);
- method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setFlags(int);
- method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setLinkUri(@Nullable android.net.Uri);
+ public static final class OnReceiveContentListener.Payload.Builder {
+ ctor public OnReceiveContentListener.Payload.Builder(@NonNull android.view.OnReceiveContentListener.Payload);
+ ctor public OnReceiveContentListener.Payload.Builder(@NonNull android.content.ClipData, int);
+ method @NonNull public android.view.OnReceiveContentListener.Payload build();
+ method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setClip(@NonNull android.content.ClipData);
+ method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setExtras(@Nullable android.os.Bundle);
+ method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setFlags(int);
+ method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setLinkUri(@Nullable android.net.Uri);
+ method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setSource(int);
}
public abstract class OrientationEventListener {
@@ -54562,7 +54643,7 @@ package android.view {
method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int);
method public void onProvideStructure(android.view.ViewStructure);
method public void onProvideVirtualStructure(android.view.ViewStructure);
- method public boolean onReceiveContent(@NonNull android.view.OnReceiveContentCallback.Payload);
+ method @Nullable public android.view.OnReceiveContentListener.Payload onReceiveContent(@NonNull android.view.OnReceiveContentListener.Payload);
method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
method @CallSuper protected void onRestoreInstanceState(android.os.Parcelable);
method public void onRtlPropertiesChanged(int);
@@ -54720,7 +54801,7 @@ package android.view {
method public void setOnHoverListener(android.view.View.OnHoverListener);
method public void setOnKeyListener(android.view.View.OnKeyListener);
method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener);
- method public void setOnReceiveContentCallback(@Nullable String[], @Nullable android.view.OnReceiveContentCallback);
+ method public void setOnReceiveContentListener(@Nullable String[], @Nullable android.view.OnReceiveContentListener);
method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
method @Deprecated public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
method public void setOnTouchListener(android.view.View.OnTouchListener);
@@ -55105,6 +55186,7 @@ package android.view {
method @Deprecated public static int getMaximumDrawingCacheSize();
method @Deprecated public static int getMaximumFlingVelocity();
method @Deprecated public static int getMinimumFlingVelocity();
+ method public static int getMultiPressTimeout();
method public static int getPressedStateDuration();
method @FloatRange(from=1.0) public float getScaledAmbiguousGestureMultiplier();
method public int getScaledDoubleTapSlop();
@@ -61736,11 +61818,6 @@ package android.widget {
field @NonNull public static final android.os.Parcelable.Creator<android.widget.TextView.SavedState> CREATOR;
}
- public class TextViewOnReceiveContentCallback implements android.view.OnReceiveContentCallback<android.widget.TextView> {
- ctor public TextViewOnReceiveContentCallback();
- method public boolean onReceiveContent(@NonNull android.widget.TextView, @NonNull android.view.OnReceiveContentCallback.Payload);
- }
-
public interface ThemedSpinnerAdapter extends android.widget.SpinnerAdapter {
method @Nullable public android.content.res.Resources.Theme getDropDownViewTheme();
method public void setDropDownViewTheme(@Nullable android.content.res.Resources.Theme);
diff --git a/api/system-current.txt b/api/system-current.txt
deleted file mode 100644
index 9cf09264fed1..000000000000
--- a/api/system-current.txt
+++ /dev/null
@@ -1,13754 +0,0 @@
-// Signature format: 2.0
-package android {
-
- public static final class Manifest.permission {
- field public static final String ACCESS_AMBIENT_LIGHT_STATS = "android.permission.ACCESS_AMBIENT_LIGHT_STATS";
- field public static final String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO";
- field public static final String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM";
- field public static final String ACCESS_CONTEXT_HUB = "android.permission.ACCESS_CONTEXT_HUB";
- field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES";
- field @Deprecated public static final String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO";
- field public static final String ACCESS_INSTANT_APPS = "android.permission.ACCESS_INSTANT_APPS";
- field public static final String ACCESS_LOCUS_ID_USAGE_STATS = "android.permission.ACCESS_LOCUS_ID_USAGE_STATS";
- field public static final String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION";
- field public static final String ACCESS_MTP = "android.permission.ACCESS_MTP";
- field public static final String ACCESS_NETWORK_CONDITIONS = "android.permission.ACCESS_NETWORK_CONDITIONS";
- field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
- field public static final String ACCESS_SHARED_LIBRARIES = "android.permission.ACCESS_SHARED_LIBRARIES";
- field public static final String ACCESS_SHORTCUTS = "android.permission.ACCESS_SHORTCUTS";
- field public static final String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
- field public static final String ACCESS_TV_DESCRAMBLER = "android.permission.ACCESS_TV_DESCRAMBLER";
- field public static final String ACCESS_TV_TUNER = "android.permission.ACCESS_TV_TUNER";
- field public static final String ACCESS_VIBRATOR_STATE = "android.permission.ACCESS_VIBRATOR_STATE";
- field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
- field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY";
- field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
- field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
- field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
- field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
- field public static final String BACKUP = "android.permission.BACKUP";
- field public static final String BIND_ATTENTION_SERVICE = "android.permission.BIND_ATTENTION_SERVICE";
- field public static final String BIND_AUGMENTED_AUTOFILL_SERVICE = "android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE";
- field public static final String BIND_CELL_BROADCAST_SERVICE = "android.permission.BIND_CELL_BROADCAST_SERVICE";
- field @Deprecated public static final String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE";
- field public static final String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE";
- field public static final String BIND_CONTENT_SUGGESTIONS_SERVICE = "android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE";
- field public static final String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH";
- field public static final String BIND_EUICC_SERVICE = "android.permission.BIND_EUICC_SERVICE";
- field public static final String BIND_EXTERNAL_STORAGE_SERVICE = "android.permission.BIND_EXTERNAL_STORAGE_SERVICE";
- field public static final String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE";
- field public static final String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
- field public static final String BIND_MUSIC_RECOGNITION_SERVICE = "android.permission.BIND_MUSIC_RECOGNITION_SERVICE";
- field public static final String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE";
- field public static final String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
- field public static final String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE";
- field public static final String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
- field public static final String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
- field public static final String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
- field public static final String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
- field public static final String BIND_SOUND_TRIGGER_DETECTION_SERVICE = "android.permission.BIND_SOUND_TRIGGER_DETECTION_SERVICE";
- field public static final String BIND_TELEPHONY_DATA_SERVICE = "android.permission.BIND_TELEPHONY_DATA_SERVICE";
- field public static final String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
- field public static final String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
- field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
- field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
- field public static final String BRICK = "android.permission.BRICK";
- field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
- field @Deprecated public static final String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
- field public static final String CAMERA_DISABLE_TRANSMIT_LED = "android.permission.CAMERA_DISABLE_TRANSMIT_LED";
- field public static final String CAPTURE_AUDIO_HOTWORD = "android.permission.CAPTURE_AUDIO_HOTWORD";
- field public static final String CAPTURE_MEDIA_OUTPUT = "android.permission.CAPTURE_MEDIA_OUTPUT";
- field public static final String CAPTURE_TV_INPUT = "android.permission.CAPTURE_TV_INPUT";
- field public static final String CAPTURE_VOICE_COMMUNICATION_OUTPUT = "android.permission.CAPTURE_VOICE_COMMUNICATION_OUTPUT";
- field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
- field public static final String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
- field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
- field public static final String COMPANION_APPROVE_WIFI_CONNECTIONS = "android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS";
- field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
- field public static final String CONFIGURE_WIFI_DISPLAY = "android.permission.CONFIGURE_WIFI_DISPLAY";
- field @Deprecated public static final String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
- field public static final String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
- field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
- field public static final String CONTROL_DISPLAY_COLOR_TRANSFORMS = "android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS";
- field public static final String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
- field public static final String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
- field public static final String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS";
- field public static final String CONTROL_VPN = "android.permission.CONTROL_VPN";
- field public static final String CREATE_USERS = "android.permission.CREATE_USERS";
- field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
- field public static final String DEVICE_POWER = "android.permission.DEVICE_POWER";
- field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
- field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
- field public static final String EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS = "android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS";
- field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
- field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
- field public static final String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
- field public static final String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
- field public static final String GET_RUNTIME_PERMISSIONS = "android.permission.GET_RUNTIME_PERMISSIONS";
- field public static final String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
- field @Deprecated public static final String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS";
- field public static final String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
- field public static final String GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS = "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS";
- field public static final String HANDLE_CAR_MODE_CHANGES = "android.permission.HANDLE_CAR_MODE_CHANGES";
- field public static final String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
- field public static final String HDMI_CEC = "android.permission.HDMI_CEC";
- field public static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS";
- field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
- field public static final String INSTALL_DYNAMIC_SYSTEM = "android.permission.INSTALL_DYNAMIC_SYSTEM";
- field public static final String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
- field public static final String INSTALL_LOCATION_TIME_ZONE_PROVIDER = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
- field public static final String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES";
- field public static final String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES";
- field public static final String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
- field public static final String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
- field public static final String INTERACT_ACROSS_USERS_FULL = "android.permission.INTERACT_ACROSS_USERS_FULL";
- field public static final String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
- field public static final String INVOKE_CARRIER_SETUP = "android.permission.INVOKE_CARRIER_SETUP";
- field public static final String KILL_UID = "android.permission.KILL_UID";
- field public static final String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS";
- field public static final String LOCK_DEVICE = "android.permission.LOCK_DEVICE";
- field public static final String LOOP_RADIO = "android.permission.LOOP_RADIO";
- field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY";
- field @Deprecated public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
- field public static final String MANAGE_ACTIVITY_TASKS = "android.permission.MANAGE_ACTIVITY_TASKS";
- field public static final String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
- field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS";
- field public static final String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
- field public static final String MANAGE_AUTO_FILL = "android.permission.MANAGE_AUTO_FILL";
- field public static final String MANAGE_CARRIER_OEM_UNLOCK_STATE = "android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE";
- field public static final String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
- field public static final String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE";
- field public static final String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
- field public static final String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
- field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
- field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
- field public static final String MANAGE_MUSIC_RECOGNITION = "android.permission.MANAGE_MUSIC_RECOGNITION";
- field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
- field public static final String MANAGE_ONE_TIME_PERMISSION_SESSIONS = "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS";
- field public static final String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
- field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
- field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY";
- field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
- field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
- field public static final String MANAGE_TIME_AND_ZONE_DETECTION = "android.permission.MANAGE_TIME_AND_ZONE_DETECTION";
- field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
- field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
- field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
- field public static final String MODIFY_APPWIDGET_BIND_PERMISSIONS = "android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS";
- field public static final String MODIFY_AUDIO_ROUTING = "android.permission.MODIFY_AUDIO_ROUTING";
- field public static final String MODIFY_CELL_BROADCASTS = "android.permission.MODIFY_CELL_BROADCASTS";
- field public static final String MODIFY_DAY_NIGHT_MODE = "android.permission.MODIFY_DAY_NIGHT_MODE";
- field @Deprecated public static final String MODIFY_NETWORK_ACCOUNTING = "android.permission.MODIFY_NETWORK_ACCOUNTING";
- field public static final String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS";
- field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
- field public static final String MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE = "android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE";
- field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
- field public static final String NETWORK_AIRPLANE_MODE = "android.permission.NETWORK_AIRPLANE_MODE";
- field public static final String NETWORK_CARRIER_PROVISIONING = "android.permission.NETWORK_CARRIER_PROVISIONING";
- field public static final String NETWORK_FACTORY = "android.permission.NETWORK_FACTORY";
- field public static final String NETWORK_MANAGED_PROVISIONING = "android.permission.NETWORK_MANAGED_PROVISIONING";
- field public static final String NETWORK_SCAN = "android.permission.NETWORK_SCAN";
- field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
- field public static final String NETWORK_SETUP_WIZARD = "android.permission.NETWORK_SETUP_WIZARD";
- field public static final String NETWORK_SIGNAL_STRENGTH_WAKEUP = "android.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP";
- field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
- field public static final String NETWORK_STATS_PROVIDER = "android.permission.NETWORK_STATS_PROVIDER";
- field public static final String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
- field public static final String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
- field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
- field public static final String OBSERVE_NETWORK_POLICY = "android.permission.OBSERVE_NETWORK_POLICY";
- field public static final String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS";
- field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS";
- field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
- field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
- field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD";
- field public static final String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS";
- field public static final String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING";
- field public static final String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION";
- field public static final String POWER_SAVER = "android.permission.POWER_SAVER";
- field public static final String PROVIDE_RESOLVER_RANKER_SERVICE = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE";
- field public static final String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT";
- field public static final String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES";
- field public static final String RADIO_SCAN_WITHOUT_LOCATION = "android.permission.RADIO_SCAN_WITHOUT_LOCATION";
- field public static final String READ_ACTIVE_EMERGENCY_SESSION = "android.permission.READ_ACTIVE_EMERGENCY_SESSION";
- field public static final String READ_CARRIER_APP_INFO = "android.permission.READ_CARRIER_APP_INFO";
- field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
- field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS";
- field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
- field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
- field public static final String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
- field public static final String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
- field public static final String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE";
- field public static final String READ_PRINT_SERVICES = "android.permission.READ_PRINT_SERVICES";
- field public static final String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS";
- field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
- field public static final String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
- field public static final String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
- field public static final String READ_SYSTEM_UPDATE_INFO = "android.permission.READ_SYSTEM_UPDATE_INFO";
- field public static final String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL";
- field public static final String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL";
- field public static final String REAL_GET_TASKS = "android.permission.REAL_GET_TASKS";
- field public static final String RECEIVE_DATA_ACTIVITY_CHANGE = "android.permission.RECEIVE_DATA_ACTIVITY_CHANGE";
- field public static final String RECEIVE_DEVICE_CUSTOMIZATION_READY = "android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY";
- field public static final String RECEIVE_EMERGENCY_BROADCAST = "android.permission.RECEIVE_EMERGENCY_BROADCAST";
- field public static final String RECEIVE_WIFI_CREDENTIAL_CHANGE = "android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE";
- field public static final String RECOVERY = "android.permission.RECOVERY";
- field public static final String RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE";
- field public static final String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
- field public static final String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER";
- field public static final String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
- field public static final String REGISTER_STATS_PULL_ATOM = "android.permission.REGISTER_STATS_PULL_ATOM";
- field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
- field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
- field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
- field public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
- field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
- field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
- field public static final String RESTORE_RUNTIME_PERMISSIONS = "android.permission.RESTORE_RUNTIME_PERMISSIONS";
- field public static final String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
- field public static final String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
- field public static final String REVIEW_ACCESSIBILITY_SERVICES = "android.permission.REVIEW_ACCESSIBILITY_SERVICES";
- field public static final String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
- field public static final String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
- field public static final String SECURE_ELEMENT_PRIVILEGED_OPERATION = "android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION";
- field public static final String SEND_CATEGORY_CAR_NOTIFICATIONS = "android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS";
- field public static final String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY";
- field public static final String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS";
- field public static final String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
- field public static final String SERIAL_PORT = "android.permission.SERIAL_PORT";
- field public static final String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
- field public static final String SET_HARMFUL_APP_WARNINGS = "android.permission.SET_HARMFUL_APP_WARNINGS";
- field public static final String SET_MEDIA_KEY_LISTENER = "android.permission.SET_MEDIA_KEY_LISTENER";
- field public static final String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
- field public static final String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED";
- field public static final String SET_SCREEN_COMPATIBILITY = "android.permission.SET_SCREEN_COMPATIBILITY";
- field public static final String SET_VOLUME_KEY_LONG_PRESS_LISTENER = "android.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER";
- field public static final String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT";
- field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
- field public static final String SHUTDOWN = "android.permission.SHUTDOWN";
- field public static final String START_ACTIVITIES_FROM_BACKGROUND = "android.permission.START_ACTIVITIES_FROM_BACKGROUND";
- field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE";
- field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
- field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
- field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
- field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
- field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA";
- field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
- field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
- field public static final String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
- field public static final String UNLIMITED_SHORTCUTS_API_CALLS = "android.permission.UNLIMITED_SHORTCUTS_API_CALLS";
- field public static final String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS";
- field public static final String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
- field public static final String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
- field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
- field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
- field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
- field public static final String WHITELIST_AUTO_REVOKE_PERMISSIONS = "android.permission.WHITELIST_AUTO_REVOKE_PERMISSIONS";
- field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
- field public static final String WIFI_SET_DEVICE_MOBILITY_STATE = "android.permission.WIFI_SET_DEVICE_MOBILITY_STATE";
- field public static final String WIFI_UPDATE_USABILITY_STATS_SCORE = "android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE";
- field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
- field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
- field public static final String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
- field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
- field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
- }
-
- public static final class Manifest.permission_group {
- field public static final String UNDEFINED = "android.permission-group.UNDEFINED";
- }
-
- public static final class R.array {
- field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005
- }
-
- public static final class R.attr {
- field public static final int allowClearUserDataOnFailedRestore = 16844288; // 0x1010600
- field public static final int isVrOnly = 16844152; // 0x1010578
- field public static final int minExtensionVersion = 16844305; // 0x1010611
- field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
- field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
- field public static final int sdkVersion = 16844304; // 0x1010610
- field public static final int supportsAmbientMode = 16844173; // 0x101058d
- field public static final int userRestriction = 16844164; // 0x1010584
- }
-
- public static final class R.bool {
- field public static final int config_sendPackageName = 17891328; // 0x1110000
- field public static final int config_showDefaultAssistant = 17891329; // 0x1110001
- field public static final int config_showDefaultEmergency = 17891330; // 0x1110002
- field public static final int config_showDefaultHome = 17891331; // 0x1110003
- }
-
- public static final class R.color {
- field public static final int system_notification_accent_color = 17170460; // 0x106001c
- }
-
- public static final class R.dimen {
- field public static final int config_restrictedIconSize = 17104903; // 0x1050007
- }
-
- public static final class R.drawable {
- field public static final int ic_info = 17301684; // 0x10800b4
- }
-
- public static final class R.raw {
- field public static final int loaderror = 17825792; // 0x1100000
- field public static final int nodomain = 17825793; // 0x1100001
- }
-
- public static final class R.string {
- field public static final int config_defaultAssistant = 17039393; // 0x1040021
- field public static final int config_defaultBrowser = 17039394; // 0x1040022
- field public static final int config_defaultCallRedirection = 17039397; // 0x1040025
- field public static final int config_defaultCallScreening = 17039398; // 0x1040026
- field public static final int config_defaultDialer = 17039395; // 0x1040023
- field public static final int config_defaultSms = 17039396; // 0x1040024
- field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f
- field public static final int config_feedbackIntentNameKey = 17039392; // 0x1040020
- field public static final int config_helpIntentExtraKey = 17039389; // 0x104001d
- field public static final int config_helpIntentNameKey = 17039390; // 0x104001e
- field public static final int config_helpPackageNameKey = 17039387; // 0x104001b
- field public static final int config_helpPackageNameValue = 17039388; // 0x104001c
- field public static final int config_systemAutomotiveCluster = 17039400; // 0x1040028
- field public static final int config_systemAutomotiveProjection = 17039402; // 0x104002a
- field public static final int config_systemGallery = 17039399; // 0x1040027
- field public static final int config_systemVideoCall = 17039401; // 0x1040029
- }
-
- public static final class R.style {
- field public static final int Theme_DeviceDefault_DocumentsUI = 16974562; // 0x10302e2
- field public static final int Theme_Leanback_FormWizard = 16974544; // 0x10302d0
- }
-
-}
-
-package android.accounts {
-
- public class AccountManager {
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.accounts.AccountManagerFuture<android.os.Bundle> finishSessionAsUser(android.os.Bundle, android.app.Activity, android.os.UserHandle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
- }
-
-}
-
-package android.app {
-
- public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
- method public void convertFromTranslucent();
- method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions);
- method @Deprecated public boolean isBackgroundVisibleBehind();
- method @Deprecated public void onBackgroundVisibleBehindChanged(boolean);
- }
-
- public static interface Activity.TranslucentConversionListener {
- method public void onTranslucentConversionComplete(boolean);
- }
-
- public class ActivityManager {
- method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
- method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
- method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public static int getCurrentUser();
- method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
- method @NonNull public java.util.Collection<java.util.Locale> getSupportedLocales();
- method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
- method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void killProcessesWhenImperceptible(@NonNull int[], @NonNull String);
- method @RequiresPermission(android.Manifest.permission.KILL_UID) public void killUid(int, String);
- method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
- method public void setDeviceLocales(@NonNull android.os.LocaleList);
- method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public static void setPersistentVrThread(int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean switchUser(@NonNull android.os.UserHandle);
- }
-
- public static interface ActivityManager.OnUidImportanceListener {
- method public void onUidImportance(int, int);
- }
-
- public class AlarmManager {
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.PendingIntent, android.os.WorkSource);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.AlarmManager.OnAlarmListener, android.os.Handler, android.os.WorkSource);
- }
-
- public class AppOpsManager {
- method @Nullable @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public android.app.RuntimeAppOpAccessMessage collectRuntimeAppOpAccessMessage();
- method @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
- method public static String[] getOpStrs();
- method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...);
- method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[]);
- method public static int opToDefaultMode(@NonNull String);
- method @Nullable public static String opToPermission(@NonNull String);
- method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(@NonNull String, int, @Nullable String, int);
- method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int);
- field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
- field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
- field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
- field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
- field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
- field public static final String OPSTR_ASSIST_STRUCTURE = "android:assist_structure";
- field public static final String OPSTR_AUDIO_ACCESSIBILITY_VOLUME = "android:audio_accessibility_volume";
- field public static final String OPSTR_AUDIO_ALARM_VOLUME = "android:audio_alarm_volume";
- field public static final String OPSTR_AUDIO_BLUETOOTH_VOLUME = "android:audio_bluetooth_volume";
- field public static final String OPSTR_AUDIO_MASTER_VOLUME = "android:audio_master_volume";
- field public static final String OPSTR_AUDIO_MEDIA_VOLUME = "android:audio_media_volume";
- 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_MANAGED_BY_INSTALLER = "android:auto_revoke_managed_by_installer";
- 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";
- field public static final String OPSTR_GPS = "android:gps";
- field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
- field public static final String OPSTR_INTERACT_ACROSS_PROFILES = "android:interact_across_profiles";
- field public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
- field public static final String OPSTR_LOADER_USAGE_STATS = "android:loader_usage_stats";
- field public static final String OPSTR_MANAGE_EXTERNAL_STORAGE = "android:manage_external_storage";
- field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
- field public static final String OPSTR_MANAGE_ONGOING_CALLS = "android:manage_ongoing_calls";
- field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
- field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
- field public static final String OPSTR_PLAY_AUDIO = "android:play_audio";
- field public static final String OPSTR_POST_NOTIFICATION = "android:post_notification";
- field public static final String OPSTR_PROJECT_MEDIA = "android:project_media";
- field public static final String OPSTR_READ_CLIPBOARD = "android:read_clipboard";
- field public static final String OPSTR_READ_ICC_SMS = "android:read_icc_sms";
- field public static final String OPSTR_READ_MEDIA_AUDIO = "android:read_media_audio";
- field public static final String OPSTR_READ_MEDIA_IMAGES = "android:read_media_images";
- field public static final String OPSTR_READ_MEDIA_VIDEO = "android:read_media_video";
- field public static final String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast";
- field public static final String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages";
- field public static final String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages";
- field public static final String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background";
- field public static final String OPSTR_RUN_IN_BACKGROUND = "android:run_in_background";
- field public static final String OPSTR_START_FOREGROUND = "android:start_foreground";
- field public static final String OPSTR_TAKE_AUDIO_FOCUS = "android:take_audio_focus";
- field public static final String OPSTR_TAKE_MEDIA_BUTTONS = "android:take_media_buttons";
- field public static final String OPSTR_TOAST_WINDOW = "android:toast_window";
- field public static final String OPSTR_TURN_SCREEN_ON = "android:turn_screen_on";
- field public static final String OPSTR_VIBRATE = "android:vibrate";
- field public static final String OPSTR_WAKE_LOCK = "android:wake_lock";
- field public static final String OPSTR_WIFI_SCAN = "android:wifi_scan";
- field public static final String OPSTR_WRITE_CLIPBOARD = "android:write_clipboard";
- field public static final String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
- field public static final String OPSTR_WRITE_MEDIA_AUDIO = "android:write_media_audio";
- field public static final String OPSTR_WRITE_MEDIA_IMAGES = "android:write_media_images";
- field public static final String OPSTR_WRITE_MEDIA_VIDEO = "android:write_media_video";
- field public static final String OPSTR_WRITE_SMS = "android:write_sms";
- field public static final String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
- field public static final int OP_FLAGS_ALL = 31; // 0x1f
- field public static final int OP_FLAGS_ALL_TRUSTED = 13; // 0xd
- field public static final int OP_FLAG_SELF = 1; // 0x1
- field public static final int OP_FLAG_TRUSTED_PROXIED = 8; // 0x8
- field public static final int OP_FLAG_TRUSTED_PROXY = 2; // 0x2
- field public static final int OP_FLAG_UNTRUSTED_PROXIED = 16; // 0x10
- field public static final int OP_FLAG_UNTRUSTED_PROXY = 4; // 0x4
- field public static final int UID_STATE_BACKGROUND = 600; // 0x258
- field public static final int UID_STATE_CACHED = 700; // 0x2bc
- field public static final int UID_STATE_FOREGROUND = 500; // 0x1f4
- field public static final int UID_STATE_FOREGROUND_SERVICE = 400; // 0x190
- field @Deprecated public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300; // 0x12c
- field public static final int UID_STATE_PERSISTENT = 100; // 0x64
- field public static final int UID_STATE_TOP = 200; // 0xc8
- }
-
- public static final class AppOpsManager.AttributedHistoricalOps implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
- method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(@IntRange(from=0) int);
- method @IntRange(from=0) public int getOpCount();
- method @Nullable public String getTag();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.AttributedHistoricalOps> CREATOR;
- }
-
- public static final class AppOpsManager.AttributedOpEntry implements android.os.Parcelable {
- method public int describeContents();
- method public long getLastAccessBackgroundTime(int);
- method public long getLastAccessForegroundTime(int);
- method public long getLastAccessTime(int);
- method public long getLastAccessTime(int, int, int);
- method public long getLastBackgroundDuration(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
- method public long getLastDuration(int);
- method public long getLastDuration(int, int, int);
- method public long getLastForegroundDuration(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
- method public long getLastRejectBackgroundTime(int);
- method public long getLastRejectForegroundTime(int);
- method public long getLastRejectTime(int);
- method public long getLastRejectTime(int, int, int);
- method public boolean isRunning();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.AttributedOpEntry> CREATOR;
- }
-
- public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
- method public int describeContents();
- method public long getAccessCount(int, int, int);
- method public long getAccessDuration(int, int, int);
- method public long getBackgroundAccessCount(int);
- method public long getBackgroundAccessDuration(int);
- method public long getBackgroundRejectCount(int);
- method public long getForegroundAccessCount(int);
- method public long getForegroundAccessDuration(int);
- method public long getForegroundRejectCount(int);
- method @NonNull public String getOpName();
- method public long getRejectCount(int, int, int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOp> CREATOR;
- }
-
- public static final class AppOpsManager.HistoricalOps implements android.os.Parcelable {
- method public int describeContents();
- method public long getBeginTimeMillis();
- method public long getEndTimeMillis();
- method @IntRange(from=0) public int getUidCount();
- method @Nullable public android.app.AppOpsManager.HistoricalUidOps getUidOps(int);
- method @NonNull public android.app.AppOpsManager.HistoricalUidOps getUidOpsAt(@IntRange(from=0) int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
- }
-
- public static final class AppOpsManager.HistoricalOpsRequest {
- }
-
- public static final class AppOpsManager.HistoricalOpsRequest.Builder {
- ctor public AppOpsManager.HistoricalOpsRequest.Builder(long, long);
- method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
- method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setAttributionTag(@Nullable String);
- method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFlags(int);
- method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
- method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
- method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setUid(int);
- }
-
- public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOps(@NonNull String);
- method @NonNull public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOpsAt(@IntRange(from=0) int);
- method @IntRange(from=0) public int getAttributedOpsCount();
- method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
- method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(@IntRange(from=0) int);
- method @IntRange(from=0) public int getOpCount();
- method @NonNull public String getPackageName();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalPackageOps> CREATOR;
- }
-
- public static final class AppOpsManager.HistoricalUidOps implements android.os.Parcelable {
- method public int describeContents();
- method @IntRange(from=0) public int getPackageCount();
- method @Nullable public android.app.AppOpsManager.HistoricalPackageOps getPackageOps(@NonNull String);
- method @NonNull public android.app.AppOpsManager.HistoricalPackageOps getPackageOpsAt(@IntRange(from=0) int);
- method public int getUid();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalUidOps> CREATOR;
- }
-
- public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.AttributedOpEntry> getAttributedOpEntries();
- method @Deprecated public long getDuration();
- method public long getLastAccessBackgroundTime(int);
- method public long getLastAccessForegroundTime(int);
- method public long getLastAccessTime(int);
- method public long getLastAccessTime(int, int, int);
- method public long getLastBackgroundDuration(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
- method public long getLastDuration(int);
- method public long getLastDuration(int, int, int);
- method public long getLastForegroundDuration(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
- method public long getLastRejectBackgroundTime(int);
- method public long getLastRejectForegroundTime(int);
- method public long getLastRejectTime(int);
- method public long getLastRejectTime(int, int, int);
- method public int getMode();
- method @NonNull public String getOpStr();
- method @Deprecated @Nullable public String getProxyPackageName();
- method @Deprecated @Nullable public String getProxyPackageName(int, int);
- method @Deprecated public int getProxyUid();
- method @Deprecated public int getProxyUid(int, int);
- method public boolean isRunning();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEntry> CREATOR;
- }
-
- public static final class AppOpsManager.OpEventProxyInfo implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public String getAttributionTag();
- method @Nullable public String getPackageName();
- method @IntRange(from=0) public int getUid();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEventProxyInfo> CREATOR;
- }
-
- public static final class AppOpsManager.PackageOps implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
- method @NonNull public String getPackageName();
- method public int getUid();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
- }
-
- public class BroadcastOptions {
- method public static android.app.BroadcastOptions makeBasic();
- method @RequiresPermission(android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND) public void setBackgroundActivityStartsAllowed(boolean);
- method public void setDontSendToRestrictedApps(boolean);
- method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void setTemporaryAppWhitelistDuration(long);
- method public android.os.Bundle toBundle();
- }
-
- public class DownloadManager {
- method @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public void onMediaStoreDownloadsDeleted(@NonNull android.util.LongSparseArray<java.lang.String>);
- field public static final String ACTION_DOWNLOAD_COMPLETED = "android.intent.action.DOWNLOAD_COMPLETED";
- }
-
- public abstract class InstantAppResolverService extends android.app.Service {
- ctor public InstantAppResolverService();
- method public final void attachBaseContext(android.content.Context);
- method public final android.os.IBinder onBind(android.content.Intent);
- method @Deprecated public void onGetInstantAppIntentFilter(@Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
- method @Deprecated public void onGetInstantAppIntentFilter(@NonNull android.content.Intent, @Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
- method @Deprecated public void onGetInstantAppIntentFilter(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
- method @MainThread public void onGetInstantAppIntentFilter(@NonNull android.content.pm.InstantAppRequestInfo, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
- method @Deprecated public void onGetInstantAppResolveInfo(@Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
- method @Deprecated public void onGetInstantAppResolveInfo(@NonNull android.content.Intent, @Nullable int[], @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
- method @Deprecated public void onGetInstantAppResolveInfo(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, @NonNull String, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
- method @MainThread public void onGetInstantAppResolveInfo(@NonNull android.content.pm.InstantAppRequestInfo, @NonNull android.app.InstantAppResolverService.InstantAppResolutionCallback);
- }
-
- public static final class InstantAppResolverService.InstantAppResolutionCallback {
- method public void onInstantAppResolveInfo(java.util.List<android.content.pm.InstantAppResolveInfo>);
- }
-
- public class KeyguardManager {
- method public android.content.Intent createConfirmFactoryResetCredentialIntent(CharSequence, CharSequence, CharSequence);
- method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public int getMinLockLength(boolean, int);
- method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public boolean getPrivateNotificationsAllowed();
- method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean isValidLockPasswordComplexity(int, @NonNull byte[], int);
- method @RequiresPermission(android.Manifest.permission.SHOW_KEYGUARD_MESSAGE) public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable CharSequence, @Nullable android.app.KeyguardManager.KeyguardDismissCallback);
- method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean setLock(int, @NonNull byte[], int);
- method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public void setPrivateNotificationsAllowed(boolean);
- }
-
- public class Notification implements android.os.Parcelable {
- field public static final String CATEGORY_CAR_EMERGENCY = "car_emergency";
- field public static final String CATEGORY_CAR_INFORMATION = "car_information";
- field public static final String CATEGORY_CAR_WARNING = "car_warning";
- field @RequiresPermission(android.Manifest.permission.NOTIFICATION_DURING_SETUP) public static final String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup";
- field @RequiresPermission(android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME) public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
- field public static final int FLAG_AUTOGROUP_SUMMARY = 1024; // 0x400
- }
-
- public static final class Notification.TvExtender implements android.app.Notification.Extender {
- ctor public Notification.TvExtender();
- ctor public Notification.TvExtender(android.app.Notification);
- method public android.app.Notification.Builder extend(android.app.Notification.Builder);
- method public String getChannelId();
- method public android.app.PendingIntent getContentIntent();
- method public android.app.PendingIntent getDeleteIntent();
- method public boolean getSuppressShowOverApps();
- method public boolean isAvailableOnTv();
- method public android.app.Notification.TvExtender setChannel(String);
- method public android.app.Notification.TvExtender setChannelId(String);
- method public android.app.Notification.TvExtender setContentIntent(android.app.PendingIntent);
- method public android.app.Notification.TvExtender setDeleteIntent(android.app.PendingIntent);
- method public android.app.Notification.TvExtender setSuppressShowOverApps(boolean);
- }
-
- public final class NotificationChannel implements android.os.Parcelable {
- method public int getUserLockedFields();
- method public boolean isDeleted();
- method public void populateFromXml(org.xmlpull.v1.XmlPullParser);
- method public void setBlockable(boolean);
- method public org.json.JSONObject toJson() throws org.json.JSONException;
- method public void writeXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
- field public static final int USER_LOCKED_SOUND = 32; // 0x20
- }
-
- public final class NotificationChannelGroup implements android.os.Parcelable {
- method public org.json.JSONObject toJson() throws org.json.JSONException;
- }
-
- public class NotificationManager {
- method @NonNull public java.util.List<java.lang.String> getAllowedAssistantAdjustments();
- method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public java.util.List<android.content.ComponentName> getEnabledNotificationListeners();
- method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
- method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
- method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean, boolean);
- field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL = "android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL";
- field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_OPEN_NOTIFICATION_HANDLER_PANEL = "android.app.action.OPEN_NOTIFICATION_HANDLER_PANEL";
- field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL = "android.app.action.TOGGLE_NOTIFICATION_HANDLER_PANEL";
- }
-
- public final class RuntimeAppOpAccessMessage implements android.os.Parcelable {
- ctor public RuntimeAppOpAccessMessage(@IntRange(from=0L) int, @IntRange(from=0L) int, @NonNull String, @Nullable String, @NonNull String, int);
- method public int describeContents();
- method @Nullable public String getAttributionTag();
- method @NonNull public String getMessage();
- method @NonNull public String getOp();
- method @NonNull public String getPackageName();
- method public int getSamplingStrategy();
- method @IntRange(from=0L) public int getUid();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.RuntimeAppOpAccessMessage> CREATOR;
- }
-
- public class SearchManager implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
- method public void launchAssist(@Nullable android.os.Bundle);
- }
-
- 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(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;
- method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setBroadcastSubscriber(android.app.PendingIntent, long, long) throws android.app.StatsManager.StatsUnavailableException;
- 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 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";
- field public static final String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
- field public static final String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
- field public static final String EXTRA_STATS_DIMENSIONS_VALUE = "android.app.extra.STATS_DIMENSIONS_VALUE";
- field public static final String EXTRA_STATS_SUBSCRIPTION_ID = "android.app.extra.STATS_SUBSCRIPTION_ID";
- field public static final String EXTRA_STATS_SUBSCRIPTION_RULE_ID = "android.app.extra.STATS_SUBSCRIPTION_RULE_ID";
- field public static final int PULL_SKIP = 1; // 0x1
- field public static final int PULL_SUCCESS = 0; // 0x0
- }
-
- 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 setCoolDownMillis(long);
- method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setTimeoutMillis(long);
- }
-
- public static interface StatsManager.StatsPullAtomCallback {
- method public int onPullAtom(int, @NonNull java.util.List<android.util.StatsEvent>);
- }
-
- public static class StatsManager.StatsUnavailableException extends android.util.AndroidException {
- ctor public StatsManager.StatsUnavailableException(String);
- ctor public StatsManager.StatsUnavailableException(String, Throwable);
- }
-
- public class StatusBarManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
- method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
- }
-
- public static final class StatusBarManager.DisableInfo {
- method public boolean areAllComponentsEnabled();
- method public boolean isNavigateToHomeDisabled();
- method public boolean isNotificationPeekingDisabled();
- method public boolean isRecentsDisabled();
- method public boolean isSearchDisabled();
- method public boolean isStatusBarExpansionDisabled();
- }
-
- public final class SystemServiceRegistry {
- method public static <TServiceClass> void registerContextAwareService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.ContextAwareServiceProducerWithBinder<TServiceClass>);
- method public static <TServiceClass> void registerContextAwareService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.ContextAwareServiceProducerWithoutBinder<TServiceClass>);
- method public static <TServiceClass> void registerStaticService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.StaticServiceProducerWithBinder<TServiceClass>);
- method public static <TServiceClass> void registerStaticService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.StaticServiceProducerWithoutBinder<TServiceClass>);
- }
-
- public static interface SystemServiceRegistry.ContextAwareServiceProducerWithBinder<TServiceClass> {
- method @NonNull public TServiceClass createService(@NonNull android.content.Context, @NonNull android.os.IBinder);
- }
-
- public static interface SystemServiceRegistry.ContextAwareServiceProducerWithoutBinder<TServiceClass> {
- method @NonNull public TServiceClass createService(@NonNull android.content.Context);
- }
-
- public static interface SystemServiceRegistry.StaticServiceProducerWithBinder<TServiceClass> {
- method @NonNull public TServiceClass createService(@NonNull android.os.IBinder);
- }
-
- public static interface SystemServiceRegistry.StaticServiceProducerWithoutBinder<TServiceClass> {
- method @NonNull public TServiceClass createService();
- }
-
- public class UiModeManager {
- method @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) public void enableCarMode(@IntRange(from=0) int, int);
- field public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED = "android.app.action.ENTER_CAR_MODE_PRIORITIZED";
- field public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED = "android.app.action.EXIT_CAR_MODE_PRIORITIZED";
- field public static final int DEFAULT_PRIORITY = 0; // 0x0
- field public static final String EXTRA_CALLING_PACKAGE = "android.app.extra.CALLING_PACKAGE";
- field public static final String EXTRA_PRIORITY = "android.app.extra.PRIORITY";
- }
-
- public final class Vr2dDisplayProperties implements android.os.Parcelable {
- ctor public Vr2dDisplayProperties(int, int, int);
- method public int describeContents();
- method public void dump(@NonNull java.io.PrintWriter, @NonNull String);
- method public int getAddedFlags();
- method public int getDpi();
- method public int getHeight();
- method public int getRemovedFlags();
- method public int getWidth();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.Vr2dDisplayProperties> CREATOR;
- field public static final int FLAG_VIRTUAL_DISPLAY_ENABLED = 1; // 0x1
- }
-
- public static final class Vr2dDisplayProperties.Builder {
- ctor public Vr2dDisplayProperties.Builder();
- method @NonNull public android.app.Vr2dDisplayProperties.Builder addFlags(int);
- method @NonNull public android.app.Vr2dDisplayProperties build();
- method @NonNull public android.app.Vr2dDisplayProperties.Builder removeFlags(int);
- method @NonNull public android.app.Vr2dDisplayProperties.Builder setDimensions(int, int, int);
- method @NonNull public android.app.Vr2dDisplayProperties.Builder setEnabled(boolean);
- }
-
- public class VrManager {
- method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public int getVr2dDisplayId();
- method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public boolean isPersistentVrModeEnabled();
- method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public boolean isVrModeEnabled();
- method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void registerVrStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.app.VrStateCallback);
- method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setAndBindVrCompositor(android.content.ComponentName);
- method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setPersistentVrModeEnabled(boolean);
- method @RequiresPermission("android.permission.ACCESS_VR_MANAGER") public void setStandbyEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVr2dDisplayProperties(@NonNull android.app.Vr2dDisplayProperties);
- method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVrInputMethod(@Nullable android.content.ComponentName);
- method @RequiresPermission(anyOf={android.Manifest.permission.RESTRICTED_VR_ACCESS, "android.permission.ACCESS_VR_STATE"}) public void unregisterVrStateCallback(@NonNull android.app.VrStateCallback);
- }
-
- public abstract class VrStateCallback {
- ctor public VrStateCallback();
- method public void onPersistentVrStateChanged(boolean);
- method public void onVrStateChanged(boolean);
- }
-
- public final class WallpaperColors implements android.os.Parcelable {
- ctor public WallpaperColors(@NonNull android.graphics.Color, @Nullable android.graphics.Color, @Nullable android.graphics.Color, int);
- method public int getColorHints();
- field public static final int HINT_SUPPORTS_DARK_TEXT = 1; // 0x1
- field public static final int HINT_SUPPORTS_DARK_THEME = 2; // 0x2
- }
-
- public final class WallpaperInfo implements android.os.Parcelable {
- method public boolean supportsAmbientMode();
- }
-
- public class WallpaperManager {
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void clearWallpaper(int, int);
- method public void setDisplayOffset(android.os.IBinder, int, int);
- method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponent(android.content.ComponentName);
- }
-
-}
-
-package android.app.admin {
-
- public class DevicePolicyKeyguardService extends android.app.Service {
- ctor public DevicePolicyKeyguardService();
- method @Nullable public void dismiss();
- method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage onCreateKeyguardSurface(@NonNull android.os.IBinder);
- }
-
- public class DevicePolicyManager {
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwnerNameOnAnyUser();
- method @Nullable public CharSequence getDeviceOwnerOrganizationName();
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getDeviceOwnerUser();
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
- method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserProvisioningState();
- method public boolean isDeviceManaged();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedKiosk();
- method public boolean isSecondaryLockscreenEnabled(@NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUnattendedManagedKiosk();
- method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long);
- method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
- method @Deprecated @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
- method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
- method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
- field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
- field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
- field public static final String ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE = "android.app.action.BIND_SECONDARY_LOCKSCREEN_SERVICE";
- field public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
- field public static final String ACTION_PROVISION_FINANCED_DEVICE = "android.app.action.PROVISION_FINANCED_DEVICE";
- field public static final String ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE = "android.app.action.PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE";
- field @RequiresPermission(android.Manifest.permission.MANAGE_FACTORY_RESET_PROTECTION) public static final String ACTION_RESET_PROTECTION_POLICY_CHANGED = "android.app.action.RESET_PROTECTION_POLICY_CHANGED";
- field public static final String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
- field public static final String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE";
- field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
- field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
- field public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
- field public static final String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
- field public static final String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
- field public static final String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
- field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
- field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1
- field public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3
- field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2
- field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0
- field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
- field public static final int STATE_USER_PROFILE_FINALIZED = 5; // 0x5
- field public static final int STATE_USER_SETUP_COMPLETE = 2; // 0x2
- field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
- field public static final int STATE_USER_SETUP_INCOMPLETE = 1; // 0x1
- field public static final int STATE_USER_UNMANAGED = 0; // 0x0
- }
-
- public final class SystemUpdatePolicy implements android.os.Parcelable {
- method public android.app.admin.SystemUpdatePolicy.InstallationOption getInstallationOptionAt(long);
- field public static final int TYPE_PAUSE = 4; // 0x4
- }
-
- public static class SystemUpdatePolicy.InstallationOption {
- method public long getEffectiveTime();
- method public int getType();
- }
-
-}
-
-package android.app.appsearch {
-
- public class AppSearchManagerFrameworkInitializer {
- method public static void initialize();
- }
-
-}
-
-package android.app.assist {
-
- public static class AssistStructure.ViewNode {
- ctor public AssistStructure.ViewNode();
- }
-
-}
-
-package android.app.backup {
-
- public class BackupDataInput {
- ctor public BackupDataInput(java.io.FileDescriptor);
- }
-
- public class BackupDataOutput {
- ctor public BackupDataOutput(java.io.FileDescriptor);
- ctor public BackupDataOutput(java.io.FileDescriptor, long);
- }
-
- public class BackupManager {
- method @RequiresPermission(android.Manifest.permission.BACKUP) public void backupNow();
- method @RequiresPermission(android.Manifest.permission.BACKUP) public android.app.backup.RestoreSession beginRestoreSession();
- method @RequiresPermission(android.Manifest.permission.BACKUP) public void cancelBackups();
- method @RequiresPermission(android.Manifest.permission.BACKUP) public void excludeKeysFromRestore(@NonNull String, @NonNull java.util.List<java.lang.String>);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public long getAvailableRestoreToken(String);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getConfigurationIntent(String);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public String getCurrentTransport();
- method @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.ComponentName getCurrentTransportComponent();
- method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getDataManagementIntent(String);
- method @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public CharSequence getDataManagementIntentLabel(@NonNull String);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public String getDataManagementLabel(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public String getDestinationString(String);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public boolean isAppEligibleForBackup(String);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public boolean isBackupEnabled();
- method @RequiresPermission(android.Manifest.permission.BACKUP) public boolean isBackupServiceActive(android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public String[] listAllTransports();
- method @RequiresPermission(android.Manifest.permission.BACKUP) public int requestBackup(String[], android.app.backup.BackupObserver);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public int requestBackup(String[], android.app.backup.BackupObserver, android.app.backup.BackupManagerMonitor, int);
- method @Deprecated public int requestRestore(android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
- method @Deprecated @RequiresPermission(android.Manifest.permission.BACKUP) public String selectBackupTransport(String);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public void selectBackupTransport(android.content.ComponentName, android.app.backup.SelectBackupTransportCallback);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public void setAncestralSerialNumber(long);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public void setAutoRestore(boolean);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public void setBackupEnabled(boolean);
- method @Deprecated @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(@NonNull android.content.ComponentName, @NonNull String, @Nullable android.content.Intent, @NonNull String, @Nullable android.content.Intent, @Nullable String);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(@NonNull android.content.ComponentName, @NonNull String, @Nullable android.content.Intent, @NonNull String, @Nullable android.content.Intent, @Nullable CharSequence);
- field public static final int ERROR_AGENT_FAILURE = -1003; // 0xfffffc15
- field public static final int ERROR_BACKUP_CANCELLED = -2003; // 0xfffff82d
- field public static final int ERROR_BACKUP_NOT_ALLOWED = -2001; // 0xfffff82f
- field public static final int ERROR_PACKAGE_NOT_FOUND = -2002; // 0xfffff82e
- field public static final int ERROR_TRANSPORT_ABORTED = -1000; // 0xfffffc18
- field public static final int ERROR_TRANSPORT_INVALID = -2; // 0xfffffffe
- field public static final int ERROR_TRANSPORT_PACKAGE_REJECTED = -1002; // 0xfffffc16
- field public static final int ERROR_TRANSPORT_QUOTA_EXCEEDED = -1005; // 0xfffffc13
- field public static final int ERROR_TRANSPORT_UNAVAILABLE = -1; // 0xffffffff
- field public static final int FLAG_NON_INCREMENTAL_BACKUP = 1; // 0x1
- field public static final String PACKAGE_MANAGER_SENTINEL = "@pm@";
- field public static final int SUCCESS = 0; // 0x0
- }
-
- public class BackupManagerMonitor {
- ctor public BackupManagerMonitor();
- method public void onEvent(android.os.Bundle);
- field public static final String EXTRA_LOG_CANCEL_ALL = "android.app.backup.extra.LOG_CANCEL_ALL";
- field public static final String EXTRA_LOG_EVENT_CATEGORY = "android.app.backup.extra.LOG_EVENT_CATEGORY";
- field public static final String EXTRA_LOG_EVENT_ID = "android.app.backup.extra.LOG_EVENT_ID";
- field public static final String EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_FULL_VERSION";
- field public static final String EXTRA_LOG_EVENT_PACKAGE_NAME = "android.app.backup.extra.LOG_EVENT_PACKAGE_NAME";
- field @Deprecated public static final String EXTRA_LOG_EVENT_PACKAGE_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_VERSION";
- field public static final String EXTRA_LOG_EXCEPTION_FULL_BACKUP = "android.app.backup.extra.LOG_EXCEPTION_FULL_BACKUP";
- field public static final String EXTRA_LOG_ILLEGAL_KEY = "android.app.backup.extra.LOG_ILLEGAL_KEY";
- field public static final String EXTRA_LOG_MANIFEST_PACKAGE_NAME = "android.app.backup.extra.LOG_MANIFEST_PACKAGE_NAME";
- field public static final String EXTRA_LOG_OLD_VERSION = "android.app.backup.extra.LOG_OLD_VERSION";
- field public static final String EXTRA_LOG_POLICY_ALLOW_APKS = "android.app.backup.extra.LOG_POLICY_ALLOW_APKS";
- field public static final String EXTRA_LOG_PREFLIGHT_ERROR = "android.app.backup.extra.LOG_PREFLIGHT_ERROR";
- field public static final String EXTRA_LOG_RESTORE_ANYWAY = "android.app.backup.extra.LOG_RESTORE_ANYWAY";
- field public static final String EXTRA_LOG_RESTORE_VERSION = "android.app.backup.extra.LOG_RESTORE_VERSION";
- field public static final String EXTRA_LOG_WIDGET_PACKAGE_NAME = "android.app.backup.extra.LOG_WIDGET_PACKAGE_NAME";
- field public static final int LOG_EVENT_CATEGORY_AGENT = 2; // 0x2
- field public static final int LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY = 3; // 0x3
- field public static final int LOG_EVENT_CATEGORY_TRANSPORT = 1; // 0x1
- field public static final int LOG_EVENT_ID_APK_NOT_INSTALLED = 40; // 0x28
- field public static final int LOG_EVENT_ID_APP_HAS_NO_AGENT = 28; // 0x1c
- field public static final int LOG_EVENT_ID_BACKUP_DISABLED = 13; // 0xd
- field public static final int LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK = 41; // 0x29
- field public static final int LOG_EVENT_ID_CANT_FIND_AGENT = 30; // 0x1e
- field public static final int LOG_EVENT_ID_CORRUPT_MANIFEST = 46; // 0x2e
- field public static final int LOG_EVENT_ID_DEVICE_NOT_PROVISIONED = 14; // 0xe
- field public static final int LOG_EVENT_ID_ERROR_PREFLIGHT = 16; // 0x10
- field public static final int LOG_EVENT_ID_EXCEPTION_FULL_BACKUP = 19; // 0x13
- field public static final int LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE = 43; // 0x2b
- field public static final int LOG_EVENT_ID_FULL_BACKUP_CANCEL = 4; // 0x4
- field public static final int LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE = 39; // 0x27
- field public static final int LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH = 37; // 0x25
- field public static final int LOG_EVENT_ID_FULL_RESTORE_TIMEOUT = 45; // 0x2d
- field public static final int LOG_EVENT_ID_ILLEGAL_KEY = 5; // 0x5
- field public static final int LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL = 21; // 0x15
- field public static final int LOG_EVENT_ID_KEY_VALUE_RESTORE_TIMEOUT = 31; // 0x1f
- field public static final int LOG_EVENT_ID_LOST_TRANSPORT = 25; // 0x19
- field public static final int LOG_EVENT_ID_MISSING_SIGNATURE = 42; // 0x2a
- field public static final int LOG_EVENT_ID_NO_DATA_TO_SEND = 7; // 0x7
- field public static final int LOG_EVENT_ID_NO_PACKAGES = 49; // 0x31
- field public static final int LOG_EVENT_ID_NO_PM_METADATA_RECEIVED = 23; // 0x17
- field public static final int LOG_EVENT_ID_NO_RESTORE_METADATA_AVAILABLE = 22; // 0x16
- field public static final int LOG_EVENT_ID_PACKAGE_INELIGIBLE = 9; // 0x9
- field public static final int LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT = 10; // 0xa
- field public static final int LOG_EVENT_ID_PACKAGE_NOT_FOUND = 12; // 0xc
- field public static final int LOG_EVENT_ID_PACKAGE_NOT_PRESENT = 26; // 0x1a
- field public static final int LOG_EVENT_ID_PACKAGE_STOPPED = 11; // 0xb
- field public static final int LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT = 15; // 0xf
- field public static final int LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA = 24; // 0x18
- field public static final int LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT = 18; // 0x12
- field public static final int LOG_EVENT_ID_RESTORE_ANY_VERSION = 34; // 0x22
- field public static final int LOG_EVENT_ID_RESTORE_VERSION_HIGHER = 27; // 0x1b
- field public static final int LOG_EVENT_ID_SIGNATURE_MISMATCH = 29; // 0x1d
- field public static final int LOG_EVENT_ID_SYSTEM_APP_NO_AGENT = 38; // 0x26
- field public static final int LOG_EVENT_ID_TRANSPORT_IS_NULL = 50; // 0x32
- field public static final int LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED = 51; // 0x33
- field public static final int LOG_EVENT_ID_UNKNOWN_VERSION = 44; // 0x2c
- field public static final int LOG_EVENT_ID_VERSIONS_MATCH = 35; // 0x23
- field public static final int LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER = 36; // 0x24
- field public static final int LOG_EVENT_ID_WIDGET_METADATA_MISMATCH = 47; // 0x2f
- field public static final int LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION = 48; // 0x30
- }
-
- public abstract class BackupObserver {
- ctor public BackupObserver();
- method public void backupFinished(int);
- method public void onResult(String, int);
- method public void onUpdate(String, android.app.backup.BackupProgress);
- }
-
- public class BackupProgress implements android.os.Parcelable {
- ctor public BackupProgress(long, long);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.backup.BackupProgress> CREATOR;
- field public final long bytesExpected;
- field public final long bytesTransferred;
- }
-
- public class BackupTransport {
- ctor public BackupTransport();
- method public int abortFullRestore();
- method public void cancelFullBackup();
- method public int checkFullBackupSize(long);
- method public int clearBackupData(android.content.pm.PackageInfo);
- method public android.content.Intent configurationIntent();
- method public String currentDestinationString();
- method public android.content.Intent dataManagementIntent();
- method @Nullable public CharSequence dataManagementIntentLabel();
- method @Deprecated @Nullable public String dataManagementLabel();
- method public int finishBackup();
- method public void finishRestore();
- method public android.app.backup.RestoreSet[] getAvailableRestoreSets();
- method public long getBackupQuota(String, boolean);
- method public android.os.IBinder getBinder();
- method public long getCurrentRestoreSet();
- method public int getNextFullRestoreDataChunk(android.os.ParcelFileDescriptor);
- method public int getRestoreData(android.os.ParcelFileDescriptor);
- method public int getTransportFlags();
- method public int initializeDevice();
- method public boolean isAppEligibleForBackup(android.content.pm.PackageInfo, boolean);
- method public String name();
- method public android.app.backup.RestoreDescription nextRestorePackage();
- method public int performBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor, int);
- method public int performBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor);
- method public int performFullBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor, int);
- method public int performFullBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor);
- method public long requestBackupTime();
- method public long requestFullBackupTime();
- method public int sendBackupData(int);
- method public int startRestore(long, android.content.pm.PackageInfo[]);
- method public String transportDirName();
- field public static final int AGENT_ERROR = -1003; // 0xfffffc15
- field public static final int AGENT_UNKNOWN = -1004; // 0xfffffc14
- field public static final String EXTRA_TRANSPORT_REGISTRATION = "android.app.backup.extra.TRANSPORT_REGISTRATION";
- field public static final int FLAG_DATA_NOT_CHANGED = 8; // 0x8
- field public static final int FLAG_INCREMENTAL = 2; // 0x2
- field public static final int FLAG_NON_INCREMENTAL = 4; // 0x4
- field public static final int FLAG_USER_INITIATED = 1; // 0x1
- field public static final int NO_MORE_DATA = -1; // 0xffffffff
- field public static final int TRANSPORT_ERROR = -1000; // 0xfffffc18
- field public static final int TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED = -1006; // 0xfffffc12
- field public static final int TRANSPORT_NOT_INITIALIZED = -1001; // 0xfffffc17
- field public static final int TRANSPORT_OK = 0; // 0x0
- field public static final int TRANSPORT_PACKAGE_REJECTED = -1002; // 0xfffffc16
- field public static final int TRANSPORT_QUOTA_EXCEEDED = -1005; // 0xfffffc13
- }
-
- public class RestoreDescription implements android.os.Parcelable {
- ctor public RestoreDescription(String, int);
- method public int describeContents();
- method public int getDataType();
- method public String getPackageName();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.backup.RestoreDescription> CREATOR;
- field public static final android.app.backup.RestoreDescription NO_MORE_PACKAGES;
- field public static final int TYPE_FULL_STREAM = 2; // 0x2
- field public static final int TYPE_KEY_VALUE = 1; // 0x1
- }
-
- public abstract class RestoreObserver {
- method public void restoreSetsAvailable(android.app.backup.RestoreSet[]);
- }
-
- public class RestoreSession {
- method public void endRestoreSession();
- method public int getAvailableRestoreSets(android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
- method public int getAvailableRestoreSets(android.app.backup.RestoreObserver);
- method public int restoreAll(long, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
- method public int restoreAll(long, android.app.backup.RestoreObserver);
- method public int restorePackage(String, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
- method public int restorePackage(String, android.app.backup.RestoreObserver);
- method public int restorePackages(long, @Nullable android.app.backup.RestoreObserver, @NonNull java.util.Set<java.lang.String>, @Nullable android.app.backup.BackupManagerMonitor);
- method public int restorePackages(long, @Nullable android.app.backup.RestoreObserver, @NonNull java.util.Set<java.lang.String>);
- }
-
- public class RestoreSet implements android.os.Parcelable {
- ctor public RestoreSet();
- ctor public RestoreSet(String, String, long);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.backup.RestoreSet> CREATOR;
- field public String device;
- field public String name;
- field public long token;
- }
-
- public abstract class SelectBackupTransportCallback {
- ctor public SelectBackupTransportCallback();
- method public void onFailure(int);
- method public void onSuccess(String);
- }
-
-}
-
-package android.app.compat {
-
- public final class CompatChanges {
- method public static boolean isChangeEnabled(long);
- method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, @NonNull String, @NonNull android.os.UserHandle);
- method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, int);
- }
-
-}
-
-package android.app.contentsuggestions {
-
- public final class ClassificationsRequest implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.os.Bundle getExtras();
- method @NonNull public java.util.List<android.app.contentsuggestions.ContentSelection> getSelections();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ClassificationsRequest> CREATOR;
- }
-
- public static final class ClassificationsRequest.Builder {
- ctor public ClassificationsRequest.Builder(@NonNull java.util.List<android.app.contentsuggestions.ContentSelection>);
- method @NonNull public android.app.contentsuggestions.ClassificationsRequest build();
- method @NonNull public android.app.contentsuggestions.ClassificationsRequest.Builder setExtras(@NonNull android.os.Bundle);
- }
-
- public final class ContentClassification implements android.os.Parcelable {
- ctor public ContentClassification(@NonNull String, @NonNull android.os.Bundle);
- method public int describeContents();
- method @NonNull public android.os.Bundle getExtras();
- method @NonNull public String getId();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentClassification> CREATOR;
- }
-
- public final class ContentSelection implements android.os.Parcelable {
- ctor public ContentSelection(@NonNull String, @NonNull android.os.Bundle);
- method public int describeContents();
- method @NonNull public android.os.Bundle getExtras();
- method @NonNull public String getId();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.contentsuggestions.ContentSelection> CREATOR;
- }
-
- public final class ContentSuggestionsManager {
- method public void classifyContentSelections(@NonNull android.app.contentsuggestions.ClassificationsRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback);
- method public boolean isEnabled();
- method public void notifyInteraction(@NonNull String, @NonNull android.os.Bundle);
- method public void provideContextImage(@NonNull android.graphics.Bitmap, @NonNull android.os.Bundle);
- method public void provideContextImage(int, @NonNull android.os.Bundle);
- method public void suggestContentSelections(@NonNull android.app.contentsuggestions.SelectionsRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.contentsuggestions.ContentSuggestionsManager.SelectionsCallback);
- }
-
- public static interface ContentSuggestionsManager.ClassificationsCallback {
- method public void onContentClassificationsAvailable(int, @NonNull java.util.List<android.app.contentsuggestions.ContentClassification>);
- }
-
- public static interface ContentSuggestionsManager.SelectionsCallback {
- method public void onContentSelectionsAvailable(int, @NonNull java.util.List<android.app.contentsuggestions.ContentSelection>);
- }
-
- public final class SelectionsRequest implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.os.Bundle getExtras();
- method @Nullable public android.graphics.Point getInterestPoint();
- method public int getTaskId();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.contentsuggestions.SelectionsRequest> CREATOR;
- }
-
- public static final class SelectionsRequest.Builder {
- ctor public SelectionsRequest.Builder(int);
- method @NonNull public android.app.contentsuggestions.SelectionsRequest build();
- method @NonNull public android.app.contentsuggestions.SelectionsRequest.Builder setExtras(@NonNull android.os.Bundle);
- method @NonNull public android.app.contentsuggestions.SelectionsRequest.Builder setInterestPoint(@NonNull android.graphics.Point);
- }
-
-}
-
-package android.app.job {
-
- public abstract class JobScheduler {
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public abstract int scheduleAsPackage(@NonNull android.app.job.JobInfo, @NonNull String, int, String);
- }
-
- public class JobSchedulerFrameworkInitializer {
- method public static void registerServiceWrappers();
- }
-
-}
-
-package android.app.prediction {
-
- public final class AppPredictionContext implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public android.os.Bundle getExtras();
- method @NonNull public String getPackageName();
- method @IntRange(from=0) public int getPredictedTargetCount();
- method @NonNull public String getUiSurface();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppPredictionContext> CREATOR;
- }
-
- public static final class AppPredictionContext.Builder {
- ctor public AppPredictionContext.Builder(@NonNull android.content.Context);
- method @NonNull public android.app.prediction.AppPredictionContext build();
- method @NonNull public android.app.prediction.AppPredictionContext.Builder setExtras(@Nullable android.os.Bundle);
- method @NonNull public android.app.prediction.AppPredictionContext.Builder setPredictedTargetCount(@IntRange(from=0) int);
- method @NonNull public android.app.prediction.AppPredictionContext.Builder setUiSurface(@NonNull String);
- }
-
- public final class AppPredictionManager {
- method @NonNull public android.app.prediction.AppPredictor createAppPredictionSession(@NonNull android.app.prediction.AppPredictionContext);
- }
-
- public final class AppPredictionSessionId implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppPredictionSessionId> CREATOR;
- }
-
- public final class AppPredictor {
- method public void destroy();
- method public void notifyAppTargetEvent(@NonNull android.app.prediction.AppTargetEvent);
- method public void notifyLaunchLocationShown(@NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
- method public void registerPredictionUpdates(@NonNull java.util.concurrent.Executor, @NonNull android.app.prediction.AppPredictor.Callback);
- method public void requestPredictionUpdate();
- method @Nullable public void sortTargets(@NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
- method public void unregisterPredictionUpdates(@NonNull android.app.prediction.AppPredictor.Callback);
- }
-
- public static interface AppPredictor.Callback {
- method public void onTargetsAvailable(@NonNull java.util.List<android.app.prediction.AppTarget>);
- }
-
- public final class AppTarget implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public String getClassName();
- method @NonNull public android.app.prediction.AppTargetId getId();
- method @NonNull public String getPackageName();
- method @IntRange(from=0) public int getRank();
- method @Nullable public android.content.pm.ShortcutInfo getShortcutInfo();
- method @NonNull public android.os.UserHandle getUser();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppTarget> CREATOR;
- }
-
- public static final class AppTarget.Builder {
- ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull String, @NonNull android.os.UserHandle);
- ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull android.content.pm.ShortcutInfo);
- method @NonNull public android.app.prediction.AppTarget build();
- method @NonNull public android.app.prediction.AppTarget.Builder setClassName(@NonNull String);
- method @NonNull public android.app.prediction.AppTarget.Builder setRank(@IntRange(from=0) int);
- }
-
- public final class AppTargetEvent implements android.os.Parcelable {
- method public int describeContents();
- method public int getAction();
- method @Nullable public String getLaunchLocation();
- method @Nullable public android.app.prediction.AppTarget getTarget();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int ACTION_DISMISS = 2; // 0x2
- field public static final int ACTION_LAUNCH = 1; // 0x1
- field public static final int ACTION_PIN = 3; // 0x3
- field public static final int ACTION_UNPIN = 4; // 0x4
- field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetEvent> CREATOR;
- }
-
- public static final class AppTargetEvent.Builder {
- ctor public AppTargetEvent.Builder(@Nullable android.app.prediction.AppTarget, int);
- method @NonNull public android.app.prediction.AppTargetEvent build();
- method @NonNull public android.app.prediction.AppTargetEvent.Builder setLaunchLocation(@Nullable String);
- }
-
- public final class AppTargetId implements android.os.Parcelable {
- ctor public AppTargetId(@NonNull String);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppTargetId> CREATOR;
- }
-
-}
-
-package android.app.role {
-
- public interface OnRoleHoldersChangedListener {
- method public void onRoleHoldersChanged(@NonNull String, @NonNull android.os.UserHandle);
- }
-
- public abstract class RoleControllerService extends android.app.Service {
- ctor public RoleControllerService();
- method @WorkerThread public abstract boolean onAddRoleHolder(@NonNull String, @NonNull String, int);
- method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method @WorkerThread public abstract boolean onClearRoleHolders(@NonNull String, int);
- method @WorkerThread public abstract boolean onGrantDefaultRoles();
- method @Deprecated public abstract boolean onIsApplicationQualifiedForRole(@NonNull String, @NonNull String);
- method public boolean onIsApplicationVisibleForRole(@NonNull String, @NonNull String);
- method public abstract boolean onIsRoleVisible(@NonNull String);
- method @WorkerThread public abstract boolean onRemoveRoleHolder(@NonNull String, @NonNull String, int);
- field public static final String SERVICE_INTERFACE = "android.app.role.RoleControllerService";
- }
-
- public final class RoleManager {
- method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
- method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
- field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1
- }
-
-}
-
-package android.app.time {
-
- public final class TimeManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public void addTimeZoneDetectorListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.time.TimeManager.TimeZoneDetectorListener);
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public android.app.time.TimeZoneCapabilitiesAndConfig getTimeZoneCapabilitiesAndConfig();
- method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public void removeTimeZoneDetectorListener(@NonNull android.app.time.TimeManager.TimeZoneDetectorListener);
- method @RequiresPermission(android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION) public boolean updateTimeZoneConfiguration(@NonNull android.app.time.TimeZoneConfiguration);
- }
-
- @java.lang.FunctionalInterface public static interface TimeManager.TimeZoneDetectorListener {
- method public void onChange();
- }
-
- public final class TimeZoneCapabilities implements android.os.Parcelable {
- method public int describeContents();
- method public int getConfigureAutoDetectionEnabledCapability();
- method public int getConfigureGeoDetectionEnabledCapability();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int CAPABILITY_NOT_ALLOWED = 20; // 0x14
- field public static final int CAPABILITY_NOT_APPLICABLE = 30; // 0x1e
- field public static final int CAPABILITY_NOT_SUPPORTED = 10; // 0xa
- field public static final int CAPABILITY_POSSESSED = 40; // 0x28
- field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneCapabilities> CREATOR;
- }
-
- public final class TimeZoneCapabilitiesAndConfig implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.app.time.TimeZoneCapabilities getCapabilities();
- method @NonNull public android.app.time.TimeZoneConfiguration getConfiguration();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneCapabilitiesAndConfig> CREATOR;
- }
-
- public final class TimeZoneConfiguration implements android.os.Parcelable {
- method public int describeContents();
- method public boolean isAutoDetectionEnabled();
- method public boolean isGeoDetectionEnabled();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.time.TimeZoneConfiguration> CREATOR;
- }
-
- public static final class TimeZoneConfiguration.Builder {
- ctor public TimeZoneConfiguration.Builder();
- ctor public TimeZoneConfiguration.Builder(@NonNull android.app.time.TimeZoneConfiguration);
- method @NonNull public android.app.time.TimeZoneConfiguration build();
- method @NonNull public android.app.time.TimeZoneConfiguration.Builder setAutoDetectionEnabled(boolean);
- method @NonNull public android.app.time.TimeZoneConfiguration.Builder setGeoDetectionEnabled(boolean);
- }
-
-}
-
-package android.app.usage {
-
- public final class CacheQuotaHint implements android.os.Parcelable {
- ctor public CacheQuotaHint(@NonNull android.app.usage.CacheQuotaHint.Builder);
- method public int describeContents();
- method public long getQuota();
- method public int getUid();
- method @Nullable public android.app.usage.UsageStats getUsageStats();
- method @Nullable public String getVolumeUuid();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.usage.CacheQuotaHint> CREATOR;
- field public static final long QUOTA_NOT_SET = -1L; // 0xffffffffffffffffL
- }
-
- public static final class CacheQuotaHint.Builder {
- ctor public CacheQuotaHint.Builder();
- ctor public CacheQuotaHint.Builder(@NonNull android.app.usage.CacheQuotaHint);
- method @NonNull public android.app.usage.CacheQuotaHint build();
- method @NonNull public android.app.usage.CacheQuotaHint.Builder setQuota(long);
- method @NonNull public android.app.usage.CacheQuotaHint.Builder setUid(int);
- method @NonNull public android.app.usage.CacheQuotaHint.Builder setUsageStats(@Nullable android.app.usage.UsageStats);
- method @NonNull public android.app.usage.CacheQuotaHint.Builder setVolumeUuid(@Nullable String);
- }
-
- public abstract class CacheQuotaService extends android.app.Service {
- ctor public CacheQuotaService();
- method public android.os.IBinder onBind(android.content.Intent);
- method public abstract java.util.List<android.app.usage.CacheQuotaHint> onComputeCacheQuotaHints(java.util.List<android.app.usage.CacheQuotaHint>);
- field public static final String SERVICE_INTERFACE = "android.app.usage.CacheQuotaService";
- }
-
- public class NetworkStatsManager {
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void registerNetworkStatsProvider(@NonNull String, @NonNull android.net.netstats.provider.NetworkStatsProvider);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void unregisterNetworkStatsProvider(@NonNull android.net.netstats.provider.NetworkStatsProvider);
- }
-
- public static final class UsageEvents.Event {
- method public int getInstanceId();
- method @Nullable public String getNotificationChannelId();
- method @Nullable public String getTaskRootClassName();
- method @Nullable public String getTaskRootPackageName();
- method public boolean isInstantApp();
- field public static final int NOTIFICATION_INTERRUPTION = 12; // 0xc
- field public static final int NOTIFICATION_SEEN = 10; // 0xa
- field public static final int SLICE_PINNED = 14; // 0xe
- field public static final int SLICE_PINNED_PRIV = 13; // 0xd
- field public static final int SYSTEM_INTERACTION = 6; // 0x6
- }
-
- public final class UsageStats implements android.os.Parcelable {
- method public int getAppLaunchCount();
- }
-
- public final class UsageStatsManager {
- method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getAppStandbyBucket(String);
- method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.Map<java.lang.String,java.lang.Integer> getAppStandbyBuckets();
- method public int getUsageSource();
- method @RequiresPermission(android.Manifest.permission.BIND_CARRIER_SERVICES) public void onCarrierPrivilegedAppsChanged();
- method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @Nullable android.app.PendingIntent);
- method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
- method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
- method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String);
- method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String, long);
- method public void reportUsageStop(@NonNull android.app.Activity, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE) public void setAppStandbyBucket(String, int);
- method @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE) public void setAppStandbyBuckets(java.util.Map<java.lang.String,java.lang.Integer>);
- method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void unregisterAppUsageLimitObserver(int);
- method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void unregisterAppUsageObserver(int);
- method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void unregisterUsageSessionObserver(int);
- method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(String, long, android.os.UserHandle);
- field public static final String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID";
- field public static final String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT";
- field public static final String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED";
- field public static final int STANDBY_BUCKET_EXEMPTED = 5; // 0x5
- field public static final int STANDBY_BUCKET_NEVER = 50; // 0x32
- field public static final int USAGE_SOURCE_CURRENT_ACTIVITY = 2; // 0x2
- field public static final int USAGE_SOURCE_TASK_ROOT_ACTIVITY = 1; // 0x1
- }
-
-}
-
-package android.bluetooth {
-
- public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@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
- field public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1; // 0xffffffff
- field public static final int OPTIONAL_CODECS_SUPPORTED = 1; // 0x1
- field public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1; // 0xffffffff
- }
-
- public final class BluetoothA2dpSink implements android.bluetooth.BluetoothProfile {
- method public void finalize();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isAudioPlaying(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
- }
-
- public final class BluetoothAdapter {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
- method public boolean disableBLE();
- method public boolean enableBLE();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public long getDiscoveryEndMillis();
- method public boolean isBleScanAlwaysAvailable();
- method public boolean isLeEnabled();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeActiveDevice(int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setActiveDevice(@NonNull android.bluetooth.BluetoothDevice, int);
- field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
- field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
- field public static final int ACTIVE_DEVICE_ALL = 2; // 0x2
- field public static final int ACTIVE_DEVICE_AUDIO = 0; // 0x0
- field public static final int ACTIVE_DEVICE_PHONE_CALL = 1; // 0x1
- }
-
- public static interface BluetoothAdapter.OnMetadataChangedListener {
- method public void onMetadataChanged(@NonNull android.bluetooth.BluetoothDevice, int, @Nullable byte[]);
- }
-
- public final class BluetoothDevice implements android.os.Parcelable {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean cancelBondProcess();
- method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getSimAccessPermission();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeBond();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMessageAccessPermission(int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSimAccessPermission(int);
- field public static final int ACCESS_ALLOWED = 1; // 0x1
- field public static final int ACCESS_REJECTED = 2; // 0x2
- field public static final int ACCESS_UNKNOWN = 0; // 0x0
- field public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
- field public static final int METADATA_COMPANION_APP = 4; // 0x4
- field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
- field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
- field public static final int METADATA_IS_UNTETHERED_HEADSET = 6; // 0x6
- field public static final int METADATA_MAIN_ICON = 5; // 0x5
- field public static final int METADATA_MANUFACTURER_NAME = 0; // 0x0
- field public static final int METADATA_MAX_LENGTH = 2048; // 0x800
- field public static final int METADATA_MODEL_NAME = 1; // 0x1
- field public static final int METADATA_SOFTWARE_VERSION = 2; // 0x2
- field public static final int METADATA_UNTETHERED_CASE_BATTERY = 12; // 0xc
- field public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; // 0xf
- field public static final int METADATA_UNTETHERED_CASE_ICON = 9; // 0x9
- field public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; // 0xa
- field public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; // 0xd
- field public static final int METADATA_UNTETHERED_LEFT_ICON = 7; // 0x7
- field public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; // 0xb
- field public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; // 0xe
- field public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; // 0x8
- }
-
- public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean connect(android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnect(android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
- }
-
- public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public long getHiSyncId(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- }
-
- public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- }
-
- public final class BluetoothHidHost implements android.bluetooth.BluetoothProfile {
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
- }
-
- public final class BluetoothMap implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void close();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) protected void finalize();
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
- }
-
- public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
- method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isTetheringOn();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setBluetoothTethering(boolean);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
- field public static final String ACTION_TETHERING_STATE_CHANGED = "android.bluetooth.action.TETHERING_STATE_CHANGED";
- field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
- field public static final String EXTRA_TETHERING_STATE = "android.bluetooth.extra.TETHERING_STATE";
- field public static final int LOCAL_NAP_ROLE = 1; // 0x1
- field public static final int LOCAL_PANU_ROLE = 2; // 0x2
- field public static final int PAN_ROLE_NONE = 0; // 0x0
- field public static final int REMOTE_NAP_ROLE = 1; // 0x1
- field public static final int REMOTE_PANU_ROLE = 2; // 0x2
- field public static final int TETHERING_STATE_OFF = 1; // 0x1
- field public static final int TETHERING_STATE_ON = 2; // 0x2
- }
-
- public class BluetoothPbap implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionState(@NonNull android.bluetooth.BluetoothDevice);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- field @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
- }
-
- public interface BluetoothProfile {
- field public static final int A2DP_SINK = 11; // 0xb
- field public static final int AVRCP_CONTROLLER = 12; // 0xc
- field public static final int CONNECTION_POLICY_ALLOWED = 100; // 0x64
- field public static final int CONNECTION_POLICY_FORBIDDEN = 0; // 0x0
- field public static final int CONNECTION_POLICY_UNKNOWN = -1; // 0xffffffff
- field public static final int HEADSET_CLIENT = 16; // 0x10
- field public static final int PAN = 5; // 0x5
- field public static final int PBAP_CLIENT = 17; // 0x11
- field @Deprecated public static final int PRIORITY_OFF = 0; // 0x0
- field @Deprecated public static final int PRIORITY_ON = 100; // 0x64
- }
-
- public final class BluetoothUuid {
- method public static boolean containsAnyUuid(@Nullable android.os.ParcelUuid[], @Nullable android.os.ParcelUuid[]);
- method @NonNull public static android.os.ParcelUuid parseUuidFrom(@Nullable byte[]);
- field @NonNull public static final android.os.ParcelUuid A2DP_SINK;
- field @NonNull public static final android.os.ParcelUuid A2DP_SOURCE;
- field @NonNull public static final android.os.ParcelUuid ADV_AUDIO_DIST;
- field @NonNull public static final android.os.ParcelUuid AVRCP_CONTROLLER;
- field @NonNull public static final android.os.ParcelUuid AVRCP_TARGET;
- field @NonNull public static final android.os.ParcelUuid BASE_UUID;
- field @NonNull public static final android.os.ParcelUuid BNEP;
- field @NonNull public static final android.os.ParcelUuid HEARING_AID;
- field @NonNull public static final android.os.ParcelUuid HFP;
- field @NonNull public static final android.os.ParcelUuid HFP_AG;
- field @NonNull public static final android.os.ParcelUuid HID;
- field @NonNull public static final android.os.ParcelUuid HOGP;
- field @NonNull public static final android.os.ParcelUuid HSP;
- field @NonNull public static final android.os.ParcelUuid HSP_AG;
- field @NonNull public static final android.os.ParcelUuid MAP;
- field @NonNull public static final android.os.ParcelUuid MAS;
- field @NonNull public static final android.os.ParcelUuid MNS;
- field @NonNull public static final android.os.ParcelUuid NAP;
- field @NonNull public static final android.os.ParcelUuid OBEX_OBJECT_PUSH;
- field @NonNull public static final android.os.ParcelUuid PANU;
- field @NonNull public static final android.os.ParcelUuid PBAP_PCE;
- field @NonNull public static final android.os.ParcelUuid PBAP_PSE;
- field @NonNull public static final android.os.ParcelUuid SAP;
- field public static final int UUID_BYTES_128_BIT = 16; // 0x10
- field public static final int UUID_BYTES_16_BIT = 2; // 0x2
- field public static final int UUID_BYTES_32_BIT = 4; // 0x4
- }
-
-}
-
-package android.bluetooth.le {
-
- public final class BluetoothLeScanner {
- method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADMIN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(android.os.WorkSource, android.bluetooth.le.ScanCallback);
- method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_ADMIN, android.Manifest.permission.UPDATE_DEVICE_STATS}) public void startScanFromSource(java.util.List<android.bluetooth.le.ScanFilter>, android.bluetooth.le.ScanSettings, android.os.WorkSource, android.bluetooth.le.ScanCallback);
- method public void startTruncatedScan(java.util.List<android.bluetooth.le.TruncatedFilter>, android.bluetooth.le.ScanSettings, android.bluetooth.le.ScanCallback);
- }
-
- public final class ResultStorageDescriptor implements android.os.Parcelable {
- ctor public ResultStorageDescriptor(int, int, int);
- method public int describeContents();
- method public int getLength();
- method public int getOffset();
- method public int getType();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.ResultStorageDescriptor> CREATOR;
- }
-
- public final class ScanSettings implements android.os.Parcelable {
- field public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; // 0x1
- field public static final int SCAN_RESULT_TYPE_FULL = 0; // 0x0
- }
-
- public static final class ScanSettings.Builder {
- method public android.bluetooth.le.ScanSettings.Builder setScanResultType(int);
- }
-
- public final class TruncatedFilter {
- ctor public TruncatedFilter(android.bluetooth.le.ScanFilter, java.util.List<android.bluetooth.le.ResultStorageDescriptor>);
- method public android.bluetooth.le.ScanFilter getFilter();
- method public java.util.List<android.bluetooth.le.ResultStorageDescriptor> getStorageDescriptors();
- }
-
-}
-
-package android.companion {
-
- public final class CompanionDeviceManager {
- method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociatedForWifiConnection(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle);
- }
-
-}
-
-package android.content {
-
- 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);
- }
-
- public abstract class BroadcastReceiver {
- method @NonNull public final android.os.UserHandle getSendingUser();
- }
-
- public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
- method public int checkUriPermission(@NonNull android.net.Uri, int, int);
- }
-
- public class ContentProviderClient implements java.lang.AutoCloseable {
- method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long);
- }
-
- public abstract class ContentResolver {
- method public int checkUriPermission(@NonNull android.net.Uri, int, int);
- 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 @Nullable @RequiresPermission("android.permission.CACHE_CONTENT") public android.os.Bundle getCache(@NonNull android.net.Uri);
- method @RequiresPermission("android.permission.CACHE_CONTENT") public void putCache(@NonNull android.net.Uri, @Nullable android.os.Bundle);
- }
-
- public abstract class Context {
- method @NonNull public android.content.Context createContextAsUser(@NonNull android.os.UserHandle, int);
- method public abstract android.content.Context createCredentialProtectedStorageContext();
- method @NonNull public android.content.Context createPackageContextAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
- method @Nullable public abstract java.io.File getPreloadsFileCache();
- method public abstract boolean isCredentialProtectedStorage();
- method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler);
- method public abstract void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle);
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
- method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
- field public static final String APP_INTEGRITY_SERVICE = "app_integrity";
- field public static final String APP_PREDICTION_SERVICE = "app_prediction";
- field public static final String BACKUP_SERVICE = "backup";
- field public static final String BATTERY_STATS_SERVICE = "batterystats";
- field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
- field public static final String BUGREPORT_SERVICE = "bugreport";
- field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
- field public static final String CONTEXTHUB_SERVICE = "contexthub";
- field public static final String ETHERNET_SERVICE = "ethernet";
- field public static final String EUICC_CARD_SERVICE = "euicc_card";
- field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
- field public static final String MEDIA_TRANSCODING_SERVICE = "media_transcoding";
- field public static final String NETD_SERVICE = "netd";
- field public static final String NETWORK_SCORE_SERVICE = "network_score";
- field public static final String OEM_LOCK_SERVICE = "oem_lock";
- field public static final String PERMISSION_SERVICE = "permission";
- field public static final String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
- field public static final String ROLLBACK_SERVICE = "rollback";
- field public static final String SECURE_ELEMENT_SERVICE = "secure_element";
- field public static final String STATS_MANAGER = "stats";
- field public static final String STATUS_BAR_SERVICE = "statusbar";
- field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
- field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
- field public static final String TETHERING_SERVICE = "tethering";
- field public static final String VR_SERVICE = "vrmanager";
- field public static final String WIFI_NL80211_SERVICE = "wifinl80211";
- field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager";
- field public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
- }
-
- public class ContextWrapper extends android.content.Context {
- method public android.content.Context createCredentialProtectedStorageContext();
- method public java.io.File getPreloadsFileCache();
- method public boolean isCredentialProtectedStorage();
- method public void sendBroadcast(android.content.Intent, String, android.os.Bundle);
- method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.os.Bundle);
- method public void sendOrderedBroadcast(android.content.Intent, String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle);
- }
-
- public class Intent implements java.lang.Cloneable android.os.Parcelable {
- field public static final String ACTION_BATTERY_LEVEL_CHANGED = "android.intent.action.BATTERY_LEVEL_CHANGED";
- field public static final String ACTION_CALL_EMERGENCY = "android.intent.action.CALL_EMERGENCY";
- field public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
- field public static final String ACTION_DEVICE_CUSTOMIZATION_READY = "android.intent.action.DEVICE_CUSTOMIZATION_READY";
- field public static final String ACTION_DIAL_EMERGENCY = "android.intent.action.DIAL_EMERGENCY";
- field public static final String ACTION_FACTORY_RESET = "android.intent.action.FACTORY_RESET";
- field public static final String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON";
- field public static final String ACTION_INCIDENT_REPORT_READY = "android.intent.action.INCIDENT_REPORT_READY";
- field public static final String ACTION_INSTALL_INSTANT_APP_PACKAGE = "android.intent.action.INSTALL_INSTANT_APP_PACKAGE";
- field public static final String ACTION_INSTANT_APP_RESOLVER_SETTINGS = "android.intent.action.INSTANT_APP_RESOLVER_SETTINGS";
- field public static final String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION";
- field public static final String ACTION_LOAD_DATA = "android.intent.action.LOAD_DATA";
- field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_MANAGE_APP_PERMISSION = "android.intent.action.MANAGE_APP_PERMISSION";
- field public static final String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS";
- field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP";
- field public static final String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";
- field public static final String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
- field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_SPECIAL_APP_ACCESSES = "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES";
- field public static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
- field public static final String ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION";
- field public static final String ACTION_PACKAGE_UNSUSPENDED_MANUALLY = "android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY";
- field public static final String ACTION_PENDING_INCIDENT_REPORTS_CHANGED = "android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED";
- field public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
- field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
- field public static final String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
- field @RequiresPermission(android.Manifest.permission.REVIEW_ACCESSIBILITY_SERVICES) public static final String ACTION_REVIEW_ACCESSIBILITY_SERVICES = "android.intent.action.REVIEW_ACCESSIBILITY_SERVICES";
- field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_ONGOING_PERMISSION_USAGE = "android.intent.action.REVIEW_ONGOING_PERMISSION_USAGE";
- field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
- field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
- field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
- field public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
- field @Deprecated public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
- field public static final String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
- field public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
- field public static final String ACTION_USER_ADDED = "android.intent.action.USER_ADDED";
- field public static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
- field public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
- field public static final String CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS";
- field public static final String EXTRA_CALLING_PACKAGE = "android.intent.extra.CALLING_PACKAGE";
- field public static final String EXTRA_FORCE_FACTORY_RESET = "android.intent.extra.FORCE_FACTORY_RESET";
- field public static final String EXTRA_INSTANT_APP_ACTION = "android.intent.extra.INSTANT_APP_ACTION";
- field public static final String EXTRA_INSTANT_APP_BUNDLES = "android.intent.extra.INSTANT_APP_BUNDLES";
- field public static final String EXTRA_INSTANT_APP_EXTRAS = "android.intent.extra.INSTANT_APP_EXTRAS";
- field public static final String EXTRA_INSTANT_APP_FAILURE = "android.intent.extra.INSTANT_APP_FAILURE";
- field public static final String EXTRA_INSTANT_APP_HOSTNAME = "android.intent.extra.INSTANT_APP_HOSTNAME";
- field public static final String EXTRA_INSTANT_APP_SUCCESS = "android.intent.extra.INSTANT_APP_SUCCESS";
- field public static final String EXTRA_INSTANT_APP_TOKEN = "android.intent.extra.INSTANT_APP_TOKEN";
- field public static final String EXTRA_LONG_VERSION_CODE = "android.intent.extra.LONG_VERSION_CODE";
- field public static final String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
- field public static final String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
- field public static final String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME";
- field public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
- field public static final String EXTRA_REASON = "android.intent.extra.REASON";
- field public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
- field public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
- field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
- field public static final String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
- field public static final String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE";
- field public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 67108864; // 0x4000000
- field public static final String METADATA_SETUP_VERSION = "android.SETUP_VERSION";
- }
-
- public class IntentFilter implements android.os.Parcelable {
- method public final int getOrder();
- method public final void setOrder(int);
- }
-
-}
-
-package android.content.integrity {
-
- public class AppIntegrityManager {
- method @NonNull public String getCurrentRuleSetProvider();
- method @NonNull public String getCurrentRuleSetVersion();
- method public void updateRuleSet(@NonNull android.content.integrity.RuleSet, @NonNull android.content.IntentSender);
- field public static final String EXTRA_STATUS = "android.content.integrity.extra.STATUS";
- field public static final int STATUS_FAILURE = 1; // 0x1
- field public static final int STATUS_SUCCESS = 0; // 0x0
- }
-
- public abstract class IntegrityFormula {
- method @NonNull public static android.content.integrity.IntegrityFormula all(@NonNull android.content.integrity.IntegrityFormula...);
- method @NonNull public static android.content.integrity.IntegrityFormula any(@NonNull android.content.integrity.IntegrityFormula...);
- method @NonNull public static android.content.integrity.IntegrityFormula not(@NonNull android.content.integrity.IntegrityFormula);
- }
-
- public static final class IntegrityFormula.Application {
- method @NonNull public static android.content.integrity.IntegrityFormula certificatesContain(@NonNull String);
- method @NonNull public static android.content.integrity.IntegrityFormula isPreInstalled();
- method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String);
- method @NonNull public static android.content.integrity.IntegrityFormula versionCodeEquals(@NonNull long);
- method @NonNull public static android.content.integrity.IntegrityFormula versionCodeGreaterThan(@NonNull long);
- method @NonNull public static android.content.integrity.IntegrityFormula versionCodeGreaterThanOrEqualTo(@NonNull long);
- }
-
- public static final class IntegrityFormula.Installer {
- method @NonNull public static android.content.integrity.IntegrityFormula certificatesContain(@NonNull String);
- method @NonNull public static android.content.integrity.IntegrityFormula notAllowedByManifest();
- method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String);
- }
-
- public static final class IntegrityFormula.SourceStamp {
- method @NonNull public static android.content.integrity.IntegrityFormula notTrusted();
- method @NonNull public static android.content.integrity.IntegrityFormula stampCertificateHashEquals(@NonNull String);
- }
-
- public final class Rule implements android.os.Parcelable {
- ctor public Rule(@NonNull android.content.integrity.IntegrityFormula, int);
- method public int describeContents();
- method public int getEffect();
- method @NonNull public android.content.integrity.IntegrityFormula getFormula();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.Rule> CREATOR;
- field public static final int DENY = 0; // 0x0
- field public static final int FORCE_ALLOW = 1; // 0x1
- }
-
- public class RuleSet {
- method @NonNull public java.util.List<android.content.integrity.Rule> getRules();
- method @NonNull public String getVersion();
- }
-
- public static class RuleSet.Builder {
- ctor public RuleSet.Builder();
- method @NonNull public android.content.integrity.RuleSet.Builder addRules(@NonNull java.util.List<android.content.integrity.Rule>);
- method @NonNull public android.content.integrity.RuleSet build();
- method @NonNull public android.content.integrity.RuleSet.Builder setVersion(@NonNull String);
- }
-
-}
-
-package android.content.om {
-
- public final class OverlayInfo implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public String getCategory();
- method @NonNull public String getPackageName();
- method @Nullable public String getTargetOverlayableName();
- method @NonNull public String getTargetPackageName();
- method public int getUserId();
- method public boolean isEnabled();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.om.OverlayInfo> CREATOR;
- }
-
- public class OverlayManager {
- method @Nullable public android.content.om.OverlayInfo getOverlayInfo(@NonNull String, @NonNull android.os.UserHandle);
- method @NonNull @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public java.util.List<android.content.om.OverlayInfo> getOverlayInfosForTarget(@NonNull String, @NonNull android.os.UserHandle);
- method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabled(@NonNull String, boolean, @NonNull android.os.UserHandle) throws java.lang.IllegalStateException, java.lang.SecurityException;
- method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public void setEnabledExclusiveInCategory(@NonNull String, @NonNull android.os.UserHandle) throws java.lang.IllegalStateException, java.lang.SecurityException;
- }
-
-}
-
-package android.content.pm {
-
- public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
- method public boolean isEncryptionAware();
- method public boolean isInstantApp();
- field public String credentialProtectedDataDir;
- field public int targetSandboxVersion;
- }
-
- public class CrossProfileApps {
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_PROFILES) public void startActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
- }
-
- public class DataLoaderParams {
- method @NonNull public static final android.content.pm.DataLoaderParams forIncremental(@NonNull android.content.ComponentName, @NonNull String);
- method @NonNull public static final android.content.pm.DataLoaderParams forStreaming(@NonNull android.content.ComponentName, @NonNull String);
- method @NonNull public final String getArguments();
- method @NonNull public final android.content.ComponentName getComponentName();
- method @NonNull public final int getType();
- }
-
- public final class InstallationFile {
- method public long getLengthBytes();
- method public int getLocation();
- method @Nullable public byte[] getMetadata();
- method @NonNull public String getName();
- method @Nullable public byte[] getSignature();
- }
-
- public final class InstantAppInfo implements android.os.Parcelable {
- ctor public InstantAppInfo(android.content.pm.ApplicationInfo, String[], String[]);
- ctor public InstantAppInfo(String, CharSequence, String[], String[]);
- method public int describeContents();
- method @Nullable public android.content.pm.ApplicationInfo getApplicationInfo();
- method @Nullable public String[] getGrantedPermissions();
- method @NonNull public String getPackageName();
- method @Nullable public String[] getRequestedPermissions();
- method @NonNull public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.pm.PackageManager);
- method @NonNull public CharSequence loadLabel(@NonNull android.content.pm.PackageManager);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstantAppInfo> CREATOR;
- }
-
- public final class InstantAppIntentFilter implements android.os.Parcelable {
- ctor public InstantAppIntentFilter(@Nullable String, @NonNull java.util.List<android.content.IntentFilter>);
- method public int describeContents();
- method public java.util.List<android.content.IntentFilter> getFilters();
- method public String getSplitName();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstantAppIntentFilter> CREATOR;
- }
-
- public final class InstantAppRequestInfo implements android.os.Parcelable {
- ctor public InstantAppRequestInfo(@NonNull android.content.Intent, @Nullable int[], @NonNull android.os.UserHandle, boolean, @NonNull String);
- method public int describeContents();
- method @Nullable public int[] getHostDigestPrefix();
- method @NonNull public android.content.Intent getIntent();
- method @NonNull public String getToken();
- method @NonNull public android.os.UserHandle getUserHandle();
- method public boolean isRequesterInstantApp();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstantAppRequestInfo> CREATOR;
- }
-
- public final class InstantAppResolveInfo implements android.os.Parcelable {
- ctor public InstantAppResolveInfo(@NonNull android.content.pm.InstantAppResolveInfo.InstantAppDigest, @Nullable String, @Nullable java.util.List<android.content.pm.InstantAppIntentFilter>, int);
- ctor public InstantAppResolveInfo(@NonNull android.content.pm.InstantAppResolveInfo.InstantAppDigest, @Nullable String, @Nullable java.util.List<android.content.pm.InstantAppIntentFilter>, long, @Nullable android.os.Bundle);
- ctor public InstantAppResolveInfo(@NonNull String, @Nullable String, @Nullable java.util.List<android.content.pm.InstantAppIntentFilter>);
- ctor public InstantAppResolveInfo(@Nullable android.os.Bundle);
- method public int describeContents();
- method public byte[] getDigestBytes();
- method public int getDigestPrefix();
- method @Nullable public android.os.Bundle getExtras();
- method public java.util.List<android.content.pm.InstantAppIntentFilter> getIntentFilters();
- method public long getLongVersionCode();
- method public String getPackageName();
- method @Deprecated public int getVersionCode();
- method public boolean shouldLetInstallerDecide();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstantAppResolveInfo> CREATOR;
- }
-
- public static final class InstantAppResolveInfo.InstantAppDigest implements android.os.Parcelable {
- ctor public InstantAppResolveInfo.InstantAppDigest(@NonNull String);
- method public int describeContents();
- method public byte[][] getDigestBytes();
- method public int[] getDigestPrefix();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.InstantAppResolveInfo.InstantAppDigest> CREATOR;
- field public static final android.content.pm.InstantAppResolveInfo.InstantAppDigest UNDEFINED;
- }
-
- public final class IntentFilterVerificationInfo implements android.os.Parcelable {
- method public int describeContents();
- method public java.util.Set<java.lang.String> getDomains();
- method public String getPackageName();
- method public int getStatus();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.IntentFilterVerificationInfo> CREATOR;
- }
-
- public class LauncherApps {
- method @Nullable public android.content.pm.LauncherApps.AppUsageLimit getAppUsageLimit(@NonNull String, @NonNull android.os.UserHandle);
- }
-
- public static final class LauncherApps.AppUsageLimit implements android.os.Parcelable {
- method public int describeContents();
- method public long getTotalUsageLimit();
- method public long getUsageRemaining();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.LauncherApps.AppUsageLimit> CREATOR;
- }
-
- public class PackageInstaller {
- method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setPermissionsResult(int, boolean);
- field public static final int DATA_LOADER_TYPE_INCREMENTAL = 2; // 0x2
- field public static final int DATA_LOADER_TYPE_NONE = 0; // 0x0
- field public static final int DATA_LOADER_TYPE_STREAMING = 1; // 0x1
- field public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE";
- field public static final int LOCATION_DATA_APP = 0; // 0x0
- field public static final int LOCATION_MEDIA_DATA = 2; // 0x2
- field public static final int LOCATION_MEDIA_OBB = 1; // 0x1
- }
-
- public static class PackageInstaller.Session implements java.io.Closeable {
- method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
- method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void commitTransferred(@NonNull android.content.IntentSender);
- method @Nullable @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public android.content.pm.DataLoaderParams getDataLoaderParams();
- method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void removeFile(int, @NonNull String);
- }
-
- public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
- method public boolean getAllocateAggressive();
- method @Deprecated public boolean getAllowDowngrade();
- method public int getAutoRevokePermissionsMode();
- method public boolean getDontKillApp();
- method public boolean getEnableRollback();
- method @Nullable public String[] getGrantedRuntimePermissions();
- method public boolean getInstallAsFullApp(boolean);
- method public boolean getInstallAsInstantApp(boolean);
- method public boolean getInstallAsVirtualPreload();
- method public boolean getRequestDowngrade();
- method public int getRollbackDataPolicy();
- method @NonNull public java.util.Set<java.lang.String> getWhitelistedRestrictedPermissions();
- }
-
- public static class PackageInstaller.SessionParams implements android.os.Parcelable {
- method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean);
- method @Deprecated public void setAllowDowngrade(boolean);
- method @RequiresPermission(allOf={android.Manifest.permission.INSTALL_PACKAGES, "com.android.permission.USE_INSTALLER_V2"}) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
- method public void setDontKillApp(boolean);
- method public void setEnableRollback(boolean);
- method public void setEnableRollback(boolean, int);
- method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]);
- method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
- method public void setInstallAsInstantApp(boolean);
- method public void setInstallAsVirtualPreload();
- method public void setRequestDowngrade(boolean);
- method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
- }
-
- public class PackageItemInfo {
- method public static void forceSafeLabels();
- method @Deprecated @NonNull public CharSequence loadSafeLabel(@NonNull android.content.pm.PackageManager);
- method @NonNull public CharSequence loadSafeLabel(@NonNull android.content.pm.PackageManager, @FloatRange(from=0) float, int);
- }
-
- public abstract class PackageManager {
- method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
- method public abstract boolean arePermissionsIndividuallyControlled();
- method @NonNull public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(@NonNull String);
- method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.pm.ApplicationInfo getApplicationInfoAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
- method @NonNull public android.content.pm.dex.ArtManager getArtManager();
- method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_SHARED_LIBRARIES) public java.util.List<android.content.pm.SharedLibraryInfo> getDeclaredSharedLibraries(@NonNull String, int);
- method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
- method @Nullable @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public CharSequence getHarmfulAppWarning(@NonNull String);
- method @Nullable public String getIncidentReportApproverPackageName();
- method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
- method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_INSTANT_APPS) public abstract android.graphics.drawable.Drawable getInstantAppIcon(String);
- method @Nullable public abstract android.content.ComponentName getInstantAppInstallerComponent();
- method @Nullable public abstract android.content.ComponentName getInstantAppResolverSettingsComponent();
- method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_INSTANT_APPS) public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
- method @NonNull public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract int getIntentVerificationStatusAsUser(@NonNull String, int);
- method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
- method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] getUnsuspendablePackages(@NonNull String[]);
- method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
- method @Deprecated public abstract int installExistingPackage(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
- method @Deprecated public abstract int installExistingPackage(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(@NonNull android.content.Intent, int, android.os.UserHandle);
- method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentActivitiesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
- method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProvidersAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
- method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentServicesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
- method public abstract void registerDexModule(@NonNull String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback);
- method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
- method public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName);
- method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull String);
- method public void sendDeviceCustomizationReadyBroadcast();
- method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(@Nullable String, int);
- method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setDistractingPackageRestrictions(@NonNull String[], int);
- method @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public void setHarmfulAppWarning(@NonNull String, @Nullable CharSequence);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable String);
- method @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable android.content.pm.SuspendDialogInfo);
- method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setSyntheticAppDetailsActivityEnabled(@NonNull String, boolean);
- method public void setSystemAppState(@NonNull String, int);
- method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public abstract void setUpdateAvailable(@NonNull String, boolean);
- method @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public abstract boolean updateIntentVerificationStatusAsUser(@NonNull String, int, int);
- method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT) public abstract void verifyIntentFilter(int, int, @NonNull java.util.List<java.lang.String>);
- field public static final String ACTION_REQUEST_PERMISSIONS = "android.content.pm.action.REQUEST_PERMISSIONS";
- field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
- field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
- field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
- field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub";
- field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
- field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
- field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
- field public static final int FLAGS_PERMISSION_RESERVED_PERMISSION_CONTROLLER = -268435456; // 0xf0000000
- field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000
- 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
- field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
- field public static final int FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT = 2048; // 0x800
- field public static final int FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT = 262144; // 0x40000
- field public static final int FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT = 4096; // 0x1000
- field public static final int FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT = 8192; // 0x2000
- field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
- field public static final int FLAG_PERMISSION_REVOKED_COMPAT = 8; // 0x8
- field @Deprecated public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8
- field public static final int FLAG_PERMISSION_SYSTEM_FIXED = 16; // 0x10
- field public static final int FLAG_PERMISSION_USER_FIXED = 2; // 0x2
- field public static final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED = 512; // 0x200
- field public static final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED = 256; // 0x100
- field public static final int FLAG_PERMISSION_USER_SET = 1; // 0x1
- field public static final int INSTALL_FAILED_ALREADY_EXISTS = -1; // 0xffffffff
- field public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13; // 0xfffffff3
- field public static final int INSTALL_FAILED_CONTAINER_ERROR = -18; // 0xffffffee
- field public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16; // 0xfffffff0
- field public static final int INSTALL_FAILED_DEXOPT = -11; // 0xfffffff5
- field public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5; // 0xfffffffb
- field public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4; // 0xfffffffc
- field public static final int INSTALL_FAILED_INTERNAL_ERROR = -110; // 0xffffff92
- field public static final int INSTALL_FAILED_INVALID_APK = -2; // 0xfffffffe
- field public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19; // 0xffffffed
- field public static final int INSTALL_FAILED_INVALID_URI = -3; // 0xfffffffd
- field public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20; // 0xffffffec
- field public static final int INSTALL_FAILED_MISSING_FEATURE = -17; // 0xffffffef
- field public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9; // 0xfffffff7
- field public static final int INSTALL_FAILED_NEWER_SDK = -14; // 0xfffffff2
- field public static final int INSTALL_FAILED_NO_SHARED_USER = -6; // 0xfffffffa
- field public static final int INSTALL_FAILED_OLDER_SDK = -12; // 0xfffffff4
- field public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23; // 0xffffffe9
- field public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26; // 0xffffffe6
- field public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10; // 0xfffffff6
- field public static final int INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE = -27; // 0xffffffe5
- field public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8; // 0xfffffff8
- field public static final int INSTALL_FAILED_TEST_ONLY = -15; // 0xfffffff1
- field public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7; // 0xfffffff9
- field public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22; // 0xffffffea
- field public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21; // 0xffffffeb
- field public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101; // 0xffffff9b
- field public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106; // 0xffffff96
- field public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107; // 0xffffff95
- field public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105; // 0xffffff97
- field public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104; // 0xffffff98
- field public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109; // 0xffffff93
- field public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108; // 0xffffff94
- field public static final int INSTALL_PARSE_FAILED_NOT_APK = -100; // 0xffffff9c
- field public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103; // 0xffffff99
- field public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102; // 0xffffff9a
- field public static final int INSTALL_SUCCEEDED = 1; // 0x1
- field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS = 2; // 0x2
- field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK = 4; // 0x4
- field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK = 1; // 0x1
- field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER = 3; // 0x3
- field public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED = 0; // 0x0
- field public static final int INTENT_FILTER_VERIFICATION_FAILURE = -1; // 0xffffffff
- field public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
- field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
- field public static final int MATCH_ANY_USER = 4194304; // 0x400000
- field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
- field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000
- field public static final int MATCH_INSTANT = 8388608; // 0x800000
- field public static final int MODULE_APEX_NAME = 1; // 0x1
- field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1
- field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2
- field public static final int RESTRICTION_NONE = 0; // 0x0
- field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN = 0; // 0x0
- field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE = 1; // 0x1
- field public static final int SYSTEM_APP_STATE_INSTALLED = 2; // 0x2
- field public static final int SYSTEM_APP_STATE_UNINSTALLED = 3; // 0x3
- }
-
- public abstract static class PackageManager.DexModuleRegisterCallback {
- ctor public PackageManager.DexModuleRegisterCallback();
- method public abstract void onDexModuleRegistered(String, boolean, String);
- }
-
- public static interface PackageManager.OnPermissionsChangedListener {
- 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_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 {
- field @StringRes public final int backgroundRequestDetailResourceId;
- field @StringRes public final int backgroundRequestResourceId;
- field @StringRes public final int requestDetailResourceId;
- field @StringRes public int requestRes;
- }
-
- public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
- field public static final int FLAG_REMOVED = 2; // 0x2
- field public static final int PROTECTION_FLAG_APP_PREDICTOR = 2097152; // 0x200000
- field public static final int PROTECTION_FLAG_COMPANION = 8388608; // 0x800000
- field public static final int PROTECTION_FLAG_CONFIGURATOR = 524288; // 0x80000
- field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
- field public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 1048576; // 0x100000
- field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
- field public static final int PROTECTION_FLAG_RETAIL_DEMO = 16777216; // 0x1000000
- field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
- field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
- field @Nullable public final String backgroundPermission;
- field @StringRes public int requestRes;
- }
-
- public class ResolveInfo implements android.os.Parcelable {
- field public boolean handleAllWebDataURI;
- }
-
- public final class ShortcutInfo implements android.os.Parcelable {
- method @Nullable public android.app.Person[] getPersons();
- }
-
- public class ShortcutManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS) public java.util.List<android.content.pm.ShortcutManager.ShareShortcutInfo> getShareTargets(@NonNull android.content.IntentFilter);
- method public boolean hasShareTargets(@NonNull String);
- }
-
- public static final class ShortcutManager.ShareShortcutInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.content.pm.ShortcutInfo getShortcutInfo();
- method @NonNull public android.content.ComponentName getTargetComponent();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ShortcutManager.ShareShortcutInfo> CREATOR;
- }
-
- public final class SuspendDialogInfo implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int BUTTON_ACTION_MORE_DETAILS = 0; // 0x0
- field public static final int BUTTON_ACTION_UNSUSPEND = 1; // 0x1
- field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.SuspendDialogInfo> CREATOR;
- }
-
- public static final class SuspendDialogInfo.Builder {
- ctor public SuspendDialogInfo.Builder();
- method @NonNull public android.content.pm.SuspendDialogInfo build();
- method @NonNull public android.content.pm.SuspendDialogInfo.Builder setIcon(@DrawableRes int);
- method @NonNull public android.content.pm.SuspendDialogInfo.Builder setMessage(@NonNull String);
- method @NonNull public android.content.pm.SuspendDialogInfo.Builder setMessage(@StringRes int);
- method @NonNull public android.content.pm.SuspendDialogInfo.Builder setNeutralButtonAction(int);
- method @NonNull public android.content.pm.SuspendDialogInfo.Builder setNeutralButtonText(@StringRes int);
- method @NonNull public android.content.pm.SuspendDialogInfo.Builder setTitle(@StringRes int);
- }
-
-}
-
-package android.content.pm.dex {
-
- public class ArtManager {
- method @RequiresPermission(allOf={android.Manifest.permission.READ_RUNTIME_PROFILES, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean isRuntimeProfilingEnabled(int);
- method @RequiresPermission(allOf={android.Manifest.permission.READ_RUNTIME_PROFILES, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void snapshotRuntimeProfile(int, @Nullable String, @Nullable String, @NonNull java.util.concurrent.Executor, @NonNull android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback);
- field public static final int PROFILE_APPS = 0; // 0x0
- field public static final int PROFILE_BOOT_IMAGE = 1; // 0x1
- field public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; // 0x1
- field public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; // 0x2
- field public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; // 0x0
- }
-
- public abstract static class ArtManager.SnapshotRuntimeProfileCallback {
- ctor public ArtManager.SnapshotRuntimeProfileCallback();
- method public abstract void onError(int);
- method public abstract void onSuccess(android.os.ParcelFileDescriptor);
- }
-
-}
-
-package android.content.pm.permission {
-
- @Deprecated public final class RuntimePermissionPresentationInfo implements android.os.Parcelable {
- ctor @Deprecated public RuntimePermissionPresentationInfo(CharSequence, boolean, boolean);
- method @Deprecated public int describeContents();
- method @Deprecated @NonNull public CharSequence getLabel();
- method @Deprecated public boolean isGranted();
- method @Deprecated public boolean isStandard();
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.content.pm.permission.RuntimePermissionPresentationInfo> CREATOR;
- }
-
-}
-
-package android.content.rollback {
-
- public final class PackageRollbackInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public String getPackageName();
- method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackFrom();
- method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackTo();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR;
- }
-
- public final class RollbackInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public java.util.List<android.content.pm.VersionedPackage> getCausePackages();
- method public int getCommittedSessionId();
- method @NonNull public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
- method public int getRollbackId();
- method public boolean isStaged();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
- }
-
- public final class RollbackManager {
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, "android.permission.TEST_MANAGE_ROLLBACKS"}) public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
- field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
- field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
- field public static final int STATUS_FAILURE = 1; // 0x1
- field public static final int STATUS_FAILURE_INSTALL = 3; // 0x3
- field public static final int STATUS_FAILURE_ROLLBACK_UNAVAILABLE = 2; // 0x2
- field public static final int STATUS_SUCCESS = 0; // 0x0
- }
-
-}
-
-package android.debug {
-
- public class AdbManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public boolean isAdbWifiQrSupported();
- method @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public boolean isAdbWifiSupported();
- }
-
-}
-
-package android.hardware {
-
- public final class Sensor {
- method public java.util.UUID getUuid();
- method public boolean isDataInjectionSupported();
- field public static final String STRING_TYPE_DYNAMIC_SENSOR_META = "android.sensor.dynamic_sensor_meta";
- field public static final String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture";
- field public static final int TYPE_DYNAMIC_SENSOR_META = 32; // 0x20
- field public static final int TYPE_WRIST_TILT_GESTURE = 26; // 0x1a
- }
-
- public abstract class SensorManager {
- method public boolean initDataInjection(boolean);
- method public boolean injectSensorData(android.hardware.Sensor, float[], int, long);
- }
-
-}
-
-package android.hardware.biometrics {
-
- public static interface BiometricManager.Authenticators {
- field @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static final int BIOMETRIC_CONVENIENCE = 4095; // 0xfff
- field @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static final int EMPTY_SET = 0; // 0x0
- }
-
-}
-
-package android.hardware.camera2 {
-
- public abstract class CameraDevice implements java.lang.AutoCloseable {
- method @Deprecated public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException;
- field public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED = 1; // 0x1
- field public static final int SESSION_OPERATION_MODE_NORMAL = 0; // 0x0
- field public static final int SESSION_OPERATION_MODE_VENDOR_START = 32768; // 0x8000
- }
-
-}
-
-package android.hardware.camera2.params {
-
- public final class OutputConfiguration implements android.os.Parcelable {
- ctor public OutputConfiguration(@NonNull android.view.Surface, int);
- ctor public OutputConfiguration(int, @NonNull android.view.Surface, int);
- method public int getRotation();
- field public static final int ROTATION_0 = 0; // 0x0
- field public static final int ROTATION_180 = 2; // 0x2
- field public static final int ROTATION_270 = 3; // 0x3
- field public static final int ROTATION_90 = 1; // 0x1
- }
-
-}
-
-package android.hardware.display {
-
- public final class AmbientBrightnessDayStats implements android.os.Parcelable {
- method public int describeContents();
- method public float[] getBucketBoundaries();
- method public java.time.LocalDate getLocalDate();
- method public float[] getStats();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.AmbientBrightnessDayStats> CREATOR;
- }
-
- public final class BrightnessChangeEvent implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessChangeEvent> CREATOR;
- field public final float batteryLevel;
- field public final float brightness;
- field public final long colorSampleDuration;
- field public final int colorTemperature;
- field @Nullable public final long[] colorValueBuckets;
- field public final boolean isDefaultBrightnessConfig;
- field public final boolean isUserSetBrightness;
- field public final float lastBrightness;
- field public final long[] luxTimestamps;
- field public final float[] luxValues;
- field public final boolean nightMode;
- field public final String packageName;
- field public final float powerBrightnessFactor;
- field public final long timeStamp;
- }
-
- public final class BrightnessConfiguration implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int);
- method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(@NonNull String);
- method public android.util.Pair<float[],float[]> getCurve();
- method public float getShortTermModelLowerLuxMultiplier();
- method public long getShortTermModelTimeoutMillis();
- method public float getShortTermModelUpperLuxMultiplier();
- method public boolean shouldCollectColorSamples();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
- field public static final long SHORT_TERM_TIMEOUT_UNSET = -1L; // 0xffffffffffffffffL
- }
-
- public static class BrightnessConfiguration.Builder {
- ctor public BrightnessConfiguration.Builder(float[], float[]);
- method @NonNull public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, @NonNull android.hardware.display.BrightnessCorrection);
- method @NonNull public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(@NonNull String, @NonNull android.hardware.display.BrightnessCorrection);
- method @NonNull public android.hardware.display.BrightnessConfiguration build();
- method public int getMaxCorrectionsByCategory();
- method public int getMaxCorrectionsByPackageName();
- method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setDescription(@Nullable String);
- method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelLowerLuxMultiplier(@FloatRange(from=0.0f) float);
- method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeoutMillis(long);
- method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelUpperLuxMultiplier(@FloatRange(from=0.0f) float);
- method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShouldCollectColorSamples(boolean);
- }
-
- public final class BrightnessCorrection implements android.os.Parcelable {
- method @FloatRange(from=0.0) public float apply(@FloatRange(from=0.0) float);
- method @NonNull public static android.hardware.display.BrightnessCorrection createScaleAndTranslateLog(float, float);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessCorrection> CREATOR;
- }
-
- public final class ColorDisplayManager {
- method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public int getNightDisplayAutoMode();
- method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public int getTransformCapabilities();
- method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setAppSaturationLevel(@NonNull String, @IntRange(from=0, to=100) int);
- method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setNightDisplayAutoMode(int);
- method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setNightDisplayCustomEndTime(@NonNull java.time.LocalTime);
- method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setNightDisplayCustomStartTime(@NonNull java.time.LocalTime);
- method @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS) public boolean setSaturationLevel(@IntRange(from=0, to=100) int);
- field public static final int AUTO_MODE_CUSTOM_TIME = 1; // 0x1
- field public static final int AUTO_MODE_DISABLED = 0; // 0x0
- field public static final int AUTO_MODE_TWILIGHT = 2; // 0x2
- field public static final int CAPABILITY_HARDWARE_ACCELERATION_GLOBAL = 2; // 0x2
- field public static final int CAPABILITY_HARDWARE_ACCELERATION_PER_APP = 4; // 0x4
- field public static final int CAPABILITY_NONE = 0; // 0x0
- field public static final int CAPABILITY_PROTECTED_CONTENT = 1; // 0x1
- }
-
- public final class DisplayManager {
- method @RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_LIGHT_STATS) public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
- method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
- method @RequiresPermission(android.Manifest.permission.BRIGHTNESS_SLIDER_USAGE) public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
- method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
- method public android.util.Pair<float[],float[]> getMinimumBrightnessCurve();
- method public android.graphics.Point getStableDisplaySize();
- method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
- method @Deprecated @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float);
- }
-
-}
-
-package android.hardware.hdmi {
-
- public abstract class HdmiClient {
- method public android.hardware.hdmi.HdmiDeviceInfo getActiveSource();
- method public void sendKeyEvent(int, boolean);
- method public void sendVendorCommand(int, byte[], boolean);
- method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener);
- }
-
- public final class HdmiControlManager {
- method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
- method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
- method @Nullable public android.hardware.hdmi.HdmiClient getClient(int);
- method @NonNull public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevices();
- method public int getPhysicalAddress();
- method @Nullable public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient();
- method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient();
- method @Nullable public android.hardware.hdmi.HdmiTvClient getTvClient();
- method public boolean isDeviceConnected(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
- method public void powerOffDevice(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
- method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
- method public void setActiveSource(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
- method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean);
- field public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
- field public static final int AVR_VOLUME_MUTED = 101; // 0x65
- field public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 162; // 0xa2
- field public static final int CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION = 160; // 0xa0
- field public static final int CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE = 161; // 0xa1
- field public static final int CLEAR_TIMER_STATUS_TIMER_CLEARED = 128; // 0x80
- field public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_INFO_AVAILABLE = 2; // 0x2
- field public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_MATCHING = 1; // 0x1
- field public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_RECORDING = 0; // 0x0
- field public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1; // 0x1
- field public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3; // 0x3
- field public static final int CONTROL_STATE_CHANGED_REASON_START = 0; // 0x0
- field public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2; // 0x2
- field public static final int DEVICE_EVENT_ADD_DEVICE = 1; // 0x1
- field public static final int DEVICE_EVENT_REMOVE_DEVICE = 2; // 0x2
- field public static final int DEVICE_EVENT_UPDATE_DEVICE = 3; // 0x3
- field public static final String EXTRA_MESSAGE_EXTRA_PARAM1 = "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1";
- field public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID";
- field public static final int ONE_TOUCH_RECORD_ALREADY_RECORDING = 18; // 0x12
- field public static final int ONE_TOUCH_RECORD_CEC_DISABLED = 51; // 0x33
- field public static final int ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION = 49; // 0x31
- field public static final int ONE_TOUCH_RECORD_DISALLOW_TO_COPY = 13; // 0xd
- field public static final int ONE_TOUCH_RECORD_DISALLOW_TO_FUTHER_COPIES = 14; // 0xe
- field public static final int ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN = 50; // 0x32
- field public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 10; // 0xa
- field public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PLUG_NUMBER = 9; // 0x9
- field public static final int ONE_TOUCH_RECORD_MEDIA_PROBLEM = 21; // 0x15
- field public static final int ONE_TOUCH_RECORD_MEDIA_PROTECTED = 19; // 0x13
- field public static final int ONE_TOUCH_RECORD_NOT_ENOUGH_SPACE = 22; // 0x16
- field public static final int ONE_TOUCH_RECORD_NO_MEDIA = 16; // 0x10
- field public static final int ONE_TOUCH_RECORD_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 12; // 0xc
- field public static final int ONE_TOUCH_RECORD_NO_SOURCE_SIGNAL = 20; // 0x14
- field public static final int ONE_TOUCH_RECORD_OTHER_REASON = 31; // 0x1f
- field public static final int ONE_TOUCH_RECORD_PARENT_LOCK_ON = 23; // 0x17
- field public static final int ONE_TOUCH_RECORD_PLAYING = 17; // 0x11
- field public static final int ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS = 48; // 0x30
- field public static final int ONE_TOUCH_RECORD_RECORDING_ALREADY_TERMINATED = 27; // 0x1b
- field public static final int ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE = 3; // 0x3
- field public static final int ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE = 1; // 0x1
- field public static final int ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE = 2; // 0x2
- field public static final int ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT = 4; // 0x4
- field public static final int ONE_TOUCH_RECORD_RECORDING_TERMINATED_NORMALLY = 26; // 0x1a
- field public static final int ONE_TOUCH_RECORD_UNABLE_ANALOGUE_SERVICE = 6; // 0x6
- field public static final int ONE_TOUCH_RECORD_UNABLE_DIGITAL_SERVICE = 5; // 0x5
- field public static final int ONE_TOUCH_RECORD_UNABLE_SELECTED_SERVICE = 7; // 0x7
- field public static final int ONE_TOUCH_RECORD_UNSUPPORTED_CA = 11; // 0xb
- field public static final int OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT = 1; // 0x1
- field public static final int OSD_MESSAGE_AVR_VOLUME_CHANGED = 2; // 0x2
- field public static final int POWER_STATUS_ON = 0; // 0x0
- field public static final int POWER_STATUS_STANDBY = 1; // 0x1
- field public static final int POWER_STATUS_TRANSIENT_TO_ON = 2; // 0x2
- field public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3; // 0x3
- field public static final int POWER_STATUS_UNKNOWN = -1; // 0xffffffff
- field @Deprecated public static final int RESULT_ALREADY_IN_PROGRESS = 4; // 0x4
- field public static final int RESULT_COMMUNICATION_FAILED = 7; // 0x7
- field public static final int RESULT_EXCEPTION = 5; // 0x5
- field public static final int RESULT_INCORRECT_MODE = 6; // 0x6
- field public static final int RESULT_SOURCE_NOT_AVAILABLE = 2; // 0x2
- field public static final int RESULT_SUCCESS = 0; // 0x0
- field public static final int RESULT_TARGET_NOT_AVAILABLE = 3; // 0x3
- field public static final int RESULT_TIMEOUT = 1; // 0x1
- field public static final int TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED = 3; // 0x3
- field public static final int TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION = 1; // 0x1
- field public static final int TIMER_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE = 2; // 0x2
- field public static final int TIMER_RECORDING_RESULT_EXTRA_NO_ERROR = 0; // 0x0
- field public static final int TIMER_RECORDING_TYPE_ANALOGUE = 2; // 0x2
- field public static final int TIMER_RECORDING_TYPE_DIGITAL = 1; // 0x1
- field public static final int TIMER_RECORDING_TYPE_EXTERNAL = 3; // 0x3
- field public static final int TIMER_STATUS_MEDIA_INFO_NOT_PRESENT = 2; // 0x2
- field public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_NOT_PROTECTED = 0; // 0x0
- field public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_PROTECTED = 1; // 0x1
- field public static final int TIMER_STATUS_NOT_PROGRAMMED_CA_NOT_SUPPORTED = 6; // 0x6
- field public static final int TIMER_STATUS_NOT_PROGRAMMED_CLOCK_FAILURE = 10; // 0xa
- field public static final int TIMER_STATUS_NOT_PROGRAMMED_DATE_OUT_OF_RANGE = 2; // 0x2
- field public static final int TIMER_STATUS_NOT_PROGRAMMED_DUPLICATED = 14; // 0xe
- field public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PHYSICAL_NUMBER = 5; // 0x5
- field public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PLUG_NUMBER = 4; // 0x4
- field public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_SEQUENCE = 3; // 0x3
- field public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_CA_ENTITLEMENTS = 7; // 0x7
- field public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_FREE_TIME = 1; // 0x1
- field public static final int TIMER_STATUS_NOT_PROGRAMMED_PARENTAL_LOCK_ON = 9; // 0x9
- field public static final int TIMER_STATUS_NOT_PROGRAMMED_UNSUPPORTED_RESOLUTION = 8; // 0x8
- field public static final int TIMER_STATUS_PROGRAMMED_INFO_ENOUGH_SPACE = 8; // 0x8
- field public static final int TIMER_STATUS_PROGRAMMED_INFO_MIGHT_NOT_ENOUGH_SPACE = 11; // 0xb
- field public static final int TIMER_STATUS_PROGRAMMED_INFO_NOT_ENOUGH_SPACE = 9; // 0x9
- field public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 10; // 0xa
- }
-
- @IntDef({android.hardware.hdmi.HdmiControlManager.RESULT_SUCCESS, android.hardware.hdmi.HdmiControlManager.RESULT_TIMEOUT, android.hardware.hdmi.HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE, android.hardware.hdmi.HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE, android.hardware.hdmi.HdmiControlManager.RESULT_ALREADY_IN_PROGRESS, android.hardware.hdmi.HdmiControlManager.RESULT_EXCEPTION, android.hardware.hdmi.HdmiControlManager.RESULT_INCORRECT_MODE, android.hardware.hdmi.HdmiControlManager.RESULT_COMMUNICATION_FAILED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface HdmiControlManager.ControlCallbackResult {
- }
-
- public static interface HdmiControlManager.HotplugEventListener {
- method public void onReceived(android.hardware.hdmi.HdmiHotplugEvent);
- }
-
- public static interface HdmiControlManager.VendorCommandListener {
- method public void onControlStateChanged(boolean, int);
- method public void onReceived(int, int, byte[], boolean);
- }
-
- public class HdmiDeviceInfo implements android.os.Parcelable {
- ctor public HdmiDeviceInfo();
- method public int describeContents();
- method public int getAdopterId();
- method public int getDeviceId();
- method public int getDevicePowerStatus();
- method public int getDeviceType();
- method public String getDisplayName();
- method public int getId();
- method public int getLogicalAddress();
- method public int getPhysicalAddress();
- method public int getPortId();
- method public int getVendorId();
- method public static int idForCecDevice(int);
- method public static int idForHardware(int);
- method public static int idForMhlDevice(int);
- method public boolean isCecDevice();
- method public boolean isInactivated();
- method public boolean isMhlDevice();
- method public boolean isSourceType();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int ADDR_INTERNAL = 0; // 0x0
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.hdmi.HdmiDeviceInfo> CREATOR;
- field public static final int DEVICE_AUDIO_SYSTEM = 5; // 0x5
- field public static final int DEVICE_INACTIVE = -1; // 0xffffffff
- field public static final int DEVICE_PLAYBACK = 4; // 0x4
- field public static final int DEVICE_RECORDER = 1; // 0x1
- field public static final int DEVICE_RESERVED = 2; // 0x2
- field public static final int DEVICE_TUNER = 3; // 0x3
- field public static final int DEVICE_TV = 0; // 0x0
- field public static final int ID_INVALID = 65535; // 0xffff
- field public static final android.hardware.hdmi.HdmiDeviceInfo INACTIVE_DEVICE;
- field public static final int PATH_INTERNAL = 0; // 0x0
- field public static final int PATH_INVALID = 65535; // 0xffff
- field public static final int PORT_INVALID = -1; // 0xffffffff
- }
-
- public final class HdmiHotplugEvent implements android.os.Parcelable {
- method public int describeContents();
- method public int getPort();
- method public boolean isConnected();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.hdmi.HdmiHotplugEvent> CREATOR;
- }
-
- public final class HdmiPlaybackClient extends android.hardware.hdmi.HdmiClient {
- method public int getDeviceType();
- method public void oneTouchPlay(android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback);
- method public void queryDisplayStatus(android.hardware.hdmi.HdmiPlaybackClient.DisplayStatusCallback);
- method public void sendStandby();
- }
-
- public static interface HdmiPlaybackClient.DisplayStatusCallback {
- method public void onComplete(int);
- }
-
- public static interface HdmiPlaybackClient.OneTouchPlayCallback {
- method public void onComplete(int);
- }
-
- public final class HdmiPortInfo implements android.os.Parcelable {
- ctor public HdmiPortInfo(int, int, int, boolean, boolean, boolean);
- method public int describeContents();
- method public int getAddress();
- method public int getId();
- method public int getType();
- method public boolean isArcSupported();
- method public boolean isCecSupported();
- method public boolean isMhlSupported();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.hdmi.HdmiPortInfo> CREATOR;
- field public static final int PORT_INPUT = 0; // 0x0
- field public static final int PORT_OUTPUT = 1; // 0x1
- }
-
- public abstract class HdmiRecordListener {
- ctor public HdmiRecordListener();
- method public void onClearTimerRecordingResult(int, int);
- method public void onOneTouchRecordResult(int, int);
- method public abstract android.hardware.hdmi.HdmiRecordSources.RecordSource onOneTouchRecordSourceRequested(int);
- method public void onTimerRecordingResult(int, android.hardware.hdmi.HdmiRecordListener.TimerStatusData);
- }
-
- public static class HdmiRecordListener.TimerStatusData {
- method public int getDurationHour();
- method public int getDurationMinute();
- method public int getExtraError();
- method public int getMediaInfo();
- method public int getNotProgammedError();
- method public int getProgrammedInfo();
- method public boolean isOverlapped();
- method public boolean isProgrammed();
- }
-
- public final class HdmiRecordSources {
- method public static boolean checkRecordSource(byte[]);
- method public static android.hardware.hdmi.HdmiRecordSources.OwnSource ofOwnSource();
- }
-
- public static final class HdmiRecordSources.AnalogueServiceSource extends android.hardware.hdmi.HdmiRecordSources.RecordSource {
- }
-
- public static final class HdmiRecordSources.DigitalServiceSource extends android.hardware.hdmi.HdmiRecordSources.RecordSource {
- }
-
- public static final class HdmiRecordSources.ExternalPhysicalAddress extends android.hardware.hdmi.HdmiRecordSources.RecordSource {
- }
-
- public static final class HdmiRecordSources.ExternalPlugData extends android.hardware.hdmi.HdmiRecordSources.RecordSource {
- }
-
- public static final class HdmiRecordSources.OwnSource extends android.hardware.hdmi.HdmiRecordSources.RecordSource {
- }
-
- public abstract static class HdmiRecordSources.RecordSource {
- }
-
- public class HdmiSwitchClient extends android.hardware.hdmi.HdmiClient {
- method public int getDeviceType();
- method @NonNull public java.util.List<android.hardware.hdmi.HdmiPortInfo> getPortInfo();
- method public void selectPort(int, @NonNull android.hardware.hdmi.HdmiSwitchClient.OnSelectListener);
- method public void selectPort(int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.hdmi.HdmiSwitchClient.OnSelectListener);
- }
-
- public static interface HdmiSwitchClient.OnSelectListener {
- method public void onSelect(@android.hardware.hdmi.HdmiControlManager.ControlCallbackResult int);
- }
-
- public class HdmiTimerRecordSources {
- method public static boolean checkTimerRecordSource(int, byte[]);
- method public static android.hardware.hdmi.HdmiTimerRecordSources.Duration durationOf(int, int);
- method public static android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource ofAnalogueSource(android.hardware.hdmi.HdmiTimerRecordSources.TimerInfo, android.hardware.hdmi.HdmiRecordSources.AnalogueServiceSource);
- method public static android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource ofDigitalSource(android.hardware.hdmi.HdmiTimerRecordSources.TimerInfo, android.hardware.hdmi.HdmiRecordSources.DigitalServiceSource);
- method public static android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource ofExternalPhysicalAddress(android.hardware.hdmi.HdmiTimerRecordSources.TimerInfo, android.hardware.hdmi.HdmiRecordSources.ExternalPhysicalAddress);
- method public static android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource ofExternalPlug(android.hardware.hdmi.HdmiTimerRecordSources.TimerInfo, android.hardware.hdmi.HdmiRecordSources.ExternalPlugData);
- method public static android.hardware.hdmi.HdmiTimerRecordSources.Time timeOf(int, int);
- method public static android.hardware.hdmi.HdmiTimerRecordSources.TimerInfo timerInfoOf(int, int, android.hardware.hdmi.HdmiTimerRecordSources.Time, android.hardware.hdmi.HdmiTimerRecordSources.Duration, int);
- field public static final int RECORDING_SEQUENCE_REPEAT_FRIDAY = 32; // 0x20
- field public static final int RECORDING_SEQUENCE_REPEAT_MONDAY = 2; // 0x2
- field public static final int RECORDING_SEQUENCE_REPEAT_ONCE_ONLY = 0; // 0x0
- field public static final int RECORDING_SEQUENCE_REPEAT_SATUREDAY = 64; // 0x40
- field public static final int RECORDING_SEQUENCE_REPEAT_SUNDAY = 1; // 0x1
- field public static final int RECORDING_SEQUENCE_REPEAT_THURSDAY = 16; // 0x10
- field public static final int RECORDING_SEQUENCE_REPEAT_TUESDAY = 4; // 0x4
- field public static final int RECORDING_SEQUENCE_REPEAT_WEDNESDAY = 8; // 0x8
- }
-
- public static final class HdmiTimerRecordSources.Duration {
- }
-
- public static final class HdmiTimerRecordSources.Time {
- }
-
- public static final class HdmiTimerRecordSources.TimerInfo {
- }
-
- public static final class HdmiTimerRecordSources.TimerRecordSource {
- }
-
- public final class HdmiTvClient extends android.hardware.hdmi.HdmiClient {
- method public void clearTimerRecording(int, int, android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource);
- method public void deviceSelect(int, @NonNull android.hardware.hdmi.HdmiTvClient.SelectCallback);
- method public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getDeviceList();
- method public int getDeviceType();
- method public void portSelect(int, @NonNull android.hardware.hdmi.HdmiTvClient.SelectCallback);
- method public void sendMhlVendorCommand(int, int, int, byte[]);
- method public void sendStandby(int);
- method public void setHdmiMhlVendorCommandListener(android.hardware.hdmi.HdmiTvClient.HdmiMhlVendorCommandListener);
- method public void setInputChangeListener(android.hardware.hdmi.HdmiTvClient.InputChangeListener);
- method public void setRecordListener(@NonNull android.hardware.hdmi.HdmiRecordListener);
- method public void setSystemAudioMode(boolean, android.hardware.hdmi.HdmiTvClient.SelectCallback);
- method public void setSystemAudioMute(boolean);
- method public void setSystemAudioVolume(int, int, int);
- method public void startOneTouchRecord(int, @NonNull android.hardware.hdmi.HdmiRecordSources.RecordSource);
- method public void startTimerRecording(int, int, android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource);
- method public void stopOneTouchRecord(int);
- field public static final int VENDOR_DATA_SIZE = 16; // 0x10
- }
-
- public static interface HdmiTvClient.HdmiMhlVendorCommandListener {
- method public void onReceived(int, int, int, byte[]);
- }
-
- public static interface HdmiTvClient.InputChangeListener {
- method public void onChanged(android.hardware.hdmi.HdmiDeviceInfo);
- }
-
- public static interface HdmiTvClient.SelectCallback {
- method public void onComplete(int);
- }
-
-}
-
-package android.hardware.lights {
-
- public final class Light implements android.os.Parcelable {
- method public int describeContents();
- method public int getId();
- method public int getOrdinal();
- method public int getType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.Light> CREATOR;
- }
-
- public final class LightState implements android.os.Parcelable {
- ctor public LightState(@ColorInt int);
- method public int describeContents();
- method @ColorInt public int getColor();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.LightState> CREATOR;
- }
-
- public final class LightsManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public java.util.List<android.hardware.lights.Light> getLights();
- method @NonNull @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public android.hardware.lights.LightsManager.LightsSession openSession();
- field public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8
- }
-
- public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
- method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
- method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void requestLights(@NonNull android.hardware.lights.LightsRequest);
- }
-
- public final class LightsRequest {
- }
-
- public static final class LightsRequest.Builder {
- ctor public LightsRequest.Builder();
- method @NonNull public android.hardware.lights.LightsRequest build();
- method @NonNull public android.hardware.lights.LightsRequest.Builder clearLight(@NonNull android.hardware.lights.Light);
- method @NonNull public android.hardware.lights.LightsRequest.Builder setLight(@NonNull android.hardware.lights.Light, @NonNull android.hardware.lights.LightState);
- }
-
-}
-
-package android.hardware.location {
-
- public class ContextHubClient implements java.io.Closeable {
- method public void close();
- method @NonNull public android.hardware.location.ContextHubInfo getAttachedHub();
- method @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int sendMessageToNanoApp(@NonNull android.hardware.location.NanoAppMessage);
- }
-
- public class ContextHubClientCallback {
- ctor public ContextHubClientCallback();
- method public void onHubReset(android.hardware.location.ContextHubClient);
- method public void onMessageFromNanoApp(android.hardware.location.ContextHubClient, android.hardware.location.NanoAppMessage);
- method public void onNanoAppAborted(android.hardware.location.ContextHubClient, long, int);
- method public void onNanoAppDisabled(android.hardware.location.ContextHubClient, long);
- method public void onNanoAppEnabled(android.hardware.location.ContextHubClient, long);
- method public void onNanoAppLoaded(android.hardware.location.ContextHubClient, long);
- method public void onNanoAppUnloaded(android.hardware.location.ContextHubClient, long);
- }
-
- public class ContextHubInfo implements android.os.Parcelable {
- ctor public ContextHubInfo();
- method public int describeContents();
- method public byte getChreApiMajorVersion();
- method public byte getChreApiMinorVersion();
- method public short getChrePatchVersion();
- method public long getChrePlatformId();
- method public int getId();
- method public int getMaxPacketLengthBytes();
- method public android.hardware.location.MemoryRegion[] getMemoryRegions();
- method public String getName();
- method public float getPeakMips();
- method public float getPeakPowerDrawMw();
- method public int getPlatformVersion();
- method public float getSleepPowerDrawMw();
- method public int getStaticSwVersion();
- method public float getStoppedPowerDrawMw();
- method public int[] getSupportedSensors();
- method public String getToolchain();
- method public int getToolchainVersion();
- method public String getVendor();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubInfo> CREATOR;
- }
-
- public class ContextHubIntentEvent {
- method @NonNull public static android.hardware.location.ContextHubIntentEvent fromIntent(@NonNull android.content.Intent);
- method @NonNull public android.hardware.location.ContextHubInfo getContextHubInfo();
- method public int getEventType();
- method public int getNanoAppAbortCode();
- method public long getNanoAppId();
- method @NonNull public android.hardware.location.NanoAppMessage getNanoAppMessage();
- }
-
- public final class ContextHubManager {
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback, @NonNull java.util.concurrent.Executor);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.ContextHubClientCallback);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
- method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int[] findNanoAppOnHub(int, @NonNull android.hardware.location.NanoAppFilter);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int[] getContextHubHandles();
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubInfo getContextHubInfo(int);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public java.util.List<android.hardware.location.ContextHubInfo> getContextHubs();
- method @Deprecated @Nullable @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo);
- method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
- method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public int unloadNanoApp(int);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_CONTEXT_HUB}) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long);
- method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback);
- field public static final int EVENT_HUB_RESET = 6; // 0x6
- field public static final int EVENT_NANOAPP_ABORTED = 4; // 0x4
- field public static final int EVENT_NANOAPP_DISABLED = 3; // 0x3
- field public static final int EVENT_NANOAPP_ENABLED = 2; // 0x2
- field public static final int EVENT_NANOAPP_LOADED = 0; // 0x0
- field public static final int EVENT_NANOAPP_MESSAGE = 5; // 0x5
- field public static final int EVENT_NANOAPP_UNLOADED = 1; // 0x1
- field public static final String EXTRA_CONTEXT_HUB_INFO = "android.hardware.location.extra.CONTEXT_HUB_INFO";
- field public static final String EXTRA_EVENT_TYPE = "android.hardware.location.extra.EVENT_TYPE";
- field public static final String EXTRA_MESSAGE = "android.hardware.location.extra.MESSAGE";
- field public static final String EXTRA_NANOAPP_ABORT_CODE = "android.hardware.location.extra.NANOAPP_ABORT_CODE";
- field public static final String EXTRA_NANOAPP_ID = "android.hardware.location.extra.NANOAPP_ID";
- }
-
- @Deprecated public abstract static class ContextHubManager.Callback {
- ctor @Deprecated protected ContextHubManager.Callback();
- method @Deprecated public abstract void onMessageReceipt(int, int, @NonNull android.hardware.location.ContextHubMessage);
- }
-
- @Deprecated public class ContextHubMessage implements android.os.Parcelable {
- ctor @Deprecated public ContextHubMessage(int, int, byte[]);
- method @Deprecated public int describeContents();
- method @Deprecated public byte[] getData();
- method @Deprecated public int getMsgType();
- method @Deprecated public int getVersion();
- method @Deprecated public void setMsgData(byte[]);
- method @Deprecated public void setMsgType(int);
- method @Deprecated public void setVersion(int);
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.hardware.location.ContextHubMessage> CREATOR;
- }
-
- public class ContextHubTransaction<T> {
- method public int getType();
- method public void setOnCompleteListener(@NonNull android.hardware.location.ContextHubTransaction.OnCompleteListener<T>, @NonNull java.util.concurrent.Executor);
- method public void setOnCompleteListener(@NonNull android.hardware.location.ContextHubTransaction.OnCompleteListener<T>);
- method public static String typeToString(int, boolean);
- method public android.hardware.location.ContextHubTransaction.Response<T> waitForResponse(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
- field public static final int RESULT_FAILED_AT_HUB = 5; // 0x5
- field public static final int RESULT_FAILED_BAD_PARAMS = 2; // 0x2
- field public static final int RESULT_FAILED_BUSY = 4; // 0x4
- field public static final int RESULT_FAILED_HAL_UNAVAILABLE = 8; // 0x8
- field public static final int RESULT_FAILED_SERVICE_INTERNAL_FAILURE = 7; // 0x7
- field public static final int RESULT_FAILED_TIMEOUT = 6; // 0x6
- field public static final int RESULT_FAILED_UNINITIALIZED = 3; // 0x3
- field public static final int RESULT_FAILED_UNKNOWN = 1; // 0x1
- field public static final int RESULT_SUCCESS = 0; // 0x0
- field public static final int TYPE_DISABLE_NANOAPP = 3; // 0x3
- field public static final int TYPE_ENABLE_NANOAPP = 2; // 0x2
- field public static final int TYPE_LOAD_NANOAPP = 0; // 0x0
- field public static final int TYPE_QUERY_NANOAPPS = 4; // 0x4
- field public static final int TYPE_UNLOAD_NANOAPP = 1; // 0x1
- }
-
- @java.lang.FunctionalInterface public static interface ContextHubTransaction.OnCompleteListener<L> {
- method public void onComplete(android.hardware.location.ContextHubTransaction<L>, android.hardware.location.ContextHubTransaction.Response<L>);
- }
-
- public static class ContextHubTransaction.Response<R> {
- method public R getContents();
- method public int getResult();
- }
-
- public final class GeofenceHardware {
- method public boolean addGeofence(int, int, android.hardware.location.GeofenceHardwareRequest, android.hardware.location.GeofenceHardwareCallback);
- method public int[] getMonitoringTypes();
- method public int getStatusOfMonitoringType(int);
- method public boolean pauseGeofence(int, int);
- method public boolean registerForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
- method public boolean removeGeofence(int, int);
- method public boolean resumeGeofence(int, int, int);
- method public boolean unregisterForMonitorStateChangeCallback(int, android.hardware.location.GeofenceHardwareMonitorCallback);
- field public static final int GEOFENCE_ENTERED = 1; // 0x1
- field public static final int GEOFENCE_ERROR_ID_EXISTS = 2; // 0x2
- field public static final int GEOFENCE_ERROR_ID_UNKNOWN = 3; // 0x3
- field public static final int GEOFENCE_ERROR_INSUFFICIENT_MEMORY = 6; // 0x6
- field public static final int GEOFENCE_ERROR_INVALID_TRANSITION = 4; // 0x4
- field public static final int GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 1; // 0x1
- field public static final int GEOFENCE_EXITED = 2; // 0x2
- field public static final int GEOFENCE_FAILURE = 5; // 0x5
- field public static final int GEOFENCE_SUCCESS = 0; // 0x0
- field public static final int GEOFENCE_UNCERTAIN = 4; // 0x4
- field public static final int MONITORING_TYPE_FUSED_HARDWARE = 1; // 0x1
- field public static final int MONITORING_TYPE_GPS_HARDWARE = 0; // 0x0
- field public static final int MONITOR_CURRENTLY_AVAILABLE = 0; // 0x0
- field public static final int MONITOR_CURRENTLY_UNAVAILABLE = 1; // 0x1
- field public static final int MONITOR_UNSUPPORTED = 2; // 0x2
- field public static final int SOURCE_TECHNOLOGY_BLUETOOTH = 16; // 0x10
- field public static final int SOURCE_TECHNOLOGY_CELL = 8; // 0x8
- field public static final int SOURCE_TECHNOLOGY_GNSS = 1; // 0x1
- field public static final int SOURCE_TECHNOLOGY_SENSORS = 4; // 0x4
- field public static final int SOURCE_TECHNOLOGY_WIFI = 2; // 0x2
- }
-
- public abstract class GeofenceHardwareCallback {
- ctor public GeofenceHardwareCallback();
- method public void onGeofenceAdd(int, int);
- method public void onGeofencePause(int, int);
- method public void onGeofenceRemove(int, int);
- method public void onGeofenceResume(int, int);
- method public void onGeofenceTransition(int, int, android.location.Location, long, int);
- }
-
- public abstract class GeofenceHardwareMonitorCallback {
- ctor public GeofenceHardwareMonitorCallback();
- method @Deprecated public void onMonitoringSystemChange(int, boolean, android.location.Location);
- method public void onMonitoringSystemChange(android.hardware.location.GeofenceHardwareMonitorEvent);
- }
-
- public class GeofenceHardwareMonitorEvent implements android.os.Parcelable {
- ctor public GeofenceHardwareMonitorEvent(int, int, int, android.location.Location);
- method public int describeContents();
- method public android.location.Location getLocation();
- method public int getMonitoringStatus();
- method public int getMonitoringType();
- method public int getSourceTechnologies();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.location.GeofenceHardwareMonitorEvent> CREATOR;
- }
-
- public final class GeofenceHardwareRequest {
- ctor public GeofenceHardwareRequest();
- method public static android.hardware.location.GeofenceHardwareRequest createCircularGeofence(double, double, double);
- method public int getLastTransition();
- method public double getLatitude();
- method public double getLongitude();
- method public int getMonitorTransitions();
- method public int getNotificationResponsiveness();
- method public double getRadius();
- method public int getSourceTechnologies();
- method public int getUnknownTimer();
- method public void setLastTransition(int);
- method public void setMonitorTransitions(int);
- method public void setNotificationResponsiveness(int);
- method public void setSourceTechnologies(int);
- method public void setUnknownTimer(int);
- }
-
- public class MemoryRegion implements android.os.Parcelable {
- ctor public MemoryRegion(android.os.Parcel);
- method public int describeContents();
- method public int getCapacityBytes();
- method public int getFreeCapacityBytes();
- method public boolean isExecutable();
- method public boolean isReadable();
- method public boolean isWritable();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.location.MemoryRegion> CREATOR;
- }
-
- @Deprecated public class NanoApp implements android.os.Parcelable {
- ctor @Deprecated public NanoApp();
- ctor @Deprecated public NanoApp(int, byte[]);
- ctor @Deprecated public NanoApp(long, byte[]);
- method @Deprecated public int describeContents();
- method @Deprecated public byte[] getAppBinary();
- method @Deprecated public long getAppId();
- method @Deprecated public int getAppVersion();
- method @Deprecated public String getName();
- method @Deprecated public int getNeededExecMemBytes();
- method @Deprecated public int getNeededReadMemBytes();
- method @Deprecated public int[] getNeededSensors();
- method @Deprecated public int getNeededWriteMemBytes();
- method @Deprecated public int[] getOutputEvents();
- method @Deprecated public String getPublisher();
- method @Deprecated public void setAppBinary(byte[]);
- method @Deprecated public void setAppId(long);
- method @Deprecated public void setAppVersion(int);
- method @Deprecated public void setName(String);
- method @Deprecated public void setNeededExecMemBytes(int);
- method @Deprecated public void setNeededReadMemBytes(int);
- method @Deprecated public void setNeededSensors(int[]);
- method @Deprecated public void setNeededWriteMemBytes(int);
- method @Deprecated public void setOutputEvents(int[]);
- method @Deprecated public void setPublisher(String);
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.hardware.location.NanoApp> CREATOR;
- }
-
- public final class NanoAppBinary implements android.os.Parcelable {
- ctor public NanoAppBinary(byte[]);
- method public int describeContents();
- method public byte[] getBinary();
- method public byte[] getBinaryNoHeader();
- method public int getFlags();
- method public int getHeaderVersion();
- method public long getHwHubType();
- method public long getNanoAppId();
- method public int getNanoAppVersion();
- method public byte getTargetChreApiMajorVersion();
- method public byte getTargetChreApiMinorVersion();
- method public boolean hasValidHeader();
- method public boolean isEncrypted();
- method public boolean isSigned();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppBinary> CREATOR;
- }
-
- @Deprecated public class NanoAppFilter implements android.os.Parcelable {
- ctor @Deprecated public NanoAppFilter(long, int, int, long);
- method @Deprecated public int describeContents();
- method @Deprecated public boolean testMatch(android.hardware.location.NanoAppInstanceInfo);
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated public static final int APP_ANY = -1; // 0xffffffff
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppFilter> CREATOR;
- field @Deprecated public static final int FLAGS_VERSION_ANY = -1; // 0xffffffff
- field @Deprecated public static final int FLAGS_VERSION_GREAT_THAN = 2; // 0x2
- field @Deprecated public static final int FLAGS_VERSION_LESS_THAN = 4; // 0x4
- field @Deprecated public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8; // 0x8
- field @Deprecated public static final int HUB_ANY = -1; // 0xffffffff
- field @Deprecated public static final int VENDOR_ANY = -1; // 0xffffffff
- }
-
- @Deprecated public class NanoAppInstanceInfo implements android.os.Parcelable {
- ctor @Deprecated public NanoAppInstanceInfo();
- method @Deprecated public int describeContents();
- method @Deprecated public long getAppId();
- method @Deprecated public int getAppVersion();
- method @Deprecated public int getContexthubId();
- method @Deprecated public int getHandle();
- method @Deprecated public String getName();
- method @Deprecated public int getNeededExecMemBytes();
- method @Deprecated public int getNeededReadMemBytes();
- method @Deprecated @NonNull public int[] getNeededSensors();
- method @Deprecated public int getNeededWriteMemBytes();
- method @Deprecated @NonNull public int[] getOutputEvents();
- method @Deprecated public String getPublisher();
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppInstanceInfo> CREATOR;
- }
-
- public final class NanoAppMessage implements android.os.Parcelable {
- method public static android.hardware.location.NanoAppMessage createMessageFromNanoApp(long, int, byte[], boolean);
- method public static android.hardware.location.NanoAppMessage createMessageToNanoApp(long, int, byte[]);
- method public int describeContents();
- method public byte[] getMessageBody();
- method public int getMessageType();
- method public long getNanoAppId();
- method public boolean isBroadcastMessage();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppMessage> CREATOR;
- }
-
- public final class NanoAppState implements android.os.Parcelable {
- ctor public NanoAppState(long, int, boolean);
- method public int describeContents();
- method public long getNanoAppId();
- method public long getNanoAppVersion();
- method public boolean isEnabled();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.location.NanoAppState> CREATOR;
- }
-
-}
-
-package android.hardware.radio {
-
- public final class Announcement implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.hardware.radio.ProgramSelector getSelector();
- method public int getType();
- method @NonNull public java.util.Map<java.lang.String,java.lang.String> getVendorInfo();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.Announcement> CREATOR;
- field public static final int TYPE_EMERGENCY = 1; // 0x1
- field public static final int TYPE_EVENT = 6; // 0x6
- field public static final int TYPE_MISC = 8; // 0x8
- field public static final int TYPE_NEWS = 5; // 0x5
- field public static final int TYPE_SPORT = 7; // 0x7
- field public static final int TYPE_TRAFFIC = 3; // 0x3
- field public static final int TYPE_WARNING = 2; // 0x2
- field public static final int TYPE_WEATHER = 4; // 0x4
- }
-
- public static interface Announcement.OnListUpdatedListener {
- method public void onListUpdated(java.util.Collection<android.hardware.radio.Announcement>);
- }
-
- public final class ProgramList implements java.lang.AutoCloseable {
- method public void addOnCompleteListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.radio.ProgramList.OnCompleteListener);
- method public void addOnCompleteListener(@NonNull android.hardware.radio.ProgramList.OnCompleteListener);
- method public void close();
- method @Nullable public android.hardware.radio.RadioManager.ProgramInfo get(@NonNull android.hardware.radio.ProgramSelector.Identifier);
- method public void registerListCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.radio.ProgramList.ListCallback);
- method public void registerListCallback(@NonNull android.hardware.radio.ProgramList.ListCallback);
- method public void removeOnCompleteListener(@NonNull android.hardware.radio.ProgramList.OnCompleteListener);
- method @NonNull public java.util.List<android.hardware.radio.RadioManager.ProgramInfo> toList();
- method public void unregisterListCallback(@NonNull android.hardware.radio.ProgramList.ListCallback);
- }
-
- public static final class ProgramList.Filter implements android.os.Parcelable {
- ctor public ProgramList.Filter(@NonNull java.util.Set<java.lang.Integer>, @NonNull java.util.Set<android.hardware.radio.ProgramSelector.Identifier>, boolean, boolean);
- method public boolean areCategoriesIncluded();
- method public boolean areModificationsExcluded();
- method public int describeContents();
- method @NonNull public java.util.Set<java.lang.Integer> getIdentifierTypes();
- method @NonNull public java.util.Set<android.hardware.radio.ProgramSelector.Identifier> getIdentifiers();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.ProgramList.Filter> CREATOR;
- }
-
- public abstract static class ProgramList.ListCallback {
- ctor public ProgramList.ListCallback();
- method public void onItemChanged(@NonNull android.hardware.radio.ProgramSelector.Identifier);
- method public void onItemRemoved(@NonNull android.hardware.radio.ProgramSelector.Identifier);
- }
-
- public static interface ProgramList.OnCompleteListener {
- method public void onComplete();
- }
-
- public final class ProgramSelector implements android.os.Parcelable {
- ctor public ProgramSelector(@android.hardware.radio.ProgramSelector.ProgramType int, @NonNull android.hardware.radio.ProgramSelector.Identifier, @Nullable android.hardware.radio.ProgramSelector.Identifier[], @Nullable long[]);
- method @NonNull public static android.hardware.radio.ProgramSelector createAmFmSelector(@android.hardware.radio.RadioManager.Band int, int);
- method @NonNull public static android.hardware.radio.ProgramSelector createAmFmSelector(@android.hardware.radio.RadioManager.Band int, int, int);
- method public int describeContents();
- method @NonNull public android.hardware.radio.ProgramSelector.Identifier[] getAllIds(@android.hardware.radio.ProgramSelector.IdentifierType int);
- method public long getFirstId(@android.hardware.radio.ProgramSelector.IdentifierType int);
- method @NonNull public android.hardware.radio.ProgramSelector.Identifier getPrimaryId();
- method @Deprecated @android.hardware.radio.ProgramSelector.ProgramType public int getProgramType();
- method @NonNull public android.hardware.radio.ProgramSelector.Identifier[] getSecondaryIds();
- method @Deprecated @NonNull public long[] getVendorIds();
- method @NonNull public android.hardware.radio.ProgramSelector withSecondaryPreferred(@NonNull android.hardware.radio.ProgramSelector.Identifier);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.ProgramSelector> CREATOR;
- field public static final int IDENTIFIER_TYPE_AMFM_FREQUENCY = 1; // 0x1
- field public static final int IDENTIFIER_TYPE_DAB_ENSEMBLE = 6; // 0x6
- field public static final int IDENTIFIER_TYPE_DAB_FREQUENCY = 8; // 0x8
- field public static final int IDENTIFIER_TYPE_DAB_SCID = 7; // 0x7
- field public static final int IDENTIFIER_TYPE_DAB_SIDECC = 5; // 0x5
- field public static final int IDENTIFIER_TYPE_DAB_SID_EXT = 5; // 0x5
- field public static final int IDENTIFIER_TYPE_DRMO_FREQUENCY = 10; // 0xa
- field @Deprecated public static final int IDENTIFIER_TYPE_DRMO_MODULATION = 11; // 0xb
- field public static final int IDENTIFIER_TYPE_DRMO_SERVICE_ID = 9; // 0x9
- field public static final int IDENTIFIER_TYPE_HD_STATION_ID_EXT = 3; // 0x3
- field public static final int IDENTIFIER_TYPE_HD_STATION_NAME = 10004; // 0x2714
- field @Deprecated public static final int IDENTIFIER_TYPE_HD_SUBCHANNEL = 4; // 0x4
- field public static final int IDENTIFIER_TYPE_INVALID = 0; // 0x0
- field public static final int IDENTIFIER_TYPE_RDS_PI = 2; // 0x2
- field public static final int IDENTIFIER_TYPE_SXM_CHANNEL = 13; // 0xd
- field public static final int IDENTIFIER_TYPE_SXM_SERVICE_ID = 12; // 0xc
- field public static final int IDENTIFIER_TYPE_VENDOR_END = 1999; // 0x7cf
- field @Deprecated public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_END = 1999; // 0x7cf
- field @Deprecated public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_START = 1000; // 0x3e8
- field public static final int IDENTIFIER_TYPE_VENDOR_START = 1000; // 0x3e8
- field @Deprecated public static final int PROGRAM_TYPE_AM = 1; // 0x1
- field @Deprecated public static final int PROGRAM_TYPE_AM_HD = 3; // 0x3
- field @Deprecated public static final int PROGRAM_TYPE_DAB = 5; // 0x5
- field @Deprecated public static final int PROGRAM_TYPE_DRMO = 6; // 0x6
- field @Deprecated public static final int PROGRAM_TYPE_FM = 2; // 0x2
- field @Deprecated public static final int PROGRAM_TYPE_FM_HD = 4; // 0x4
- field @Deprecated public static final int PROGRAM_TYPE_INVALID = 0; // 0x0
- field @Deprecated public static final int PROGRAM_TYPE_SXM = 7; // 0x7
- field @Deprecated public static final int PROGRAM_TYPE_VENDOR_END = 1999; // 0x7cf
- field @Deprecated public static final int PROGRAM_TYPE_VENDOR_START = 1000; // 0x3e8
- }
-
- public static final class ProgramSelector.Identifier implements android.os.Parcelable {
- ctor public ProgramSelector.Identifier(@android.hardware.radio.ProgramSelector.IdentifierType int, long);
- method public int describeContents();
- method @android.hardware.radio.ProgramSelector.IdentifierType public int getType();
- method public long getValue();
- method public boolean isCategoryType();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.ProgramSelector.Identifier> CREATOR;
- }
-
- @IntDef(prefix={"IDENTIFIER_TYPE_"}, value={android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_INVALID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_RDS_PI, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_STATION_ID_EXT, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_SUBCHANNEL, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_HD_STATION_NAME, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SIDECC, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_SCID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_SERVICE_ID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_FREQUENCY, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_DRMO_MODULATION, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_SXM_SERVICE_ID, android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL}) @IntRange(from=android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_VENDOR_START, to=android.hardware.radio.ProgramSelector.IDENTIFIER_TYPE_VENDOR_END) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ProgramSelector.IdentifierType {
- }
-
- @Deprecated @IntDef(prefix={"PROGRAM_TYPE_"}, value={android.hardware.radio.ProgramSelector.PROGRAM_TYPE_INVALID, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_AM, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_FM, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_AM_HD, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_FM_HD, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_DAB, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_DRMO, android.hardware.radio.ProgramSelector.PROGRAM_TYPE_SXM}) @IntRange(from=android.hardware.radio.ProgramSelector.PROGRAM_TYPE_VENDOR_START, to=android.hardware.radio.ProgramSelector.PROGRAM_TYPE_VENDOR_END) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ProgramSelector.ProgramType {
- }
-
- public class RadioManager {
- method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public void addAnnouncementListener(@NonNull java.util.Set<java.lang.Integer>, @NonNull android.hardware.radio.Announcement.OnListUpdatedListener);
- method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public void addAnnouncementListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.Set<java.lang.Integer>, @NonNull android.hardware.radio.Announcement.OnListUpdatedListener);
- method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public int listModules(java.util.List<android.hardware.radio.RadioManager.ModuleProperties>);
- method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public android.hardware.radio.RadioTuner openTuner(int, android.hardware.radio.RadioManager.BandConfig, boolean, android.hardware.radio.RadioTuner.Callback, android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.ACCESS_BROADCAST_RADIO) public void removeAnnouncementListener(@NonNull android.hardware.radio.Announcement.OnListUpdatedListener);
- field public static final int BAND_AM = 0; // 0x0
- field public static final int BAND_AM_HD = 3; // 0x3
- field public static final int BAND_FM = 1; // 0x1
- field public static final int BAND_FM_HD = 2; // 0x2
- field public static final int BAND_INVALID = -1; // 0xffffffff
- field public static final int CLASS_AM_FM = 0; // 0x0
- field public static final int CLASS_DT = 2; // 0x2
- field public static final int CLASS_SAT = 1; // 0x1
- field public static final int CONFIG_DAB_DAB_LINKING = 6; // 0x6
- field public static final int CONFIG_DAB_DAB_SOFT_LINKING = 8; // 0x8
- field public static final int CONFIG_DAB_FM_LINKING = 7; // 0x7
- field public static final int CONFIG_DAB_FM_SOFT_LINKING = 9; // 0x9
- field public static final int CONFIG_FORCE_ANALOG = 2; // 0x2
- field public static final int CONFIG_FORCE_DIGITAL = 3; // 0x3
- field public static final int CONFIG_FORCE_MONO = 1; // 0x1
- field public static final int CONFIG_RDS_AF = 4; // 0x4
- field public static final int CONFIG_RDS_REG = 5; // 0x5
- field public static final int REGION_ITU_1 = 0; // 0x0
- field public static final int REGION_ITU_2 = 1; // 0x1
- field public static final int REGION_JAPAN = 3; // 0x3
- field public static final int REGION_KOREA = 4; // 0x4
- field public static final int REGION_OIRT = 2; // 0x2
- field public static final int STATUS_BAD_VALUE = -22; // 0xffffffea
- field public static final int STATUS_DEAD_OBJECT = -32; // 0xffffffe0
- field public static final int STATUS_ERROR = -2147483648; // 0x80000000
- field public static final int STATUS_INVALID_OPERATION = -38; // 0xffffffda
- field public static final int STATUS_NO_INIT = -19; // 0xffffffed
- field public static final int STATUS_OK = 0; // 0x0
- field public static final int STATUS_PERMISSION_DENIED = -1; // 0xffffffff
- field public static final int STATUS_TIMED_OUT = -110; // 0xffffff92
- }
-
- public static class RadioManager.AmBandConfig extends android.hardware.radio.RadioManager.BandConfig {
- method public boolean getStereo();
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.RadioManager.AmBandConfig> CREATOR;
- }
-
- public static class RadioManager.AmBandConfig.Builder {
- ctor public RadioManager.AmBandConfig.Builder(android.hardware.radio.RadioManager.AmBandDescriptor);
- ctor public RadioManager.AmBandConfig.Builder(android.hardware.radio.RadioManager.AmBandConfig);
- method public android.hardware.radio.RadioManager.AmBandConfig build();
- method public android.hardware.radio.RadioManager.AmBandConfig.Builder setStereo(boolean);
- }
-
- public static class RadioManager.AmBandDescriptor extends android.hardware.radio.RadioManager.BandDescriptor {
- method public boolean isStereoSupported();
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.RadioManager.AmBandDescriptor> CREATOR;
- }
-
- @IntDef(prefix={"BAND_"}, value={android.hardware.radio.RadioManager.BAND_INVALID, android.hardware.radio.RadioManager.BAND_AM, android.hardware.radio.RadioManager.BAND_FM, android.hardware.radio.RadioManager.BAND_AM_HD, android.hardware.radio.RadioManager.BAND_FM_HD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RadioManager.Band {
- }
-
- public static class RadioManager.BandConfig implements android.os.Parcelable {
- method public int describeContents();
- method public int getLowerLimit();
- method public int getRegion();
- method public int getSpacing();
- method public int getType();
- method public int getUpperLimit();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.RadioManager.BandConfig> CREATOR;
- }
-
- public static class RadioManager.BandDescriptor implements android.os.Parcelable {
- method public int describeContents();
- method public int getLowerLimit();
- method public int getRegion();
- method public int getSpacing();
- method public int getType();
- method public int getUpperLimit();
- method public boolean isAmBand();
- method public boolean isFmBand();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.RadioManager.BandDescriptor> CREATOR;
- }
-
- public static class RadioManager.FmBandConfig extends android.hardware.radio.RadioManager.BandConfig {
- method public boolean getAf();
- method public boolean getEa();
- method public boolean getRds();
- method public boolean getStereo();
- method public boolean getTa();
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.RadioManager.FmBandConfig> CREATOR;
- }
-
- public static class RadioManager.FmBandConfig.Builder {
- ctor public RadioManager.FmBandConfig.Builder(android.hardware.radio.RadioManager.FmBandDescriptor);
- ctor public RadioManager.FmBandConfig.Builder(android.hardware.radio.RadioManager.FmBandConfig);
- method public android.hardware.radio.RadioManager.FmBandConfig build();
- method public android.hardware.radio.RadioManager.FmBandConfig.Builder setAf(boolean);
- method public android.hardware.radio.RadioManager.FmBandConfig.Builder setEa(boolean);
- method public android.hardware.radio.RadioManager.FmBandConfig.Builder setRds(boolean);
- method public android.hardware.radio.RadioManager.FmBandConfig.Builder setStereo(boolean);
- method public android.hardware.radio.RadioManager.FmBandConfig.Builder setTa(boolean);
- }
-
- public static class RadioManager.FmBandDescriptor extends android.hardware.radio.RadioManager.BandDescriptor {
- method public boolean isAfSupported();
- method public boolean isEaSupported();
- method public boolean isRdsSupported();
- method public boolean isStereoSupported();
- method public boolean isTaSupported();
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.RadioManager.FmBandDescriptor> CREATOR;
- }
-
- public static class RadioManager.ModuleProperties implements android.os.Parcelable {
- method public int describeContents();
- method public android.hardware.radio.RadioManager.BandDescriptor[] getBands();
- method public int getClassId();
- method @Nullable public java.util.Map<java.lang.String,java.lang.Integer> getDabFrequencyTable();
- method public int getId();
- method public String getImplementor();
- method public int getNumAudioSources();
- method public int getNumTuners();
- method public String getProduct();
- method public String getSerial();
- method @NonNull public String getServiceName();
- method @NonNull public java.util.Map<java.lang.String,java.lang.String> getVendorInfo();
- method public String getVersion();
- method public boolean isBackgroundScanningSupported();
- method public boolean isCaptureSupported();
- method public boolean isInitializationRequired();
- method public boolean isProgramIdentifierSupported(@android.hardware.radio.ProgramSelector.IdentifierType int);
- method public boolean isProgramTypeSupported(@android.hardware.radio.ProgramSelector.ProgramType int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.RadioManager.ModuleProperties> CREATOR;
- }
-
- public static class RadioManager.ProgramInfo implements android.os.Parcelable {
- method public int describeContents();
- method @Deprecated public int getChannel();
- method @Nullable public android.hardware.radio.ProgramSelector.Identifier getLogicallyTunedTo();
- method public android.hardware.radio.RadioMetadata getMetadata();
- method @Nullable public android.hardware.radio.ProgramSelector.Identifier getPhysicallyTunedTo();
- method @Nullable public java.util.Collection<android.hardware.radio.ProgramSelector.Identifier> getRelatedContent();
- method @NonNull public android.hardware.radio.ProgramSelector getSelector();
- method public int getSignalStrength();
- method @Deprecated public int getSubChannel();
- method @NonNull public java.util.Map<java.lang.String,java.lang.String> getVendorInfo();
- method @Deprecated public boolean isDigital();
- method public boolean isLive();
- method public boolean isMuted();
- method public boolean isStereo();
- method public boolean isTrafficAnnouncementActive();
- method public boolean isTrafficProgram();
- method public boolean isTuned();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.RadioManager.ProgramInfo> CREATOR;
- }
-
- public final class RadioMetadata implements android.os.Parcelable {
- method public boolean containsKey(String);
- method public int describeContents();
- method @Deprecated public android.graphics.Bitmap getBitmap(String);
- method public android.hardware.radio.RadioMetadata.Clock getClock(String);
- method public int getInt(String);
- method public String getString(String);
- method public java.util.Set<java.lang.String> keySet();
- method public int size();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.RadioMetadata> CREATOR;
- field public static final String METADATA_KEY_ALBUM = "android.hardware.radio.metadata.ALBUM";
- field public static final String METADATA_KEY_ART = "android.hardware.radio.metadata.ART";
- field public static final String METADATA_KEY_ARTIST = "android.hardware.radio.metadata.ARTIST";
- field public static final String METADATA_KEY_CLOCK = "android.hardware.radio.metadata.CLOCK";
- field public static final String METADATA_KEY_DAB_COMPONENT_NAME = "android.hardware.radio.metadata.DAB_COMPONENT_NAME";
- field public static final String METADATA_KEY_DAB_COMPONENT_NAME_SHORT = "android.hardware.radio.metadata.DAB_COMPONENT_NAME_SHORT";
- field public static final String METADATA_KEY_DAB_ENSEMBLE_NAME = "android.hardware.radio.metadata.DAB_ENSEMBLE_NAME";
- field public static final String METADATA_KEY_DAB_ENSEMBLE_NAME_SHORT = "android.hardware.radio.metadata.DAB_ENSEMBLE_NAME_SHORT";
- field public static final String METADATA_KEY_DAB_SERVICE_NAME = "android.hardware.radio.metadata.DAB_SERVICE_NAME";
- field public static final String METADATA_KEY_DAB_SERVICE_NAME_SHORT = "android.hardware.radio.metadata.DAB_SERVICE_NAME_SHORT";
- field public static final String METADATA_KEY_GENRE = "android.hardware.radio.metadata.GENRE";
- field public static final String METADATA_KEY_ICON = "android.hardware.radio.metadata.ICON";
- field public static final String METADATA_KEY_PROGRAM_NAME = "android.hardware.radio.metadata.PROGRAM_NAME";
- field public static final String METADATA_KEY_RBDS_PTY = "android.hardware.radio.metadata.RBDS_PTY";
- field public static final String METADATA_KEY_RDS_PI = "android.hardware.radio.metadata.RDS_PI";
- field public static final String METADATA_KEY_RDS_PS = "android.hardware.radio.metadata.RDS_PS";
- field public static final String METADATA_KEY_RDS_PTY = "android.hardware.radio.metadata.RDS_PTY";
- field public static final String METADATA_KEY_RDS_RT = "android.hardware.radio.metadata.RDS_RT";
- field public static final String METADATA_KEY_TITLE = "android.hardware.radio.metadata.TITLE";
- }
-
- public static final class RadioMetadata.Builder {
- ctor public RadioMetadata.Builder();
- ctor public RadioMetadata.Builder(android.hardware.radio.RadioMetadata);
- method public android.hardware.radio.RadioMetadata build();
- method public android.hardware.radio.RadioMetadata.Builder putBitmap(String, android.graphics.Bitmap);
- method public android.hardware.radio.RadioMetadata.Builder putClock(String, long, int);
- method public android.hardware.radio.RadioMetadata.Builder putInt(String, int);
- method public android.hardware.radio.RadioMetadata.Builder putString(String, String);
- }
-
- public static final class RadioMetadata.Clock implements android.os.Parcelable {
- ctor public RadioMetadata.Clock(long, int);
- method public int describeContents();
- method public int getTimezoneOffsetMinutes();
- method public long getUtcEpochSeconds();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.radio.RadioMetadata.Clock> CREATOR;
- }
-
- public abstract class RadioTuner {
- ctor public RadioTuner();
- method public abstract int cancel();
- method public abstract void cancelAnnouncement();
- method public abstract void close();
- method @Deprecated public abstract int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
- method @Nullable public android.hardware.radio.ProgramList getDynamicProgramList(@Nullable android.hardware.radio.ProgramList.Filter);
- method public abstract boolean getMute();
- method @NonNull public java.util.Map<java.lang.String,java.lang.String> getParameters(@NonNull java.util.List<java.lang.String>);
- method @Deprecated public abstract int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
- method @Deprecated @NonNull public abstract java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(@Nullable java.util.Map<java.lang.String,java.lang.String>);
- method public abstract boolean hasControl();
- method @Deprecated public abstract boolean isAnalogForced();
- method @Deprecated public abstract boolean isAntennaConnected();
- method public boolean isConfigFlagSet(int);
- method public boolean isConfigFlagSupported(int);
- method public abstract int scan(int, boolean);
- method @Deprecated public abstract void setAnalogForced(boolean);
- method public void setConfigFlag(int, boolean);
- method @Deprecated public abstract int setConfiguration(android.hardware.radio.RadioManager.BandConfig);
- method public abstract int setMute(boolean);
- method @NonNull public java.util.Map<java.lang.String,java.lang.String> setParameters(@NonNull java.util.Map<java.lang.String,java.lang.String>);
- method public abstract boolean startBackgroundScan();
- method public abstract int step(int, boolean);
- method @Deprecated public abstract int tune(int, int);
- method public abstract void tune(@NonNull android.hardware.radio.ProgramSelector);
- field public static final int DIRECTION_DOWN = 1; // 0x1
- field public static final int DIRECTION_UP = 0; // 0x0
- field @Deprecated public static final int ERROR_BACKGROUND_SCAN_FAILED = 6; // 0x6
- field @Deprecated public static final int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5; // 0x5
- field @Deprecated public static final int ERROR_CANCELLED = 2; // 0x2
- field @Deprecated public static final int ERROR_CONFIG = 4; // 0x4
- field @Deprecated public static final int ERROR_HARDWARE_FAILURE = 0; // 0x0
- field @Deprecated public static final int ERROR_SCAN_TIMEOUT = 3; // 0x3
- field @Deprecated public static final int ERROR_SERVER_DIED = 1; // 0x1
- }
-
- public abstract static class RadioTuner.Callback {
- ctor public RadioTuner.Callback();
- method public void onAntennaState(boolean);
- method public void onBackgroundScanAvailabilityChange(boolean);
- method public void onBackgroundScanComplete();
- method @Deprecated public void onConfigurationChanged(android.hardware.radio.RadioManager.BandConfig);
- method public void onControlChanged(boolean);
- method public void onEmergencyAnnouncement(boolean);
- method @Deprecated public void onError(int);
- method @Deprecated public void onMetadataChanged(android.hardware.radio.RadioMetadata);
- method public void onParametersUpdated(@NonNull java.util.Map<java.lang.String,java.lang.String>);
- method public void onProgramInfoChanged(android.hardware.radio.RadioManager.ProgramInfo);
- method public void onProgramListChanged();
- method public void onTrafficAnnouncement(boolean);
- method public void onTuneFailed(int, @Nullable android.hardware.radio.ProgramSelector);
- }
-
-}
-
-package android.hardware.soundtrigger {
-
- public class SoundTrigger {
- field public static final int RECOGNITION_MODE_GENERIC = 8; // 0x8
- field public static final int RECOGNITION_MODE_USER_AUTHENTICATION = 4; // 0x4
- field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2
- field public static final int RECOGNITION_MODE_VOICE_TRIGGER = 1; // 0x1
- field public static final int STATUS_OK = 0; // 0x0
- }
-
- public static final class SoundTrigger.Keyphrase implements android.os.Parcelable {
- ctor public SoundTrigger.Keyphrase(int, int, @NonNull java.util.Locale, @NonNull String, @Nullable int[]);
- method public int getId();
- method @NonNull public java.util.Locale getLocale();
- method public int getRecognitionModes();
- method @NonNull public String getText();
- method @NonNull public int[] getUsers();
- method @NonNull public static android.hardware.soundtrigger.SoundTrigger.Keyphrase readFromParcel(@NonNull android.os.Parcel);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.Keyphrase> CREATOR;
- }
-
- public static final class SoundTrigger.KeyphraseSoundModel extends android.hardware.soundtrigger.SoundTrigger.SoundModel implements android.os.Parcelable {
- ctor public SoundTrigger.KeyphraseSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], @Nullable android.hardware.soundtrigger.SoundTrigger.Keyphrase[], int);
- ctor public SoundTrigger.KeyphraseSoundModel(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], @Nullable android.hardware.soundtrigger.SoundTrigger.Keyphrase[]);
- method @NonNull public android.hardware.soundtrigger.SoundTrigger.Keyphrase[] getKeyphrases();
- method @NonNull public static android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel readFromParcel(@NonNull android.os.Parcel);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel> CREATOR;
- }
-
- public static final class SoundTrigger.ModelParamRange implements android.os.Parcelable {
- method public int getEnd();
- method public int getStart();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.ModelParamRange> CREATOR;
- }
-
- public static final class SoundTrigger.ModuleProperties implements android.os.Parcelable {
- method public int describeContents();
- method public int getAudioCapabilities();
- method @NonNull public String getDescription();
- method public int getId();
- method @NonNull public String getImplementor();
- method public int getMaxBufferMillis();
- method public int getMaxKeyphrases();
- method public int getMaxSoundModels();
- method public int getMaxUsers();
- method public int getPowerConsumptionMw();
- method public int getRecognitionModes();
- method @NonNull public String getSupportedModelArch();
- method @NonNull public java.util.UUID getUuid();
- method public int getVersion();
- method public boolean isCaptureTransitionSupported();
- method public boolean isConcurrentCaptureSupported();
- method public boolean isTriggerReturnedInEvent();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int AUDIO_CAPABILITY_ECHO_CANCELLATION = 1; // 0x1
- field public static final int AUDIO_CAPABILITY_NOISE_SUPPRESSION = 2; // 0x2
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.ModuleProperties> CREATOR;
- }
-
- public static class SoundTrigger.RecognitionEvent {
- method @Nullable public android.media.AudioFormat getCaptureFormat();
- method public int getCaptureSession();
- method public byte[] getData();
- method public boolean isCaptureAvailable();
- }
-
- public static class SoundTrigger.SoundModel {
- method @NonNull public byte[] getData();
- method public int getType();
- method @NonNull public java.util.UUID getUuid();
- method @NonNull public java.util.UUID getVendorUuid();
- method public int getVersion();
- field public static final int TYPE_GENERIC_SOUND = 1; // 0x1
- field public static final int TYPE_KEYPHRASE = 0; // 0x0
- }
-
-}
-
-package android.hardware.usb {
-
- public class UsbDeviceConnection {
- method public boolean resetDevice();
- }
-
- public class UsbManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public long getCurrentFunctions();
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USB) public java.util.List<android.hardware.usb.UsbPort> getPorts();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void grantPermission(android.hardware.usb.UsbDevice, String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void resetUsbGadget();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long);
- field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_ACCESSORY_HANDSHAKE = "android.hardware.usb.action.USB_ACCESSORY_HANDSHAKE";
- field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
- field public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE";
- field public static final String EXTRA_ACCESSORY_HANDSHAKE_END = "android.hardware.usb.extra.ACCESSORY_HANDSHAKE_END";
- field public static final String EXTRA_ACCESSORY_START = "android.hardware.usb.extra.ACCESSORY_START";
- field public static final String EXTRA_ACCESSORY_STRING_COUNT = "android.hardware.usb.extra.ACCESSORY_STRING_COUNT";
- field public static final String EXTRA_ACCESSORY_UEVENT_TIME = "android.hardware.usb.extra.ACCESSORY_UEVENT_TIME";
- field public static final long FUNCTION_ACCESSORY = 2L; // 0x2L
- field public static final long FUNCTION_ADB = 1L; // 0x1L
- field public static final long FUNCTION_AUDIO_SOURCE = 64L; // 0x40L
- field public static final long FUNCTION_MIDI = 8L; // 0x8L
- field public static final long FUNCTION_MTP = 4L; // 0x4L
- field public static final long FUNCTION_NCM = 1024L; // 0x400L
- field public static final long FUNCTION_NONE = 0L; // 0x0L
- field public static final long FUNCTION_PTP = 16L; // 0x10L
- field public static final long FUNCTION_RNDIS = 32L; // 0x20L
- field public static final String USB_CONFIGURED = "configured";
- field public static final String USB_CONNECTED = "connected";
- field public static final String USB_FUNCTION_NCM = "ncm";
- field public static final String USB_FUNCTION_RNDIS = "rndis";
- }
-
- public final class UsbPort {
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
- }
-
- public final class UsbPortStatus implements android.os.Parcelable {
- method public int describeContents();
- method public int getCurrentDataRole();
- method public int getCurrentMode();
- method public int getCurrentPowerRole();
- method public int getSupportedRoleCombinations();
- method public boolean isConnected();
- method public boolean isRoleCombinationSupported(int, int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.hardware.usb.UsbPortStatus> CREATOR;
- field public static final int DATA_ROLE_DEVICE = 2; // 0x2
- field public static final int DATA_ROLE_HOST = 1; // 0x1
- field public static final int DATA_ROLE_NONE = 0; // 0x0
- field public static final int MODE_AUDIO_ACCESSORY = 4; // 0x4
- field public static final int MODE_DEBUG_ACCESSORY = 8; // 0x8
- field public static final int MODE_DFP = 2; // 0x2
- field public static final int MODE_NONE = 0; // 0x0
- field public static final int MODE_UFP = 1; // 0x1
- field public static final int POWER_ROLE_NONE = 0; // 0x0
- field public static final int POWER_ROLE_SINK = 2; // 0x2
- field public static final int POWER_ROLE_SOURCE = 1; // 0x1
- }
-
-}
-
-package android.location {
-
- public abstract class BatchedLocationCallback {
- ctor public BatchedLocationCallback();
- method public void onLocationBatch(java.util.List<android.location.Location>);
- }
-
- public final class GnssCapabilities {
- method public boolean hasGeofencing();
- method public boolean hasLowPowerMode();
- method public boolean hasMeasurementCorrections();
- method public boolean hasMeasurementCorrectionsExcessPathLength();
- method public boolean hasMeasurementCorrectionsLosSats();
- method public boolean hasMeasurementCorrectionsReflectingPane();
- method public boolean hasMeasurements();
- method public boolean hasNavMessages();
- method public boolean hasSatelliteBlacklist();
- }
-
- public final class GnssMeasurementCorrections implements android.os.Parcelable {
- method public int describeContents();
- method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
- method @FloatRange(from=0.0f, to=360.0f) public float getEnvironmentBearingDegrees();
- method @FloatRange(from=0.0f, to=180.0f) public float getEnvironmentBearingUncertaintyDegrees();
- method @FloatRange(from=0.0f) public double getHorizontalPositionUncertaintyMeters();
- method @FloatRange(from=-90.0F, to=90.0f) public double getLatitudeDegrees();
- method @FloatRange(from=-180.0F, to=180.0f) public double getLongitudeDegrees();
- method @NonNull public java.util.List<android.location.GnssSingleSatCorrection> getSingleSatelliteCorrectionList();
- method @IntRange(from=0) public long getToaGpsNanosecondsOfWeek();
- method @FloatRange(from=0.0f) public double getVerticalPositionUncertaintyMeters();
- method public boolean hasEnvironmentBearing();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementCorrections> CREATOR;
- }
-
- public static final class GnssMeasurementCorrections.Builder {
- ctor public GnssMeasurementCorrections.Builder();
- method @NonNull public android.location.GnssMeasurementCorrections build();
- method @NonNull public android.location.GnssMeasurementCorrections.Builder setAltitudeMeters(@FloatRange(from=-1000.0F, to=10000.0f) double);
- method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingDegrees(@FloatRange(from=0.0f, to=360.0f) float);
- method @NonNull public android.location.GnssMeasurementCorrections.Builder setEnvironmentBearingUncertaintyDegrees(@FloatRange(from=0.0f, to=180.0f) float);
- method @NonNull public android.location.GnssMeasurementCorrections.Builder setHorizontalPositionUncertaintyMeters(@FloatRange(from=0.0f) double);
- method @NonNull public android.location.GnssMeasurementCorrections.Builder setLatitudeDegrees(@FloatRange(from=-90.0F, to=90.0f) double);
- method @NonNull public android.location.GnssMeasurementCorrections.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double);
- method @NonNull public android.location.GnssMeasurementCorrections.Builder setSingleSatelliteCorrectionList(@NonNull java.util.List<android.location.GnssSingleSatCorrection>);
- method @NonNull public android.location.GnssMeasurementCorrections.Builder setToaGpsNanosecondsOfWeek(@IntRange(from=0) long);
- method @NonNull public android.location.GnssMeasurementCorrections.Builder setVerticalPositionUncertaintyMeters(@FloatRange(from=0.0f) double);
- }
-
- public final class GnssReflectingPlane implements android.os.Parcelable {
- method public int describeContents();
- method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
- method @FloatRange(from=0.0f, to=360.0f) public double getAzimuthDegrees();
- method @FloatRange(from=-90.0F, to=90.0f) public double getLatitudeDegrees();
- method @FloatRange(from=-180.0F, to=180.0f) public double getLongitudeDegrees();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.location.GnssReflectingPlane> CREATOR;
- }
-
- public static final class GnssReflectingPlane.Builder {
- ctor public GnssReflectingPlane.Builder();
- method @NonNull public android.location.GnssReflectingPlane build();
- method @NonNull public android.location.GnssReflectingPlane.Builder setAltitudeMeters(@FloatRange(from=-1000.0F, to=10000.0f) double);
- method @NonNull public android.location.GnssReflectingPlane.Builder setAzimuthDegrees(@FloatRange(from=0.0f, to=360.0f) double);
- method @NonNull public android.location.GnssReflectingPlane.Builder setLatitudeDegrees(@FloatRange(from=-90.0F, to=90.0f) double);
- method @NonNull public android.location.GnssReflectingPlane.Builder setLongitudeDegrees(@FloatRange(from=-180.0F, to=180.0f) double);
- }
-
- public final class GnssRequest implements android.os.Parcelable {
- method public int describeContents();
- method public boolean isFullTracking();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssRequest> CREATOR;
- }
-
- public static final class GnssRequest.Builder {
- ctor public GnssRequest.Builder();
- ctor public GnssRequest.Builder(@NonNull android.location.GnssRequest);
- method @NonNull public android.location.GnssRequest build();
- method @NonNull public android.location.GnssRequest.Builder setFullTracking(boolean);
- }
-
- public final class GnssSingleSatCorrection implements android.os.Parcelable {
- method public int describeContents();
- method @FloatRange(from=0.0f, fromInclusive=false) public float getCarrierFrequencyHz();
- method public int getConstellationType();
- method @FloatRange(from=0.0f) public float getExcessPathLengthMeters();
- method @FloatRange(from=0.0f) public float getExcessPathLengthUncertaintyMeters();
- method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
- method @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
- method @IntRange(from=0) public int getSatelliteId();
- method public boolean hasExcessPathLength();
- method public boolean hasExcessPathLengthUncertainty();
- method public boolean hasReflectingPlane();
- method public boolean hasValidSatelliteLineOfSight();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
- }
-
- public static final class GnssSingleSatCorrection.Builder {
- ctor public GnssSingleSatCorrection.Builder();
- method @NonNull public android.location.GnssSingleSatCorrection build();
- method @NonNull public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(@FloatRange(from=0.0f, fromInclusive=false) float);
- method @NonNull public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
- method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(@FloatRange(from=0.0f) float);
- method @NonNull public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(@FloatRange(from=0.0f) float);
- method @NonNull public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
- method @NonNull public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(@Nullable android.location.GnssReflectingPlane);
- method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int);
- }
-
- @Deprecated public class GpsClock implements android.os.Parcelable {
- method @Deprecated public int describeContents();
- method @Deprecated public double getBiasInNs();
- method @Deprecated public double getBiasUncertaintyInNs();
- method @Deprecated public double getDriftInNsPerSec();
- method @Deprecated public double getDriftUncertaintyInNsPerSec();
- method @Deprecated public long getFullBiasInNs();
- method @Deprecated public short getLeapSecond();
- method @Deprecated public long getTimeInNs();
- method @Deprecated public double getTimeUncertaintyInNs();
- method @Deprecated public byte getType();
- method @Deprecated public boolean hasBiasInNs();
- method @Deprecated public boolean hasBiasUncertaintyInNs();
- method @Deprecated public boolean hasDriftInNsPerSec();
- method @Deprecated public boolean hasDriftUncertaintyInNsPerSec();
- method @Deprecated public boolean hasFullBiasInNs();
- method @Deprecated public boolean hasLeapSecond();
- method @Deprecated public boolean hasTimeUncertaintyInNs();
- method @Deprecated public void reset();
- method @Deprecated public void resetBiasInNs();
- method @Deprecated public void resetBiasUncertaintyInNs();
- method @Deprecated public void resetDriftInNsPerSec();
- method @Deprecated public void resetDriftUncertaintyInNsPerSec();
- method @Deprecated public void resetFullBiasInNs();
- method @Deprecated public void resetLeapSecond();
- method @Deprecated public void resetTimeUncertaintyInNs();
- method @Deprecated public void set(android.location.GpsClock);
- method @Deprecated public void setBiasInNs(double);
- method @Deprecated public void setBiasUncertaintyInNs(double);
- method @Deprecated public void setDriftInNsPerSec(double);
- method @Deprecated public void setDriftUncertaintyInNsPerSec(double);
- method @Deprecated public void setFullBiasInNs(long);
- method @Deprecated public void setLeapSecond(short);
- method @Deprecated public void setTimeInNs(long);
- method @Deprecated public void setTimeUncertaintyInNs(double);
- method @Deprecated public void setType(byte);
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsClock> CREATOR;
- field @Deprecated public static final byte TYPE_GPS_TIME = 2; // 0x2
- field @Deprecated public static final byte TYPE_LOCAL_HW_TIME = 1; // 0x1
- field @Deprecated public static final byte TYPE_UNKNOWN = 0; // 0x0
- }
-
- @Deprecated public class GpsMeasurement implements android.os.Parcelable {
- method @Deprecated public int describeContents();
- method @Deprecated public double getAccumulatedDeltaRangeInMeters();
- method @Deprecated public short getAccumulatedDeltaRangeState();
- method @Deprecated public double getAccumulatedDeltaRangeUncertaintyInMeters();
- method @Deprecated public double getAzimuthInDeg();
- method @Deprecated public double getAzimuthUncertaintyInDeg();
- method @Deprecated public int getBitNumber();
- method @Deprecated public long getCarrierCycles();
- method @Deprecated public float getCarrierFrequencyInHz();
- method @Deprecated public double getCarrierPhase();
- method @Deprecated public double getCarrierPhaseUncertainty();
- method @Deprecated public double getCn0InDbHz();
- method @Deprecated public double getCodePhaseInChips();
- method @Deprecated public double getCodePhaseUncertaintyInChips();
- method @Deprecated public double getDopplerShiftInHz();
- method @Deprecated public double getDopplerShiftUncertaintyInHz();
- method @Deprecated public double getElevationInDeg();
- method @Deprecated public double getElevationUncertaintyInDeg();
- method @Deprecated public byte getLossOfLock();
- method @Deprecated public byte getMultipathIndicator();
- method @Deprecated public byte getPrn();
- method @Deprecated public double getPseudorangeInMeters();
- method @Deprecated public double getPseudorangeRateInMetersPerSec();
- method @Deprecated public double getPseudorangeRateUncertaintyInMetersPerSec();
- method @Deprecated public double getPseudorangeUncertaintyInMeters();
- method @Deprecated public long getReceivedGpsTowInNs();
- method @Deprecated public long getReceivedGpsTowUncertaintyInNs();
- method @Deprecated public double getSnrInDb();
- method @Deprecated public short getState();
- method @Deprecated public short getTimeFromLastBitInMs();
- method @Deprecated public double getTimeOffsetInNs();
- method @Deprecated public boolean hasAzimuthInDeg();
- method @Deprecated public boolean hasAzimuthUncertaintyInDeg();
- method @Deprecated public boolean hasBitNumber();
- method @Deprecated public boolean hasCarrierCycles();
- method @Deprecated public boolean hasCarrierFrequencyInHz();
- method @Deprecated public boolean hasCarrierPhase();
- method @Deprecated public boolean hasCarrierPhaseUncertainty();
- method @Deprecated public boolean hasCodePhaseInChips();
- method @Deprecated public boolean hasCodePhaseUncertaintyInChips();
- method @Deprecated public boolean hasDopplerShiftInHz();
- method @Deprecated public boolean hasDopplerShiftUncertaintyInHz();
- method @Deprecated public boolean hasElevationInDeg();
- method @Deprecated public boolean hasElevationUncertaintyInDeg();
- method @Deprecated public boolean hasPseudorangeInMeters();
- method @Deprecated public boolean hasPseudorangeUncertaintyInMeters();
- method @Deprecated public boolean hasSnrInDb();
- method @Deprecated public boolean hasTimeFromLastBitInMs();
- method @Deprecated public boolean isPseudorangeRateCorrected();
- method @Deprecated public boolean isUsedInFix();
- method @Deprecated public void reset();
- method @Deprecated public void resetAzimuthInDeg();
- method @Deprecated public void resetAzimuthUncertaintyInDeg();
- method @Deprecated public void resetBitNumber();
- method @Deprecated public void resetCarrierCycles();
- method @Deprecated public void resetCarrierFrequencyInHz();
- method @Deprecated public void resetCarrierPhase();
- method @Deprecated public void resetCarrierPhaseUncertainty();
- method @Deprecated public void resetCodePhaseInChips();
- method @Deprecated public void resetCodePhaseUncertaintyInChips();
- method @Deprecated public void resetDopplerShiftInHz();
- method @Deprecated public void resetDopplerShiftUncertaintyInHz();
- method @Deprecated public void resetElevationInDeg();
- method @Deprecated public void resetElevationUncertaintyInDeg();
- method @Deprecated public void resetPseudorangeInMeters();
- method @Deprecated public void resetPseudorangeUncertaintyInMeters();
- method @Deprecated public void resetSnrInDb();
- method @Deprecated public void resetTimeFromLastBitInMs();
- method @Deprecated public void set(android.location.GpsMeasurement);
- method @Deprecated public void setAccumulatedDeltaRangeInMeters(double);
- method @Deprecated public void setAccumulatedDeltaRangeState(short);
- method @Deprecated public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
- method @Deprecated public void setAzimuthInDeg(double);
- method @Deprecated public void setAzimuthUncertaintyInDeg(double);
- method @Deprecated public void setBitNumber(int);
- method @Deprecated public void setCarrierCycles(long);
- method @Deprecated public void setCarrierFrequencyInHz(float);
- method @Deprecated public void setCarrierPhase(double);
- method @Deprecated public void setCarrierPhaseUncertainty(double);
- method @Deprecated public void setCn0InDbHz(double);
- method @Deprecated public void setCodePhaseInChips(double);
- method @Deprecated public void setCodePhaseUncertaintyInChips(double);
- method @Deprecated public void setDopplerShiftInHz(double);
- method @Deprecated public void setDopplerShiftUncertaintyInHz(double);
- method @Deprecated public void setElevationInDeg(double);
- method @Deprecated public void setElevationUncertaintyInDeg(double);
- method @Deprecated public void setLossOfLock(byte);
- method @Deprecated public void setMultipathIndicator(byte);
- method @Deprecated public void setPrn(byte);
- method @Deprecated public void setPseudorangeInMeters(double);
- method @Deprecated public void setPseudorangeRateInMetersPerSec(double);
- method @Deprecated public void setPseudorangeRateUncertaintyInMetersPerSec(double);
- method @Deprecated public void setPseudorangeUncertaintyInMeters(double);
- method @Deprecated public void setReceivedGpsTowInNs(long);
- method @Deprecated public void setReceivedGpsTowUncertaintyInNs(long);
- method @Deprecated public void setSnrInDb(double);
- method @Deprecated public void setState(short);
- method @Deprecated public void setTimeFromLastBitInMs(short);
- method @Deprecated public void setTimeOffsetInNs(double);
- method @Deprecated public void setUsedInFix(boolean);
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
- field @Deprecated public static final short ADR_STATE_RESET = 2; // 0x2
- field @Deprecated public static final short ADR_STATE_UNKNOWN = 0; // 0x0
- field @Deprecated public static final short ADR_STATE_VALID = 1; // 0x1
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsMeasurement> CREATOR;
- field @Deprecated public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
- field @Deprecated public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
- field @Deprecated public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
- field @Deprecated public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
- field @Deprecated public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
- field @Deprecated public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
- field @Deprecated public static final short STATE_BIT_SYNC = 2; // 0x2
- field @Deprecated public static final short STATE_CODE_LOCK = 1; // 0x1
- field @Deprecated public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
- field @Deprecated public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
- field @Deprecated public static final short STATE_TOW_DECODED = 8; // 0x8
- field @Deprecated public static final short STATE_UNKNOWN = 0; // 0x0
- }
-
- @Deprecated public class GpsMeasurementsEvent implements android.os.Parcelable {
- ctor @Deprecated public GpsMeasurementsEvent(android.location.GpsClock, android.location.GpsMeasurement[]);
- method @Deprecated public int describeContents();
- method @Deprecated @NonNull public android.location.GpsClock getClock();
- method @Deprecated @NonNull public java.util.Collection<android.location.GpsMeasurement> getMeasurements();
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsMeasurementsEvent> CREATOR;
- field @Deprecated public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
- field @Deprecated public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
- field @Deprecated public static final int STATUS_READY = 1; // 0x1
- }
-
- @Deprecated public static interface GpsMeasurementsEvent.Listener {
- method @Deprecated public void onGpsMeasurementsReceived(android.location.GpsMeasurementsEvent);
- method @Deprecated public void onStatusChanged(int);
- }
-
- @Deprecated public class GpsNavigationMessage implements android.os.Parcelable {
- method @Deprecated public int describeContents();
- method @Deprecated @NonNull public byte[] getData();
- method @Deprecated public short getMessageId();
- method @Deprecated public byte getPrn();
- method @Deprecated public short getStatus();
- method @Deprecated public short getSubmessageId();
- method @Deprecated public byte getType();
- method @Deprecated public void reset();
- method @Deprecated public void set(android.location.GpsNavigationMessage);
- method @Deprecated public void setData(byte[]);
- method @Deprecated public void setMessageId(short);
- method @Deprecated public void setPrn(byte);
- method @Deprecated public void setStatus(short);
- method @Deprecated public void setSubmessageId(short);
- method @Deprecated public void setType(byte);
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessage> CREATOR;
- field @Deprecated public static final short STATUS_PARITY_PASSED = 1; // 0x1
- field @Deprecated public static final short STATUS_PARITY_REBUILT = 2; // 0x2
- field @Deprecated public static final short STATUS_UNKNOWN = 0; // 0x0
- field @Deprecated public static final byte TYPE_CNAV2 = 4; // 0x4
- field @Deprecated public static final byte TYPE_L1CA = 1; // 0x1
- field @Deprecated public static final byte TYPE_L2CNAV = 2; // 0x2
- field @Deprecated public static final byte TYPE_L5CNAV = 3; // 0x3
- field @Deprecated public static final byte TYPE_UNKNOWN = 0; // 0x0
- }
-
- @Deprecated public class GpsNavigationMessageEvent implements android.os.Parcelable {
- ctor @Deprecated public GpsNavigationMessageEvent(android.location.GpsNavigationMessage);
- method @Deprecated public int describeContents();
- method @Deprecated @NonNull public android.location.GpsNavigationMessage getNavigationMessage();
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.location.GpsNavigationMessageEvent> CREATOR;
- field @Deprecated public static int STATUS_GPS_LOCATION_DISABLED;
- field @Deprecated public static int STATUS_NOT_SUPPORTED;
- field @Deprecated public static int STATUS_READY;
- }
-
- @Deprecated public static interface GpsNavigationMessageEvent.Listener {
- method @Deprecated public void onGpsNavigationMessageReceived(android.location.GpsNavigationMessageEvent);
- method @Deprecated public void onStatusChanged(int);
- }
-
- public class Location implements android.os.Parcelable {
- method public boolean isComplete();
- method public void makeComplete();
- method public void setIsFromMockProvider(boolean);
- field @Deprecated public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
- }
-
- public class LocationManager {
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
- method @Nullable public String getExtraLocationControllerPackage();
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
- method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
- method public boolean isExtraLocationControllerPackageEnabled();
- method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
- method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
- method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
- method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
- method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
- }
-
- public final class LocationRequest implements android.os.Parcelable {
- method @Deprecated @NonNull public static android.location.LocationRequest create();
- method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedCriteria(@NonNull android.location.Criteria, long, float, boolean);
- method @Deprecated @NonNull public static android.location.LocationRequest createFromDeprecatedProvider(@NonNull String, long, float, boolean);
- method @Deprecated public long getExpireAt();
- method @Deprecated public long getExpireIn();
- method @Deprecated public long getFastestInterval();
- method @Deprecated public boolean getHideFromAppOps();
- method @Deprecated public long getInterval();
- method @Deprecated public int getNumUpdates();
- method @Deprecated @NonNull public String getProvider();
- method @Deprecated public float getSmallestDisplacement();
- method @NonNull public android.os.WorkSource getWorkSource();
- method public boolean isHiddenFromAppOps();
- method public boolean isLocationSettingsIgnored();
- method public boolean isLowPower();
- method @Deprecated public boolean isLowPowerMode();
- method @Deprecated @NonNull public android.location.LocationRequest setExpireAt(long);
- method @Deprecated @NonNull public android.location.LocationRequest setExpireIn(long);
- method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long);
- method @Deprecated public void setHideFromAppOps(boolean);
- method @Deprecated @NonNull public android.location.LocationRequest setInterval(long);
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean);
- method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean);
- method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int);
- method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String);
- method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
- method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
- method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
- field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
- field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
- field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
- field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
- field @Deprecated public static final int POWER_LOW = 201; // 0xc9
- field @Deprecated public static final int POWER_NONE = 200; // 0xc8
- }
-
- public static final class LocationRequest.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
- }
-
-}
-
-package android.media {
-
- public final class AudioAttributes implements android.os.Parcelable {
- method public int getAllFlags();
- method public android.os.Bundle getBundle();
- method public int getCapturePreset();
- method public int getSystemUsage();
- method public static boolean isSystemUsage(int);
- field public static final int FLAG_BEACON = 8; // 0x8
- field public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 64; // 0x40
- field public static final int FLAG_BYPASS_MUTE = 128; // 0x80
- field public static final int FLAG_HW_HOTWORD = 32; // 0x20
- field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_ANNOUNCEMENT = 1003; // 0x3eb
- field @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public static final int USAGE_CALL_ASSISTANT = 17; // 0x11
- field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_EMERGENCY = 1000; // 0x3e8
- field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_SAFETY = 1001; // 0x3e9
- field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int USAGE_VEHICLE_STATUS = 1002; // 0x3ea
- }
-
- public static class AudioAttributes.Builder {
- method public android.media.AudioAttributes.Builder addBundle(@NonNull android.os.Bundle);
- method public android.media.AudioAttributes.Builder setCapturePreset(int);
- method public android.media.AudioAttributes.Builder setInternalCapturePreset(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioAttributes.Builder setSystemUsage(int);
- }
-
- public final class AudioDeviceAttributes implements android.os.Parcelable {
- ctor public AudioDeviceAttributes(@NonNull android.media.AudioDeviceInfo);
- ctor public AudioDeviceAttributes(int, int, @NonNull String);
- method public int describeContents();
- method @NonNull public String getAddress();
- method public int getRole();
- method public int getType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioDeviceAttributes> CREATOR;
- field public static final int ROLE_INPUT = 1; // 0x1
- field public static final int ROLE_OUTPUT = 2; // 0x2
- }
-
- public final class AudioFocusInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.media.AudioAttributes getAttributes();
- method @NonNull public String getClientId();
- method public int getClientUid();
- method public int getFlags();
- method public int getGainRequest();
- method public int getLossReceived();
- method @NonNull public String getPackageName();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioFocusInfo> CREATOR;
- }
-
- public final class AudioFocusRequest {
- method public boolean locksFocus();
- }
-
- public static final class AudioFocusRequest.Builder {
- method @NonNull public android.media.AudioFocusRequest.Builder setLocksFocus(boolean);
- }
-
- public class AudioManager {
- method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
- method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException;
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForCapturePresetChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener) throws java.lang.SecurityException;
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException;
- method public void clearAudioServerStateCallback();
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean clearPreferredDevicesForCapturePreset(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
- method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
- method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
- method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
- method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
- method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAttributes getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages();
- method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
- method public boolean isAudioServerRunning();
- method public boolean isHdmiSystemAudioSupported();
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
- method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForCapturePresetChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
- method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForCapturePreset(int, @NonNull android.media.AudioDeviceAttributes);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy);
- method public void unregisterVolumeGroupCallback(@NonNull android.media.AudioManager.VolumeGroupCallback);
- field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
- field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
- field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
- field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; // 0x3
- field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; // 0x4
- field public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; // 0x2
- field public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; // 0x1
- field public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; // 0x0
- field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int STREAM_ASSISTANT = 11; // 0xb
- field public static final int SUCCESS = 0; // 0x0
- }
-
- public abstract static class AudioManager.AudioServerStateCallback {
- ctor public AudioManager.AudioServerStateCallback();
- method public void onAudioServerDown();
- method public void onAudioServerUp();
- }
-
- @Deprecated public static interface AudioManager.OnPreferredDeviceForStrategyChangedListener {
- method @Deprecated public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes);
- }
-
- public static interface AudioManager.OnPreferredDevicesForCapturePresetChangedListener {
- method public void onPreferredDevicesForCapturePresetChanged(int, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
- }
-
- public static interface AudioManager.OnPreferredDevicesForStrategyChangedListener {
- method public void onPreferredDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>);
- }
-
- public abstract static class AudioManager.VolumeGroupCallback {
- ctor public AudioManager.VolumeGroupCallback();
- method public void onAudioVolumeGroupChanged(int, int);
- }
-
- public final class AudioPlaybackConfiguration implements android.os.Parcelable {
- method public int getClientPid();
- method public int getClientUid();
- method public int getPlayerInterfaceId();
- method public android.media.PlayerProxy getPlayerProxy();
- method public int getPlayerState();
- method public int getPlayerType();
- method public boolean isActive();
- field public static final int PLAYER_STATE_IDLE = 1; // 0x1
- field public static final int PLAYER_STATE_PAUSED = 3; // 0x3
- field public static final int PLAYER_STATE_RELEASED = 0; // 0x0
- field public static final int PLAYER_STATE_STARTED = 2; // 0x2
- field public static final int PLAYER_STATE_STOPPED = 4; // 0x4
- field public static final int PLAYER_STATE_UNKNOWN = -1; // 0xffffffff
- field public static final int PLAYER_TYPE_JAM_AUDIOTRACK = 1; // 0x1
- field public static final int PLAYER_TYPE_JAM_MEDIAPLAYER = 2; // 0x2
- field public static final int PLAYER_TYPE_JAM_SOUNDPOOL = 3; // 0x3
- field public static final int PLAYER_TYPE_SLES_AUDIOPLAYER_BUFFERQUEUE = 11; // 0xb
- field public static final int PLAYER_TYPE_SLES_AUDIOPLAYER_URI_FD = 12; // 0xc
- field public static final int PLAYER_TYPE_UNKNOWN = -1; // 0xffffffff
- }
-
- public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection {
- ctor public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException;
- }
-
- public static class AudioRecord.Builder {
- method public android.media.AudioRecord.Builder setAudioAttributes(@NonNull android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
- method public android.media.AudioRecord.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
- }
-
- public final class AudioRecordingConfiguration implements android.os.Parcelable {
- method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getClientUid();
- }
-
- public class AudioTrack implements android.media.AudioRouting android.media.VolumeAutomation {
- field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int ENCAPSULATION_MODE_HANDLE = 2; // 0x2
- }
-
- public static class AudioTrack.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioTrack.Builder setTunerConfiguration(@NonNull android.media.AudioTrack.TunerConfiguration);
- }
-
- public static class AudioTrack.TunerConfiguration {
- ctor @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public AudioTrack.TunerConfiguration(@IntRange(from=1) int, @IntRange(from=1) int);
- method @IntRange(from=1) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getContentId();
- method @IntRange(from=1) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getSyncId();
- }
-
- public class HwAudioSource {
- method public boolean isPlaying();
- method public void start();
- method public void stop();
- }
-
- public static final class HwAudioSource.Builder {
- ctor public HwAudioSource.Builder();
- method @NonNull public android.media.HwAudioSource build();
- method @NonNull public android.media.HwAudioSource.Builder setAudioAttributes(@NonNull android.media.AudioAttributes);
- method @NonNull public android.media.HwAudioSource.Builder setAudioDeviceInfo(@NonNull android.media.AudioDeviceInfo);
- }
-
- public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
- method @RequiresPermission("android.permission.BIND_IMS_SERVICE") public void setOnImsRxNoticeListener(@Nullable android.media.MediaPlayer.OnImsRxNoticeListener, @Nullable android.os.Handler);
- }
-
- public static interface MediaPlayer.OnImsRxNoticeListener {
- method public void onImsRxNotice(@NonNull android.media.MediaPlayer, @NonNull byte[]);
- }
-
- public final class MediaRecorder.AudioSource {
- field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int ECHO_REFERENCE = 1997; // 0x7cd
- field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD) public static final int HOTWORD = 1999; // 0x7cf
- field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int RADIO_TUNER = 1998; // 0x7ce
- }
-
- public final class MediaTranscodeManager {
- method @NonNull public android.media.MediaTranscodeManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException, android.media.MediaTranscodingException.ServiceNotAvailableException;
- field public static final int PRIORITY_REALTIME = 1; // 0x1
- field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
- }
-
- @java.lang.FunctionalInterface public static interface MediaTranscodeManager.OnTranscodingFinishedListener {
- method public void onTranscodingFinished(@NonNull android.media.MediaTranscodeManager.TranscodingSession);
- }
-
- public static final class MediaTranscodeManager.TranscodingRequest {
- method public int getClientPid();
- method public int getClientUid();
- method @NonNull public android.net.Uri getDestinationUri();
- method public int getPriority();
- method @NonNull public android.net.Uri getSourceUri();
- method public int getType();
- method @Nullable public android.media.MediaFormat getVideoTrackFormat();
- }
-
- public static final class MediaTranscodeManager.TranscodingRequest.Builder {
- ctor public MediaTranscodeManager.TranscodingRequest.Builder();
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientPid(int);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientUid(int);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setType(int);
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setVideoTrackFormat(@NonNull android.media.MediaFormat);
- }
-
- public static class MediaTranscodeManager.TranscodingRequest.MediaFormatResolver {
- ctor public MediaTranscodeManager.TranscodingRequest.MediaFormatResolver();
- method @Nullable public android.media.MediaFormat resolveVideoFormat();
- method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.MediaFormatResolver setSourceVideoFormatHint(@NonNull android.media.MediaFormat);
- method public boolean shouldTranscode();
- field public static final String CAPS_SUPPORTS_HEVC = "support-hevc";
- }
-
- public static final class MediaTranscodeManager.TranscodingSession {
- method public void cancel();
- method @IntRange(from=0, to=100) public int getProgress();
- method public int getResult();
- method public int getSessionId();
- method public int getStatus();
- method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
- method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
- field public static final int RESULT_CANCELED = 4; // 0x4
- field public static final int RESULT_ERROR = 3; // 0x3
- field public static final int RESULT_NONE = 1; // 0x1
- field public static final int RESULT_SUCCESS = 2; // 0x2
- field public static final int STATUS_FINISHED = 3; // 0x3
- field public static final int STATUS_PAUSED = 4; // 0x4
- field public static final int STATUS_PENDING = 1; // 0x1
- field public static final int STATUS_RUNNING = 2; // 0x2
- }
-
- @java.lang.FunctionalInterface public static interface MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener {
- method public void onProgressUpdate(@NonNull android.media.MediaTranscodeManager.TranscodingSession, @IntRange(from=0, to=100) int);
- }
-
- public class PlayerProxy {
- method public void pause();
- method public void setPan(float);
- method public void setStartDelayMs(int);
- method public void setVolume(float);
- method public void start();
- method public void stop();
- }
-
- public class RingtoneManager {
- method @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) public static void ensureDefaultRingtones(@NonNull android.content.Context);
- }
-
-}
-
-package android.media.audiofx {
-
- public class AudioEffect {
- ctor @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public AudioEffect(@NonNull java.util.UUID, @NonNull android.media.AudioDeviceAttributes);
- method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public static boolean isEffectSupportedForDevice(@NonNull java.util.UUID, @NonNull android.media.AudioDeviceAttributes);
- }
-
-}
-
-package android.media.audiopolicy {
-
- public class AudioMix {
- method public int getMixState();
- field public static final int MIX_STATE_DISABLED = -1; // 0xffffffff
- field public static final int MIX_STATE_IDLE = 0; // 0x0
- field public static final int MIX_STATE_MIXING = 1; // 0x1
- field public static final int ROUTE_FLAG_LOOP_BACK = 2; // 0x2
- field public static final int ROUTE_FLAG_RENDER = 1; // 0x1
- }
-
- public static class AudioMix.Builder {
- ctor public AudioMix.Builder(android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException;
- method public android.media.audiopolicy.AudioMix build() throws java.lang.IllegalArgumentException;
- method public android.media.audiopolicy.AudioMix.Builder setDevice(@NonNull android.media.AudioDeviceInfo) throws java.lang.IllegalArgumentException;
- method public android.media.audiopolicy.AudioMix.Builder setFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
- method public android.media.audiopolicy.AudioMix.Builder setRouteFlags(int) throws java.lang.IllegalArgumentException;
- }
-
- public class AudioMixingRule {
- field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
- field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1
- field public static final int RULE_MATCH_UID = 4; // 0x4
- field public static final int RULE_MATCH_USERID = 8; // 0x8
- }
-
- public static class AudioMixingRule.Builder {
- ctor public AudioMixingRule.Builder();
- method public android.media.audiopolicy.AudioMixingRule.Builder addMixRule(int, Object) throws java.lang.IllegalArgumentException;
- method public android.media.audiopolicy.AudioMixingRule.Builder addRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
- method @NonNull public android.media.audiopolicy.AudioMixingRule.Builder allowPrivilegedPlaybackCapture(boolean);
- method public android.media.audiopolicy.AudioMixingRule build();
- method public android.media.audiopolicy.AudioMixingRule.Builder excludeMixRule(int, Object) throws java.lang.IllegalArgumentException;
- method public android.media.audiopolicy.AudioMixingRule.Builder excludeRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
- }
-
- public class AudioPolicy {
- method public int attachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>);
- method public android.media.AudioRecord createAudioRecordSink(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
- method public android.media.AudioTrack createAudioTrackSource(android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
- method public int detachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>);
- method public int getFocusDuckingBehavior();
- method public int getStatus();
- method public boolean removeUidDeviceAffinity(int);
- method public boolean removeUserIdDeviceAffinity(int);
- method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
- method public void setRegistration(String);
- method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
- method public boolean setUserIdDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
- method public String toLogFriendlyString();
- field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0
- field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0
- field public static final int FOCUS_POLICY_DUCKING_IN_POLICY = 1; // 0x1
- field public static final int POLICY_STATUS_REGISTERED = 2; // 0x2
- field public static final int POLICY_STATUS_UNREGISTERED = 1; // 0x1
- }
-
- public abstract static class AudioPolicy.AudioPolicyFocusListener {
- ctor public AudioPolicy.AudioPolicyFocusListener();
- method public void onAudioFocusAbandon(android.media.AudioFocusInfo);
- method public void onAudioFocusGrant(android.media.AudioFocusInfo, int);
- method public void onAudioFocusLoss(android.media.AudioFocusInfo, boolean);
- method public void onAudioFocusRequest(android.media.AudioFocusInfo, int);
- }
-
- public abstract static class AudioPolicy.AudioPolicyStatusListener {
- ctor public AudioPolicy.AudioPolicyStatusListener();
- method public void onMixStateUpdate(android.media.audiopolicy.AudioMix);
- method public void onStatusChange();
- }
-
- public abstract static class AudioPolicy.AudioPolicyVolumeCallback {
- ctor public AudioPolicy.AudioPolicyVolumeCallback();
- method public void onVolumeAdjustment(int);
- }
-
- public static class AudioPolicy.Builder {
- ctor public AudioPolicy.Builder(android.content.Context);
- method @NonNull public android.media.audiopolicy.AudioPolicy.Builder addMix(@NonNull android.media.audiopolicy.AudioMix) throws java.lang.IllegalArgumentException;
- method @NonNull public android.media.audiopolicy.AudioPolicy build();
- method public void setAudioPolicyFocusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener);
- method public void setAudioPolicyStatusListener(android.media.audiopolicy.AudioPolicy.AudioPolicyStatusListener);
- method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setAudioPolicyVolumeCallback(@NonNull android.media.audiopolicy.AudioPolicy.AudioPolicyVolumeCallback);
- method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsAudioFocusPolicy(boolean);
- method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setLooper(@NonNull android.os.Looper) throws java.lang.IllegalArgumentException;
- }
-
- public final class AudioProductStrategy implements android.os.Parcelable {
- method @NonNull public static android.media.audiopolicy.AudioProductStrategy createInvalidAudioProductStrategy(int);
- method public int describeContents();
- method @NonNull public android.media.AudioAttributes getAudioAttributes();
- method public int getId();
- method public boolean supportsAudioAttributes(@NonNull android.media.AudioAttributes);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioProductStrategy> CREATOR;
- }
-
- public final class AudioVolumeGroup implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public java.util.List<android.media.AudioAttributes> getAudioAttributes();
- method public int getId();
- method @NonNull public int[] getLegacyStreamTypes();
- method @NonNull public String name();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioVolumeGroup> CREATOR;
- field public static final int DEFAULT_VOLUME_GROUP = -1; // 0xffffffff
- }
-
-}
-
-package android.media.musicrecognition {
-
- public class MusicRecognitionManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_MUSIC_RECOGNITION) public void beginStreamingSearch(@NonNull android.media.musicrecognition.RecognitionRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.musicrecognition.MusicRecognitionManager.RecognitionCallback);
- field public static final int RECOGNITION_FAILED_AUDIO_UNAVAILABLE = 7; // 0x7
- field public static final int RECOGNITION_FAILED_NOT_FOUND = 1; // 0x1
- field public static final int RECOGNITION_FAILED_NO_CONNECTIVITY = 2; // 0x2
- field public static final int RECOGNITION_FAILED_SERVICE_KILLED = 5; // 0x5
- field public static final int RECOGNITION_FAILED_SERVICE_UNAVAILABLE = 3; // 0x3
- field public static final int RECOGNITION_FAILED_TIMEOUT = 6; // 0x6
- field public static final int RECOGNITION_FAILED_UNKNOWN = -1; // 0xffffffff
- }
-
- public static interface MusicRecognitionManager.RecognitionCallback {
- method public void onAudioStreamClosed();
- method public void onRecognitionFailed(@NonNull android.media.musicrecognition.RecognitionRequest, int);
- method public void onRecognitionSucceeded(@NonNull android.media.musicrecognition.RecognitionRequest, @NonNull android.media.MediaMetadata, @Nullable android.os.Bundle);
- }
-
- public abstract class MusicRecognitionService extends android.app.Service {
- ctor public MusicRecognitionService();
- method public abstract void onRecognize(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @NonNull android.media.musicrecognition.MusicRecognitionService.Callback);
- }
-
- public static interface MusicRecognitionService.Callback {
- method public void onRecognitionFailed(int);
- method public void onRecognitionSucceeded(@NonNull android.media.MediaMetadata, @Nullable android.os.Bundle);
- }
-
- public final class RecognitionRequest implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.media.AudioAttributes getAudioAttributes();
- method @NonNull public android.media.AudioFormat getAudioFormat();
- method public int getCaptureSession();
- method public int getIgnoreBeginningFrames();
- method public int getMaxAudioLengthSeconds();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.musicrecognition.RecognitionRequest> CREATOR;
- }
-
- public static final class RecognitionRequest.Builder {
- ctor public RecognitionRequest.Builder();
- method @NonNull public android.media.musicrecognition.RecognitionRequest build();
- method @NonNull public android.media.musicrecognition.RecognitionRequest.Builder setAudioAttributes(@NonNull android.media.AudioAttributes);
- method @NonNull public android.media.musicrecognition.RecognitionRequest.Builder setAudioFormat(@NonNull android.media.AudioFormat);
- method @NonNull public android.media.musicrecognition.RecognitionRequest.Builder setCaptureSession(int);
- method @NonNull public android.media.musicrecognition.RecognitionRequest.Builder setIgnoreBeginningFrames(int);
- method @NonNull public android.media.musicrecognition.RecognitionRequest.Builder setMaxAudioLengthSeconds(int);
- }
-
-}
-
-package android.media.session {
-
- public final class MediaSessionManager {
- method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventDispatchedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener);
- method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void addOnMediaKeyEventSessionChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener);
- method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventDispatchedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventDispatchedListener);
- method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void removeOnMediaKeyEventSessionChangedListener(@NonNull android.media.session.MediaSessionManager.OnMediaKeyEventSessionChangedListener);
- method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler);
- }
-
- public static interface MediaSessionManager.OnMediaKeyEventDispatchedListener {
- method public void onMediaKeyEventDispatched(@NonNull android.view.KeyEvent, @NonNull String, @Nullable android.media.session.MediaSession.Token);
- }
-
- public static interface MediaSessionManager.OnMediaKeyEventSessionChangedListener {
- method public void onMediaKeyEventSessionChanged(@NonNull String, @Nullable android.media.session.MediaSession.Token);
- }
-
- public static interface MediaSessionManager.OnMediaKeyListener {
- method public boolean onMediaKey(android.view.KeyEvent);
- }
-
- public static interface MediaSessionManager.OnVolumeKeyLongPressListener {
- method public void onVolumeKeyLongPress(android.view.KeyEvent);
- }
-
-}
-
-package android.media.soundtrigger {
-
- public abstract class SoundTriggerDetectionService extends android.app.Service {
- ctor public SoundTriggerDetectionService();
- method @MainThread public void onConnected(@NonNull java.util.UUID, @Nullable android.os.Bundle);
- method @MainThread public void onDisconnected(@NonNull java.util.UUID, @Nullable android.os.Bundle);
- method @MainThread public void onError(@NonNull java.util.UUID, @Nullable android.os.Bundle, int, int);
- method @MainThread public void onGenericRecognitionEvent(@NonNull java.util.UUID, @Nullable android.os.Bundle, int, @NonNull android.hardware.soundtrigger.SoundTrigger.RecognitionEvent);
- method @MainThread public abstract void onStopOperation(@NonNull java.util.UUID, @Nullable android.os.Bundle, int);
- method public final void operationFinished(@Nullable java.util.UUID, int);
- }
-
- public final class SoundTriggerDetector {
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public boolean startRecognition(int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public boolean stopRecognition();
- field public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 2; // 0x2
- field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1
- field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION = 4; // 0x4
- field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION = 8; // 0x8
- }
-
- public abstract static class SoundTriggerDetector.Callback {
- ctor public SoundTriggerDetector.Callback();
- method public abstract void onAvailabilityChanged(int);
- method public abstract void onDetected(@NonNull android.media.soundtrigger.SoundTriggerDetector.EventPayload);
- method public abstract void onError();
- method public abstract void onRecognitionPaused();
- method public abstract void onRecognitionResumed();
- }
-
- public static class SoundTriggerDetector.EventPayload {
- method @Nullable public android.media.AudioFormat getCaptureAudioFormat();
- method @Nullable public byte[] getTriggerAudio();
- }
-
- public final class SoundTriggerManager {
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerDetector createSoundTriggerDetector(java.util.UUID, @NonNull android.media.soundtrigger.SoundTriggerDetector.Callback, @Nullable android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void deleteModel(java.util.UUID);
- method public int getDetectionServiceOperationsTimeout();
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModuleProperties getModuleProperties();
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int getParameter(@NonNull java.util.UUID, int);
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModelParamRange queryParameter(@Nullable java.util.UUID, int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int setParameter(@Nullable java.util.UUID, int, int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
- }
-
- public static class SoundTriggerManager.Model {
- method @NonNull public static android.media.soundtrigger.SoundTriggerManager.Model create(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[], int);
- method @NonNull public static android.media.soundtrigger.SoundTriggerManager.Model create(@NonNull java.util.UUID, @NonNull java.util.UUID, @Nullable byte[]);
- method @Nullable public byte[] getModelData();
- method @NonNull public java.util.UUID getModelUuid();
- method @NonNull public java.util.UUID getVendorUuid();
- method public int getVersion();
- }
-
-}
-
-package android.media.tv {
-
- public final class DvbDeviceInfo implements android.os.Parcelable {
- ctor public DvbDeviceInfo(int, int);
- method public int describeContents();
- method @IntRange(from=0) public int getAdapterId();
- method @IntRange(from=0) public int getDeviceId();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.DvbDeviceInfo> CREATOR;
- }
-
- public final class TunedInfo implements android.os.Parcelable {
- method public int describeContents();
- method public int getAppTag();
- method public int getAppType();
- method @Nullable public android.net.Uri getChannelUri();
- method @NonNull public String getInputId();
- method public boolean isForeground();
- method public boolean isRecordingSession();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int APP_TAG_SELF = 0; // 0x0
- field public static final int APP_TYPE_NON_SYSTEM = 3; // 0x3
- field public static final int APP_TYPE_SELF = 1; // 0x1
- field public static final int APP_TYPE_SYSTEM = 2; // 0x2
- field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TunedInfo> CREATOR;
- }
-
- public final class TvContentRatingSystemInfo implements android.os.Parcelable {
- method public static android.media.tv.TvContentRatingSystemInfo createTvContentRatingSystemInfo(int, android.content.pm.ApplicationInfo);
- method public int describeContents();
- method public android.net.Uri getXmlUri();
- method public boolean isSystemDefined();
- method public void writeToParcel(android.os.Parcel, int);
- }
-
- public final class TvContract {
- method public static android.net.Uri buildChannelsUriForInput(@Nullable String, boolean);
- method public static android.net.Uri buildChannelsUriForInput(@Nullable String, @Nullable String, boolean);
- field public static final String ACTION_CHANNEL_BROWSABLE_REQUESTED = "android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED";
- field public static final String EXTRA_BLOCKED_PACKAGES = "android.media.tv.extra.BLOCKED_PACKAGES";
- field public static final String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
- field public static final String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
- field public static final String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
- field public static final String EXTRA_EXISTING_COLUMN_NAMES = "android.media.tv.extra.EXISTING_COLUMN_NAMES";
- field public static final String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
- field public static final String EXTRA_RESULT_CODE = "android.media.tv.extra.RESULT_CODE";
- field public static final String METHOD_ADD_COLUMN = "add_column";
- field public static final String METHOD_BLOCK_PACKAGE = "block_package";
- field public static final String METHOD_GET_BLOCKED_PACKAGES = "get_blocked_packages";
- field public static final String METHOD_GET_COLUMNS = "get_columns";
- field public static final String METHOD_UNBLOCK_PACKAGE = "unblock_package";
- field public static final int RESULT_ERROR_INVALID_ARGUMENT = 2; // 0x2
- field public static final int RESULT_ERROR_IO = 1; // 0x1
- field public static final int RESULT_OK = 0; // 0x0
- }
-
- public static final class TvContract.WatchedPrograms implements android.media.tv.TvContract.BaseTvColumns {
- field public static final String COLUMN_CHANNEL_ID = "channel_id";
- field public static final String COLUMN_DESCRIPTION = "description";
- field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final String COLUMN_INTERNAL_SESSION_TOKEN = "session_token";
- field public static final String COLUMN_INTERNAL_TUNE_PARAMS = "tune_params";
- field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
- field public static final String COLUMN_TITLE = "title";
- field public static final String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
- field public static final String COLUMN_WATCH_START_TIME_UTC_MILLIS = "watch_start_time_utc_millis";
- field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watched_program";
- field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watched_program";
- field public static final android.net.Uri CONTENT_URI;
- }
-
- public final class TvInputHardwareInfo implements android.os.Parcelable {
- method public int describeContents();
- method public String getAudioAddress();
- method public int getAudioType();
- method public int getCableConnectionStatus();
- method public int getDeviceId();
- method public int getHdmiPortId();
- method public int getType();
- method public void readFromParcel(android.os.Parcel);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CABLE_CONNECTION_STATUS_CONNECTED = 1; // 0x1
- field public static final int CABLE_CONNECTION_STATUS_DISCONNECTED = 2; // 0x2
- field public static final int CABLE_CONNECTION_STATUS_UNKNOWN = 0; // 0x0
- field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TvInputHardwareInfo> CREATOR;
- field public static final int TV_INPUT_TYPE_COMPONENT = 6; // 0x6
- field public static final int TV_INPUT_TYPE_COMPOSITE = 3; // 0x3
- field public static final int TV_INPUT_TYPE_DISPLAY_PORT = 10; // 0xa
- field public static final int TV_INPUT_TYPE_DVI = 8; // 0x8
- field public static final int TV_INPUT_TYPE_HDMI = 9; // 0x9
- field public static final int TV_INPUT_TYPE_OTHER_HARDWARE = 1; // 0x1
- field public static final int TV_INPUT_TYPE_SCART = 5; // 0x5
- field public static final int TV_INPUT_TYPE_SVIDEO = 4; // 0x4
- field public static final int TV_INPUT_TYPE_TUNER = 2; // 0x2
- field public static final int TV_INPUT_TYPE_VGA = 7; // 0x7
- }
-
- public static final class TvInputHardwareInfo.Builder {
- ctor public TvInputHardwareInfo.Builder();
- method public android.media.tv.TvInputHardwareInfo.Builder audioAddress(String);
- method public android.media.tv.TvInputHardwareInfo.Builder audioType(int);
- method public android.media.tv.TvInputHardwareInfo build();
- method public android.media.tv.TvInputHardwareInfo.Builder cableConnectionStatus(int);
- method public android.media.tv.TvInputHardwareInfo.Builder deviceId(int);
- method public android.media.tv.TvInputHardwareInfo.Builder hdmiPortId(int);
- method public android.media.tv.TvInputHardwareInfo.Builder type(int);
- }
-
- public final class TvInputInfo implements android.os.Parcelable {
- method @Deprecated public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, String, String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method @Deprecated public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, String, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method @Deprecated public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method @Deprecated public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public android.hardware.hdmi.HdmiDeviceInfo getHdmiDeviceInfo();
- method public boolean isConnectedToHdmiSwitch();
- method public boolean isHardwareInput();
- method public android.graphics.drawable.Drawable loadIcon(@NonNull android.content.Context, int);
- }
-
- public static final class TvInputInfo.Builder {
- method public android.media.tv.TvInputInfo.Builder setHdmiDeviceInfo(android.hardware.hdmi.HdmiDeviceInfo);
- method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon);
- method public android.media.tv.TvInputInfo.Builder setIcon(android.graphics.drawable.Icon, int);
- method public android.media.tv.TvInputInfo.Builder setLabel(CharSequence);
- method public android.media.tv.TvInputInfo.Builder setLabel(@StringRes int);
- method public android.media.tv.TvInputInfo.Builder setParentId(String);
- method public android.media.tv.TvInputInfo.Builder setTvInputHardwareInfo(android.media.tv.TvInputHardwareInfo);
- }
-
- public static final class TvInputInfo.TvInputSettings {
- method public static java.util.Map<java.lang.String,java.lang.String> getCustomLabels(android.content.Context, int);
- method public static java.util.Set<java.lang.String> getHiddenTvInputIds(android.content.Context, int);
- method public static void putCustomLabels(android.content.Context, java.util.Map<java.lang.String,java.lang.String>, int);
- method public static void putHiddenTvInputs(android.content.Context, java.util.Set<java.lang.String>, int);
- }
-
- 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, @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);
- method @NonNull @RequiresPermission("com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS") public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
- method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
- method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
- method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList();
- method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean isSingleSessionActive();
- method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyPreviewProgramAddedToWatchNext(String, long, long);
- method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyPreviewProgramBrowsableDisabled(String, long);
- method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyWatchNextProgramBrowsableDisabled(String, long);
- method @Nullable @RequiresPermission("android.permission.DVB_DEVICE") public android.os.ParcelFileDescriptor openDvbDevice(@NonNull android.media.tv.DvbDeviceInfo, int);
- method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public void releaseTvInputHardware(int, android.media.tv.TvInputManager.Hardware);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void removeBlockedRating(@NonNull android.media.tv.TvContentRating);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void setParentalControlsEnabled(boolean);
- }
-
- public static final class TvInputManager.Hardware {
- method public void overrideAudioSink(int, String, int, int, int);
- method public void setStreamVolume(float);
- method public boolean setSurface(android.view.Surface, android.media.tv.TvStreamConfig);
- }
-
- public abstract static class TvInputManager.HardwareCallback {
- ctor public TvInputManager.HardwareCallback();
- method public abstract void onReleased();
- method public abstract void onStreamConfigChanged(android.media.tv.TvStreamConfig[]);
- }
-
- public abstract static class TvInputManager.TvInputCallback {
- method public void onCurrentTunedInfosUpdated(@NonNull java.util.List<android.media.tv.TunedInfo>);
- }
-
- public abstract class TvInputService extends android.app.Service {
- method @Nullable public android.os.IBinder createExtension();
- method @Nullable public android.media.tv.TvInputInfo onHardwareAdded(android.media.tv.TvInputHardwareInfo);
- method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
- method @Nullable public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
- method @Nullable public String onHdmiDeviceRemoved(android.hardware.hdmi.HdmiDeviceInfo);
- method public void onHdmiDeviceUpdated(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
- }
-
- public abstract static class TvInputService.RecordingSession {
- method public void notifySessionEvent(@NonNull String, android.os.Bundle);
- }
-
- public abstract static class TvInputService.Session implements android.view.KeyEvent.Callback {
- method public void notifySessionEvent(@NonNull String, android.os.Bundle);
- method public void onSetMain(boolean);
- }
-
- public abstract static class TvRecordingClient.RecordingCallback {
- method public void onEvent(String, String, android.os.Bundle);
- }
-
- public class TvStreamConfig implements android.os.Parcelable {
- method public int describeContents();
- method public int getGeneration();
- method public int getMaxHeight();
- method public int getMaxWidth();
- method public int getStreamId();
- method public int getType();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TvStreamConfig> CREATOR;
- field public static final int STREAM_TYPE_BUFFER_PRODUCER = 2; // 0x2
- field public static final int STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE = 1; // 0x1
- }
-
- public static final class TvStreamConfig.Builder {
- ctor public TvStreamConfig.Builder();
- method public android.media.tv.TvStreamConfig build();
- method public android.media.tv.TvStreamConfig.Builder generation(int);
- method public android.media.tv.TvStreamConfig.Builder maxHeight(int);
- method public android.media.tv.TvStreamConfig.Builder maxWidth(int);
- method public android.media.tv.TvStreamConfig.Builder streamId(int);
- method public android.media.tv.TvStreamConfig.Builder type(int);
- }
-
- public class TvView extends android.view.ViewGroup {
- method @RequiresPermission("android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE") public void setMain();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void unblockContent(android.media.tv.TvContentRating);
- }
-
- public abstract static class TvView.TvInputCallback {
- method public void onEvent(String, String, android.os.Bundle);
- }
-
-}
-
-package android.media.tv.tuner {
-
- public class DemuxCapabilities {
- method public int getAudioFilterCount();
- method public int getDemuxCount();
- method public int getFilterCapabilities();
- method @NonNull @Size(5) public int[] getLinkCapabilities();
- method public int getPcrFilterCount();
- method public int getPesFilterCount();
- method public int getPlaybackCount();
- method public int getRecordCount();
- method public int getSectionFilterCount();
- method public long getSectionFilterLength();
- method public int getTsFilterCount();
- method public int getVideoFilterCount();
- method public boolean isTimeFilterSupported();
- }
-
- public class Descrambler implements java.lang.AutoCloseable {
- method public int addPid(int, int, @Nullable android.media.tv.tuner.filter.Filter);
- method public void close();
- method public int removePid(int, int, @Nullable android.media.tv.tuner.filter.Filter);
- method public int setKeyToken(@NonNull byte[]);
- field public static final int PID_TYPE_MMTP = 2; // 0x2
- field public static final int PID_TYPE_T = 1; // 0x1
- }
-
- public class Lnb implements java.lang.AutoCloseable {
- method public void close();
- method public int sendDiseqcMessage(@NonNull byte[]);
- method public int setSatellitePosition(int);
- method public int setTone(int);
- method public int setVoltage(int);
- field public static final int EVENT_TYPE_DISEQC_RX_OVERFLOW = 0; // 0x0
- field public static final int EVENT_TYPE_DISEQC_RX_PARITY_ERROR = 2; // 0x2
- field public static final int EVENT_TYPE_DISEQC_RX_TIMEOUT = 1; // 0x1
- field public static final int EVENT_TYPE_LNB_OVERLOAD = 3; // 0x3
- field public static final int POSITION_A = 1; // 0x1
- field public static final int POSITION_B = 2; // 0x2
- field public static final int POSITION_UNDEFINED = 0; // 0x0
- field public static final int TONE_CONTINUOUS = 1; // 0x1
- field public static final int TONE_NONE = 0; // 0x0
- field public static final int VOLTAGE_11V = 2; // 0x2
- field public static final int VOLTAGE_12V = 3; // 0x3
- field public static final int VOLTAGE_13V = 4; // 0x4
- field public static final int VOLTAGE_14V = 5; // 0x5
- field public static final int VOLTAGE_15V = 6; // 0x6
- field public static final int VOLTAGE_18V = 7; // 0x7
- field public static final int VOLTAGE_19V = 8; // 0x8
- field public static final int VOLTAGE_5V = 1; // 0x1
- field public static final int VOLTAGE_NONE = 0; // 0x0
- }
-
- public interface LnbCallback {
- method public void onDiseqcMessage(@NonNull byte[]);
- method public void onEvent(int);
- }
-
- public class Tuner implements java.lang.AutoCloseable {
- ctor @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public Tuner(@NonNull android.content.Context, @Nullable String, int);
- method public int cancelScanning();
- method public int cancelTuning();
- method public void clearOnTuneEventListener();
- method public void clearResourceLostListener();
- method public void close();
- method public int connectCiCam(int);
- method public int disconnectCiCam();
- method public int getAvSyncHwId(@NonNull android.media.tv.tuner.filter.Filter);
- method public long getAvSyncTime(int);
- method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
- method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
- method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
- method public int linkFrontendToCiCam(int);
- method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler();
- method @Nullable public android.media.tv.tuner.dvr.DvrPlayback openDvrPlayback(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener);
- method @Nullable public android.media.tv.tuner.dvr.DvrRecorder openDvrRecorder(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnRecordStatusChangedListener);
- method @Nullable public android.media.tv.tuner.filter.Filter openFilter(int, int, long, @Nullable java.util.concurrent.Executor, @Nullable android.media.tv.tuner.filter.FilterCallback);
- method @Nullable public android.media.tv.tuner.Lnb openLnb(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
- method @Nullable public android.media.tv.tuner.Lnb openLnbByName(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
- method @Nullable public android.media.tv.tuner.filter.TimeFilter openTimeFilter();
- method public int scan(@NonNull android.media.tv.tuner.frontend.FrontendSettings, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.ScanCallback);
- method public int setLnaEnabled(boolean);
- method public void setOnTuneEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.OnTuneEventListener);
- method public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener);
- method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner);
- method public int tune(@NonNull android.media.tv.tuner.frontend.FrontendSettings);
- method public int unlinkFrontendToCiCam(int);
- method public void updateResourcePriority(int, int);
- field public static final int INVALID_AV_SYNC_ID = -1; // 0xffffffff
- field public static final int INVALID_FILTER_ID = -1; // 0xffffffff
- field public static final long INVALID_FILTER_ID_64BIT = -1L; // 0xffffffffffffffffL
- field public static final int INVALID_FRONTEND_SETTING_FREQUENCY = -1; // 0xffffffff
- field public static final int INVALID_LTS_ID = -1; // 0xffffffff
- field public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1; // 0xffffffff
- field public static final int INVALID_STREAM_ID = 65535; // 0xffff
- field public static final long INVALID_TIMESTAMP = -1L; // 0xffffffffffffffffL
- field public static final int INVALID_TS_PID = 65535; // 0xffff
- field public static final int RESULT_INVALID_ARGUMENT = 4; // 0x4
- field public static final int RESULT_INVALID_STATE = 3; // 0x3
- field public static final int RESULT_NOT_INITIALIZED = 2; // 0x2
- field public static final int RESULT_OUT_OF_MEMORY = 5; // 0x5
- field public static final int RESULT_SUCCESS = 0; // 0x0
- field public static final int RESULT_UNAVAILABLE = 1; // 0x1
- field public static final int RESULT_UNKNOWN_ERROR = 6; // 0x6
- field public static final int SCAN_TYPE_AUTO = 1; // 0x1
- field public static final int SCAN_TYPE_BLIND = 2; // 0x2
- field public static final int SCAN_TYPE_UNDEFINED = 0; // 0x0
- }
-
- public static interface Tuner.OnResourceLostListener {
- method public void onResourceLost(@NonNull android.media.tv.tuner.Tuner);
- }
-
- public final class TunerVersionChecker {
- method public static int getTunerVersion();
- field public static final int TUNER_VERSION_1_0 = 65536; // 0x10000
- field public static final int TUNER_VERSION_1_1 = 65537; // 0x10001
- field public static final int TUNER_VERSION_UNKNOWN = 0; // 0x0
- }
-
-}
-
-package android.media.tv.tuner.dvr {
-
- public class DvrPlayback implements java.lang.AutoCloseable {
- method @Deprecated public int attachFilter(@NonNull android.media.tv.tuner.filter.Filter);
- method public void close();
- method public int configure(@NonNull android.media.tv.tuner.dvr.DvrSettings);
- method @Deprecated public int detachFilter(@NonNull android.media.tv.tuner.filter.Filter);
- method public int flush();
- method public long read(long);
- method public long read(@NonNull byte[], long, long);
- method public void setFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
- method public int start();
- method public int stop();
- field public static final int PLAYBACK_STATUS_ALMOST_EMPTY = 2; // 0x2
- field public static final int PLAYBACK_STATUS_ALMOST_FULL = 4; // 0x4
- field public static final int PLAYBACK_STATUS_EMPTY = 1; // 0x1
- field public static final int PLAYBACK_STATUS_FULL = 8; // 0x8
- }
-
- public class DvrRecorder implements java.lang.AutoCloseable {
- method public int attachFilter(@NonNull android.media.tv.tuner.filter.Filter);
- method public void close();
- method public int configure(@NonNull android.media.tv.tuner.dvr.DvrSettings);
- method public int detachFilter(@NonNull android.media.tv.tuner.filter.Filter);
- method public int flush();
- method public void setFileDescriptor(@NonNull android.os.ParcelFileDescriptor);
- method public int start();
- method public int stop();
- method public long write(long);
- method public long write(@NonNull byte[], long, long);
- }
-
- public class DvrSettings {
- method @NonNull public static android.media.tv.tuner.dvr.DvrSettings.Builder builder();
- method public int getDataFormat();
- method public long getHighThreshold();
- method public long getLowThreshold();
- method public long getPacketSize();
- method public int getStatusMask();
- field public static final int DATA_FORMAT_ES = 2; // 0x2
- field public static final int DATA_FORMAT_PES = 1; // 0x1
- field public static final int DATA_FORMAT_SHV_TLV = 3; // 0x3
- field public static final int DATA_FORMAT_TS = 0; // 0x0
- }
-
- public static final class DvrSettings.Builder {
- ctor public DvrSettings.Builder();
- method @NonNull public android.media.tv.tuner.dvr.DvrSettings build();
- method @NonNull public android.media.tv.tuner.dvr.DvrSettings.Builder setDataFormat(int);
- method @NonNull public android.media.tv.tuner.dvr.DvrSettings.Builder setHighThreshold(long);
- method @NonNull public android.media.tv.tuner.dvr.DvrSettings.Builder setLowThreshold(long);
- method @NonNull public android.media.tv.tuner.dvr.DvrSettings.Builder setPacketSize(long);
- method @NonNull public android.media.tv.tuner.dvr.DvrSettings.Builder setStatusMask(int);
- }
-
- public interface OnPlaybackStatusChangedListener {
- method public void onPlaybackStatusChanged(int);
- }
-
- public interface OnRecordStatusChangedListener {
- method public void onRecordStatusChanged(int);
- }
-
-}
-
-package android.media.tv.tuner.filter {
-
- public final class AlpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
- method @NonNull public static android.media.tv.tuner.filter.AlpFilterConfiguration.Builder builder();
- method public int getLengthType();
- method public int getPacketType();
- method public int getType();
- 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 final class AlpFilterConfiguration.Builder {
- method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration build();
- method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setLengthType(int);
- method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setPacketType(int);
- method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
- }
-
- public class AudioDescriptor {
- method public byte getAdFade();
- method public byte getAdGainCenter();
- method public byte getAdGainFront();
- method public byte getAdGainSurround();
- method public byte getAdPan();
- method public char getAdVersionTextTag();
- }
-
- public class AvSettings extends android.media.tv.tuner.filter.Settings {
- method @NonNull public static android.media.tv.tuner.filter.AvSettings.Builder builder(int, boolean);
- method public int getAudioStreamType();
- method public int getVideoStreamType();
- method public boolean isPassthrough();
- field public static final int AUDIO_STREAM_TYPE_AAC = 6; // 0x6
- field public static final int AUDIO_STREAM_TYPE_AC3 = 7; // 0x7
- field public static final int AUDIO_STREAM_TYPE_AC4 = 9; // 0x9
- field public static final int AUDIO_STREAM_TYPE_DRA = 15; // 0xf
- field public static final int AUDIO_STREAM_TYPE_DTS = 10; // 0xa
- field public static final int AUDIO_STREAM_TYPE_DTS_HD = 11; // 0xb
- field public static final int AUDIO_STREAM_TYPE_EAC3 = 8; // 0x8
- field public static final int AUDIO_STREAM_TYPE_MP3 = 2; // 0x2
- field public static final int AUDIO_STREAM_TYPE_MPEG1 = 3; // 0x3
- field public static final int AUDIO_STREAM_TYPE_MPEG2 = 4; // 0x4
- field public static final int AUDIO_STREAM_TYPE_MPEGH = 5; // 0x5
- field public static final int AUDIO_STREAM_TYPE_OPUS = 13; // 0xd
- field public static final int AUDIO_STREAM_TYPE_PCM = 1; // 0x1
- field public static final int AUDIO_STREAM_TYPE_UNDEFINED = 0; // 0x0
- field public static final int AUDIO_STREAM_TYPE_VORBIS = 14; // 0xe
- field public static final int AUDIO_STREAM_TYPE_WMA = 12; // 0xc
- field public static final int VIDEO_STREAM_TYPE_AV1 = 10; // 0xa
- field public static final int VIDEO_STREAM_TYPE_AVC = 5; // 0x5
- field public static final int VIDEO_STREAM_TYPE_AVS = 11; // 0xb
- field public static final int VIDEO_STREAM_TYPE_AVS2 = 12; // 0xc
- field public static final int VIDEO_STREAM_TYPE_HEVC = 6; // 0x6
- field public static final int VIDEO_STREAM_TYPE_MPEG1 = 2; // 0x2
- field public static final int VIDEO_STREAM_TYPE_MPEG2 = 3; // 0x3
- field public static final int VIDEO_STREAM_TYPE_MPEG4P2 = 4; // 0x4
- field public static final int VIDEO_STREAM_TYPE_RESERVED = 1; // 0x1
- field public static final int VIDEO_STREAM_TYPE_UNDEFINED = 0; // 0x0
- field public static final int VIDEO_STREAM_TYPE_VC1 = 7; // 0x7
- field public static final int VIDEO_STREAM_TYPE_VP8 = 8; // 0x8
- field public static final int VIDEO_STREAM_TYPE_VP9 = 9; // 0x9
- }
-
- public static class AvSettings.Builder {
- method @NonNull public android.media.tv.tuner.filter.AvSettings build();
- method @NonNull public android.media.tv.tuner.filter.AvSettings.Builder setAudioStreamType(int);
- method @NonNull public android.media.tv.tuner.filter.AvSettings.Builder setPassthrough(boolean);
- method @NonNull public android.media.tv.tuner.filter.AvSettings.Builder setVideoStreamType(int);
- }
-
- public class DownloadEvent extends android.media.tv.tuner.filter.FilterEvent {
- method public int getDataLength();
- method public int getItemFragmentIndex();
- method public int getItemId();
- method public int getLastItemFragmentIndex();
- method public int getMpuSequenceNumber();
- }
-
- public class DownloadSettings extends android.media.tv.tuner.filter.Settings {
- method @NonNull public static android.media.tv.tuner.filter.DownloadSettings.Builder builder(int);
- method public int getDownloadId();
- }
-
- public static class DownloadSettings.Builder {
- method @NonNull public android.media.tv.tuner.filter.DownloadSettings build();
- method @NonNull public android.media.tv.tuner.filter.DownloadSettings.Builder setDownloadId(int);
- }
-
- public class Filter implements java.lang.AutoCloseable {
- method public void close();
- method public int configure(@NonNull android.media.tv.tuner.filter.FilterConfiguration);
- method public int flush();
- method public int getId();
- method public long getId64Bit();
- method public int read(@NonNull byte[], long, long);
- method public int setDataSource(@Nullable android.media.tv.tuner.filter.Filter);
- method public int start();
- method public int stop();
- field public static final int STATUS_DATA_READY = 1; // 0x1
- field public static final int STATUS_HIGH_WATER = 4; // 0x4
- field public static final int STATUS_LOW_WATER = 2; // 0x2
- field public static final int STATUS_OVERFLOW = 8; // 0x8
- field public static final int SUBTYPE_AUDIO = 3; // 0x3
- field public static final int SUBTYPE_DOWNLOAD = 5; // 0x5
- field public static final int SUBTYPE_IP = 13; // 0xd
- field public static final int SUBTYPE_IP_PAYLOAD = 12; // 0xc
- field public static final int SUBTYPE_MMTP = 10; // 0xa
- field public static final int SUBTYPE_NTP = 11; // 0xb
- field public static final int SUBTYPE_PAYLOAD_THROUGH = 14; // 0xe
- field public static final int SUBTYPE_PCR = 8; // 0x8
- field public static final int SUBTYPE_PES = 2; // 0x2
- field public static final int SUBTYPE_PTP = 16; // 0x10
- field public static final int SUBTYPE_RECORD = 6; // 0x6
- field public static final int SUBTYPE_SECTION = 1; // 0x1
- field public static final int SUBTYPE_TEMI = 9; // 0x9
- field public static final int SUBTYPE_TLV = 15; // 0xf
- field public static final int SUBTYPE_TS = 7; // 0x7
- field public static final int SUBTYPE_UNDEFINED = 0; // 0x0
- field public static final int SUBTYPE_VIDEO = 4; // 0x4
- field public static final int TYPE_ALP = 16; // 0x10
- field public static final int TYPE_IP = 4; // 0x4
- 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 {
- method public void onFilterEvent(@NonNull android.media.tv.tuner.filter.Filter, @NonNull android.media.tv.tuner.filter.FilterEvent[]);
- method public void onFilterStatusChanged(@NonNull android.media.tv.tuner.filter.Filter, int);
- }
-
- public abstract class FilterConfiguration {
- method @Nullable public android.media.tv.tuner.filter.Settings getSettings();
- method public abstract int getType();
- }
-
- public abstract class FilterEvent {
- ctor public FilterEvent();
- }
-
- public final class IpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
- method @NonNull public static android.media.tv.tuner.filter.IpFilterConfiguration.Builder builder();
- method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress();
- method public int getDstPort();
- method @IntRange(from=0, to=61439) public int getIpFilterContextId();
- method @NonNull @Size(min=4, max=16) public byte[] getSrcIpAddress();
- method public int getSrcPort();
- method public int getType();
- method public boolean isPassthrough();
- field public static final int INVALID_IP_FILTER_CONTEXT_ID = -1; // 0xffffffff
- }
-
- public static final class IpFilterConfiguration.Builder {
- method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration build();
- method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstIpAddress(@NonNull byte[]);
- method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstPort(int);
- method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setIpFilterContextId(int);
- method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setPassthrough(boolean);
- method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
- method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcIpAddress(@NonNull byte[]);
- method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcPort(int);
- }
-
- public class IpPayloadEvent extends android.media.tv.tuner.filter.FilterEvent {
- method public int getDataLength();
- }
-
- public class MediaEvent extends android.media.tv.tuner.filter.FilterEvent {
- method public long getAudioHandle();
- method public long getAvDataId();
- method public long getDataLength();
- method @Nullable public android.media.tv.tuner.filter.AudioDescriptor getExtraMetaData();
- method @Nullable public android.media.MediaCodec.LinearBlock getLinearBlock();
- method public int getMpuSequenceNumber();
- method public long getOffset();
- method public long getPts();
- method public int getStreamId();
- method public boolean isPrivateData();
- method public boolean isPtsPresent();
- method public boolean isSecureMemory();
- method public void release();
- }
-
- public final class MmtpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
- method @NonNull public static android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder builder();
- method public int getMmtpPacketId();
- method public int getType();
- }
-
- public static final class MmtpFilterConfiguration.Builder {
- method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration build();
- method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder setMmtpPacketId(int);
- method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
- }
-
- public class MmtpRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
- method public long getDataLength();
- method public int getMpuSequenceNumber();
- method public long getPts();
- method public int getScHevcIndexMask();
- }
-
- public class PesEvent extends android.media.tv.tuner.filter.FilterEvent {
- method public int getDataLength();
- method public int getMpuSequenceNumber();
- method public int getStreamId();
- }
-
- public class PesSettings extends android.media.tv.tuner.filter.Settings {
- method @NonNull public static android.media.tv.tuner.filter.PesSettings.Builder builder(int);
- method public int getStreamId();
- method public boolean isRaw();
- }
-
- public static class PesSettings.Builder {
- method @NonNull public android.media.tv.tuner.filter.PesSettings build();
- method @NonNull public android.media.tv.tuner.filter.PesSettings.Builder setRaw(boolean);
- method @NonNull public android.media.tv.tuner.filter.PesSettings.Builder setStreamId(int);
- }
-
- public class RecordSettings extends android.media.tv.tuner.filter.Settings {
- method @NonNull public static android.media.tv.tuner.filter.RecordSettings.Builder builder(int);
- method public int getScIndexMask();
- method public int getScIndexType();
- method public int getTsIndexMask();
- field public static final int INDEX_TYPE_NONE = 0; // 0x0
- field public static final int INDEX_TYPE_SC = 1; // 0x1
- field public static final int INDEX_TYPE_SC_HEVC = 2; // 0x2
- field public static final int SC_HEVC_INDEX_AUD = 2; // 0x2
- field public static final int SC_HEVC_INDEX_SLICE_BLA_N_LP = 16; // 0x10
- field public static final int SC_HEVC_INDEX_SLICE_BLA_W_RADL = 8; // 0x8
- field public static final int SC_HEVC_INDEX_SLICE_CE_BLA_W_LP = 4; // 0x4
- field public static final int SC_HEVC_INDEX_SLICE_IDR_N_LP = 64; // 0x40
- field public static final int SC_HEVC_INDEX_SLICE_IDR_W_RADL = 32; // 0x20
- field public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA = 128; // 0x80
- field public static final int SC_HEVC_INDEX_SPS = 1; // 0x1
- field public static final int SC_INDEX_B_FRAME = 4; // 0x4
- field public static final int SC_INDEX_I_FRAME = 1; // 0x1
- field public static final int SC_INDEX_P_FRAME = 2; // 0x2
- field public static final int SC_INDEX_SEQUENCE = 8; // 0x8
- field public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG = 4096; // 0x1000
- field public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED = 8; // 0x8
- field public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED = 4; // 0x4
- field public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED = 16; // 0x10
- field public static final int TS_INDEX_DISCONTINUITY_INDICATOR = 32; // 0x20
- field public static final int TS_INDEX_FIRST_PACKET = 1; // 0x1
- field public static final int TS_INDEX_OPCR_FLAG = 512; // 0x200
- field public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR = 2; // 0x2
- field public static final int TS_INDEX_PCR_FLAG = 256; // 0x100
- field public static final int TS_INDEX_PRIORITY_INDICATOR = 128; // 0x80
- field public static final int TS_INDEX_PRIVATE_DATA = 2048; // 0x800
- field public static final int TS_INDEX_RANDOM_ACCESS_INDICATOR = 64; // 0x40
- field public static final int TS_INDEX_SPLICING_POINT_FLAG = 1024; // 0x400
- }
-
- public static class RecordSettings.Builder {
- method @NonNull public android.media.tv.tuner.filter.RecordSettings build();
- method @NonNull public android.media.tv.tuner.filter.RecordSettings.Builder setScIndexMask(int);
- method @NonNull public android.media.tv.tuner.filter.RecordSettings.Builder setScIndexType(int);
- method @NonNull public android.media.tv.tuner.filter.RecordSettings.Builder setTsIndexMask(int);
- }
-
- public class SectionEvent extends android.media.tv.tuner.filter.FilterEvent {
- method public int getDataLength();
- method public int getSectionNumber();
- method public int getTableId();
- method public int getVersion();
- }
-
- public abstract class SectionSettings extends android.media.tv.tuner.filter.Settings {
- method public boolean isCrcEnabled();
- method public boolean isRaw();
- method public boolean isRepeat();
- }
-
- public abstract static class SectionSettings.Builder<T extends android.media.tv.tuner.filter.SectionSettings.Builder<T>> {
- method @NonNull public T setCrcEnabled(boolean);
- method @NonNull public T setRaw(boolean);
- method @NonNull public T setRepeat(boolean);
- }
-
- public class SectionSettingsWithSectionBits extends android.media.tv.tuner.filter.SectionSettings {
- method @NonNull public static android.media.tv.tuner.filter.SectionSettingsWithSectionBits.Builder builder(int);
- method @NonNull public byte[] getFilterBytes();
- method @NonNull public byte[] getMask();
- method @NonNull public byte[] getMode();
- }
-
- public static class SectionSettingsWithSectionBits.Builder extends android.media.tv.tuner.filter.SectionSettings.Builder<android.media.tv.tuner.filter.SectionSettingsWithSectionBits.Builder> {
- method @NonNull public android.media.tv.tuner.filter.SectionSettingsWithSectionBits build();
- method @NonNull public android.media.tv.tuner.filter.SectionSettingsWithSectionBits.Builder setFilter(@NonNull byte[]);
- method @NonNull public android.media.tv.tuner.filter.SectionSettingsWithSectionBits.Builder setMask(@NonNull byte[]);
- method @NonNull public android.media.tv.tuner.filter.SectionSettingsWithSectionBits.Builder setMode(@NonNull byte[]);
- }
-
- public class SectionSettingsWithTableInfo extends android.media.tv.tuner.filter.SectionSettings {
- method @NonNull public static android.media.tv.tuner.filter.SectionSettingsWithTableInfo.Builder builder(int);
- method public int getTableId();
- method public int getVersion();
- }
-
- public static class SectionSettingsWithTableInfo.Builder extends android.media.tv.tuner.filter.SectionSettings.Builder<android.media.tv.tuner.filter.SectionSettingsWithTableInfo.Builder> {
- method @NonNull public android.media.tv.tuner.filter.SectionSettingsWithTableInfo build();
- method @NonNull public android.media.tv.tuner.filter.SectionSettingsWithTableInfo.Builder setTableId(int);
- method @NonNull public android.media.tv.tuner.filter.SectionSettingsWithTableInfo.Builder setVersion(int);
- }
-
- public abstract class Settings {
- method public int getType();
- }
-
- public class TemiEvent extends android.media.tv.tuner.filter.FilterEvent {
- method @NonNull public byte[] getDescriptorData();
- method public byte getDescriptorTag();
- method public long getPts();
- }
-
- public class TimeFilter implements java.lang.AutoCloseable {
- method public int clearTimestamp();
- method public void close();
- method public long getSourceTime();
- method public long getTimeStamp();
- method public int setCurrentTimestamp(long);
- }
-
- public final class TlvFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
- method @NonNull public static android.media.tv.tuner.filter.TlvFilterConfiguration.Builder builder();
- method public int getPacketType();
- 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 final class TlvFilterConfiguration.Builder {
- method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration build();
- method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setCompressedIpPacket(boolean);
- method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setPacketType(int);
- method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setPassthrough(boolean);
- method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
- }
-
- public final class TsFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
- method @NonNull public static android.media.tv.tuner.filter.TsFilterConfiguration.Builder builder();
- method public int getTpid();
- method public int getType();
- }
-
- public static final class TsFilterConfiguration.Builder {
- method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration build();
- method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
- method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setTpid(int);
- }
-
- public class TsRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
- method public long getDataLength();
- method public int getPacketId();
- method public long getPts();
- method public int getScIndexMask();
- method public int getTsIndexMask();
- }
-
-}
-
-package android.media.tv.tuner.frontend {
-
- public class AnalogFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
- method public int getSifStandardCapability();
- method public int getSignalTypeCapability();
- }
-
- public class AnalogFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
- method @NonNull public static android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder builder();
- method public int getAftFlag();
- method public int getSifStandard();
- method public int getSignalType();
- method public int getType();
- field public static final int AFT_FLAG_FALSE = 2; // 0x2
- field public static final int AFT_FLAG_TRUE = 1; // 0x1
- field public static final int AFT_FLAG_UNDEFINED = 0; // 0x0
- field public static final int SIF_AUTO = 1; // 0x1
- field public static final int SIF_BG = 2; // 0x2
- field public static final int SIF_BG_A2 = 4; // 0x4
- field public static final int SIF_BG_NICAM = 8; // 0x8
- field public static final int SIF_DK = 32; // 0x20
- field public static final int SIF_DK1_A2 = 64; // 0x40
- field public static final int SIF_DK2_A2 = 128; // 0x80
- field public static final int SIF_DK3_A2 = 256; // 0x100
- field public static final int SIF_DK_NICAM = 512; // 0x200
- field public static final int SIF_I = 16; // 0x10
- field public static final int SIF_I_NICAM = 32768; // 0x8000
- field public static final int SIF_L = 1024; // 0x400
- field public static final int SIF_L_NICAM = 65536; // 0x10000
- field public static final int SIF_L_PRIME = 131072; // 0x20000
- field public static final int SIF_M = 2048; // 0x800
- field public static final int SIF_M_A2 = 8192; // 0x2000
- field public static final int SIF_M_BTSC = 4096; // 0x1000
- field public static final int SIF_M_EIAJ = 16384; // 0x4000
- field public static final int SIF_UNDEFINED = 0; // 0x0
- field public static final int SIGNAL_TYPE_AUTO = 1; // 0x1
- field public static final int SIGNAL_TYPE_NTSC = 32; // 0x20
- field public static final int SIGNAL_TYPE_NTSC_443 = 64; // 0x40
- field public static final int SIGNAL_TYPE_PAL = 2; // 0x2
- field public static final int SIGNAL_TYPE_PAL_60 = 16; // 0x10
- field public static final int SIGNAL_TYPE_PAL_M = 4; // 0x4
- field public static final int SIGNAL_TYPE_PAL_N = 8; // 0x8
- field public static final int SIGNAL_TYPE_SECAM = 128; // 0x80
- field public static final int SIGNAL_TYPE_UNDEFINED = 0; // 0x0
- }
-
- public static class AnalogFrontendSettings.Builder {
- method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings build();
- method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setAftFlag(int);
- method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setFrequency(int);
- method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSifStandard(int);
- method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSignalType(int);
- }
-
- public class Atsc3FrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
- method public int getBandwidthCapability();
- method public int getDemodOutputFormatCapability();
- method public int getFecCapability();
- method public int getModulationCapability();
- method public int getPlpCodeRateCapability();
- method public int getTimeInterleaveModeCapability();
- }
-
- public class Atsc3FrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
- method @NonNull public static android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder builder();
- method public int getBandwidth();
- method public int getDemodOutputFormat();
- method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings[] getPlpSettings();
- method public int getType();
- field public static final int BANDWIDTH_AUTO = 1; // 0x1
- field public static final int BANDWIDTH_BANDWIDTH_6MHZ = 2; // 0x2
- field public static final int BANDWIDTH_BANDWIDTH_7MHZ = 4; // 0x4
- field public static final int BANDWIDTH_BANDWIDTH_8MHZ = 8; // 0x8
- field public static final int BANDWIDTH_UNDEFINED = 0; // 0x0
- field public static final int CODERATE_10_15 = 512; // 0x200
- field public static final int CODERATE_11_15 = 1024; // 0x400
- field public static final int CODERATE_12_15 = 2048; // 0x800
- field public static final int CODERATE_13_15 = 4096; // 0x1000
- field public static final int CODERATE_2_15 = 2; // 0x2
- field public static final int CODERATE_3_15 = 4; // 0x4
- field public static final int CODERATE_4_15 = 8; // 0x8
- field public static final int CODERATE_5_15 = 16; // 0x10
- field public static final int CODERATE_6_15 = 32; // 0x20
- field public static final int CODERATE_7_15 = 64; // 0x40
- field public static final int CODERATE_8_15 = 128; // 0x80
- field public static final int CODERATE_9_15 = 256; // 0x100
- field public static final int CODERATE_AUTO = 1; // 0x1
- field public static final int CODERATE_UNDEFINED = 0; // 0x0
- field public static final int DEMOD_OUTPUT_FORMAT_ATSC3_LINKLAYER_PACKET = 1; // 0x1
- field public static final int DEMOD_OUTPUT_FORMAT_BASEBAND_PACKET = 2; // 0x2
- field public static final int DEMOD_OUTPUT_FORMAT_UNDEFINED = 0; // 0x0
- field public static final int FEC_AUTO = 1; // 0x1
- field public static final int FEC_BCH_LDPC_16K = 2; // 0x2
- field public static final int FEC_BCH_LDPC_64K = 4; // 0x4
- field public static final int FEC_CRC_LDPC_16K = 8; // 0x8
- field public static final int FEC_CRC_LDPC_64K = 16; // 0x10
- field public static final int FEC_LDPC_16K = 32; // 0x20
- field public static final int FEC_LDPC_64K = 64; // 0x40
- field public static final int FEC_UNDEFINED = 0; // 0x0
- field public static final int MODULATION_AUTO = 1; // 0x1
- field public static final int MODULATION_MOD_1024QAM = 32; // 0x20
- field public static final int MODULATION_MOD_16QAM = 4; // 0x4
- field public static final int MODULATION_MOD_256QAM = 16; // 0x10
- field public static final int MODULATION_MOD_4096QAM = 64; // 0x40
- field public static final int MODULATION_MOD_64QAM = 8; // 0x8
- field public static final int MODULATION_MOD_QPSK = 2; // 0x2
- field public static final int MODULATION_UNDEFINED = 0; // 0x0
- field public static final int TIME_INTERLEAVE_MODE_AUTO = 1; // 0x1
- field public static final int TIME_INTERLEAVE_MODE_CTI = 2; // 0x2
- field public static final int TIME_INTERLEAVE_MODE_HTI = 4; // 0x4
- field public static final int TIME_INTERLEAVE_MODE_UNDEFINED = 0; // 0x0
- }
-
- public static class Atsc3FrontendSettings.Builder {
- method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings build();
- method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setBandwidth(int);
- method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setDemodOutputFormat(int);
- method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setFrequency(int);
- method @NonNull public android.media.tv.tuner.frontend.Atsc3FrontendSettings.Builder setPlpSettings(@NonNull android.media.tv.tuner.frontend.Atsc3PlpSettings[]);
- }
-
- public class Atsc3PlpInfo {
- method public boolean getLlsFlag();
- method public int getPlpId();
- }
-
- public class Atsc3PlpSettings {
- method @NonNull public static android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder builder();
- method public int getCodeRate();
- method public int getFec();
- method public int getInterleaveMode();
- method public int getModulation();
- method public int getPlpId();
- }
-
- public static class Atsc3PlpSettings.Builder {
- method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings build();
- method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder setCodeRate(int);
- method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder setFec(int);
- method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder setInterleaveMode(int);
- method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder setModulation(int);
- method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpSettings.Builder setPlpId(int);
- }
-
- public class AtscFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
- method public int getModulationCapability();
- }
-
- public class AtscFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
- method @NonNull public static android.media.tv.tuner.frontend.AtscFrontendSettings.Builder builder();
- method public int getModulation();
- method public int getType();
- field public static final int MODULATION_AUTO = 1; // 0x1
- field public static final int MODULATION_MOD_16VSB = 8; // 0x8
- field public static final int MODULATION_MOD_8VSB = 4; // 0x4
- field public static final int MODULATION_UNDEFINED = 0; // 0x0
- }
-
- public static class AtscFrontendSettings.Builder {
- method @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings build();
- method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings.Builder setFrequency(int);
- method @NonNull public android.media.tv.tuner.frontend.AtscFrontendSettings.Builder setModulation(int);
- }
-
- public final class DtmbFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
- method public int getBandwidthCapability();
- method public int getCodeRateCapability();
- method public int getGuardIntervalCapability();
- method public int getModulationCapability();
- method public int getTimeInterleaveModeCapability();
- method public int getTransmissionModeCapability();
- }
-
- public final class DtmbFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
- method @NonNull public static android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder builder();
- method public int getBandwidth();
- method public int getCodeRate();
- method public int getGuardInterval();
- method public int getModulation();
- method public int getTimeInterleaveMode();
- method public int getTransmissionMode();
- method public int getType();
- field public static final int BANDWIDTH_6MHZ = 4; // 0x4
- field public static final int BANDWIDTH_8MHZ = 2; // 0x2
- field public static final int BANDWIDTH_AUTO = 1; // 0x1
- field public static final int BANDWIDTH_UNDEFINED = 0; // 0x0
- field public static final int CODERATE_2_5 = 2; // 0x2
- field public static final int CODERATE_3_5 = 4; // 0x4
- field public static final int CODERATE_4_5 = 8; // 0x8
- field public static final int CODERATE_AUTO = 1; // 0x1
- field public static final int CODERATE_UNDEFINED = 0; // 0x0
- field public static final int GUARD_INTERVAL_AUTO = 1; // 0x1
- field public static final int GUARD_INTERVAL_PN_420_CONST = 16; // 0x10
- field public static final int GUARD_INTERVAL_PN_420_VARIOUS = 2; // 0x2
- field public static final int GUARD_INTERVAL_PN_595_CONST = 4; // 0x4
- field public static final int GUARD_INTERVAL_PN_945_CONST = 32; // 0x20
- field public static final int GUARD_INTERVAL_PN_945_VARIOUS = 8; // 0x8
- field public static final int GUARD_INTERVAL_PN_RESERVED = 64; // 0x40
- field public static final int GUARD_INTERVAL_UNDEFINED = 0; // 0x0
- field public static final int MODULATION_CONSTELLATION_16QAM = 8; // 0x8
- field public static final int MODULATION_CONSTELLATION_32QAM = 16; // 0x10
- field public static final int MODULATION_CONSTELLATION_4QAM = 2; // 0x2
- field public static final int MODULATION_CONSTELLATION_4QAM_NR = 4; // 0x4
- field public static final int MODULATION_CONSTELLATION_64QAM = 32; // 0x20
- field public static final int MODULATION_CONSTELLATION_AUTO = 1; // 0x1
- field public static final int MODULATION_CONSTELLATION_UNDEFINED = 0; // 0x0
- field public static final int TIME_INTERLEAVE_MODE_AUTO = 1; // 0x1
- field public static final int TIME_INTERLEAVE_MODE_TIMER_INT_240 = 2; // 0x2
- field public static final int TIME_INTERLEAVE_MODE_TIMER_INT_720 = 4; // 0x4
- field public static final int TIME_INTERLEAVE_MODE_UNDEFINED = 0; // 0x0
- field public static final int TRANSMISSION_MODE_AUTO = 1; // 0x1
- field public static final int TRANSMISSION_MODE_C1 = 2; // 0x2
- field public static final int TRANSMISSION_MODE_C3780 = 4; // 0x4
- field public static final int TRANSMISSION_MODE_UNDEFINED = 0; // 0x0
- }
-
- public static final class DtmbFrontendSettings.Builder {
- method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings build();
- method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setBandwidth(int);
- method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setCodeRate(int);
- method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setFrequency(int);
- method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setGuardInterval(int);
- method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setModulation(int);
- method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setTimeInterleaveMode(int);
- method @NonNull public android.media.tv.tuner.frontend.DtmbFrontendSettings.Builder setTransmissionMode(int);
- }
-
- public class DvbcFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
- method public int getAnnexCapability();
- method public int getFecCapability();
- method public int getModulationCapability();
- }
-
- public class DvbcFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
- method @NonNull public static android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder builder();
- method public int getAnnex();
- method public int getBandwidth();
- method public long getInnerFec();
- method public int getModulation();
- method public int getOuterFec();
- method public int getSpectralInversion();
- method public int getSymbolRate();
- method public int getTimeInterleaveMode();
- method public int getType();
- field public static final int ANNEX_A = 1; // 0x1
- field public static final int ANNEX_B = 2; // 0x2
- field public static final int ANNEX_C = 4; // 0x4
- field public static final int ANNEX_UNDEFINED = 0; // 0x0
- field public static final int BANDWIDTH_5MHZ = 1; // 0x1
- field public static final int BANDWIDTH_6MHZ = 2; // 0x2
- field public static final int BANDWIDTH_7MHZ = 4; // 0x4
- field public static final int BANDWIDTH_8MHZ = 8; // 0x8
- field public static final int BANDWIDTH_UNDEFINED = 0; // 0x0
- field public static final int MODULATION_AUTO = 1; // 0x1
- field public static final int MODULATION_MOD_128QAM = 16; // 0x10
- field public static final int MODULATION_MOD_16QAM = 2; // 0x2
- field public static final int MODULATION_MOD_256QAM = 32; // 0x20
- field public static final int MODULATION_MOD_32QAM = 4; // 0x4
- field public static final int MODULATION_MOD_64QAM = 8; // 0x8
- field public static final int MODULATION_UNDEFINED = 0; // 0x0
- field public static final int OUTER_FEC_OUTER_FEC_NONE = 1; // 0x1
- field public static final int OUTER_FEC_OUTER_FEC_RS = 2; // 0x2
- field public static final int OUTER_FEC_UNDEFINED = 0; // 0x0
- field @Deprecated public static final int SPECTRAL_INVERSION_INVERTED = 2; // 0x2
- field @Deprecated public static final int SPECTRAL_INVERSION_NORMAL = 1; // 0x1
- field @Deprecated public static final int SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
- field public static final int TIME_INTERLEAVE_MODE_128_1_0 = 2; // 0x2
- field public static final int TIME_INTERLEAVE_MODE_128_1_1 = 4; // 0x4
- field public static final int TIME_INTERLEAVE_MODE_128_2 = 128; // 0x80
- field public static final int TIME_INTERLEAVE_MODE_128_3 = 256; // 0x100
- field public static final int TIME_INTERLEAVE_MODE_128_4 = 512; // 0x200
- field public static final int TIME_INTERLEAVE_MODE_16_8 = 32; // 0x20
- field public static final int TIME_INTERLEAVE_MODE_32_4 = 16; // 0x10
- field public static final int TIME_INTERLEAVE_MODE_64_2 = 8; // 0x8
- field public static final int TIME_INTERLEAVE_MODE_8_16 = 64; // 0x40
- field public static final int TIME_INTERLEAVE_MODE_AUTO = 1; // 0x1
- field public static final int TIME_INTERLEAVE_MODE_UNDEFINED = 0; // 0x0
- }
-
- public static class DvbcFrontendSettings.Builder {
- method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings build();
- method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setAnnex(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setBandwidth(int);
- method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setFrequency(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setInnerFec(long);
- method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setModulation(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setOuterFec(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSpectralInversion(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSymbolRate(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setTimeInterleaveMode(int);
- }
-
- public class DvbsCodeRate {
- method @NonNull public static android.media.tv.tuner.frontend.DvbsCodeRate.Builder builder();
- method public int getBitsPer1000Symbol();
- method public long getInnerFec();
- method public boolean isLinear();
- method public boolean isShortFrameEnabled();
- }
-
- public static class DvbsCodeRate.Builder {
- method @NonNull public android.media.tv.tuner.frontend.DvbsCodeRate build();
- method @NonNull public android.media.tv.tuner.frontend.DvbsCodeRate.Builder setBitsPer1000Symbol(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbsCodeRate.Builder setInnerFec(long);
- method @NonNull public android.media.tv.tuner.frontend.DvbsCodeRate.Builder setLinear(boolean);
- method @NonNull public android.media.tv.tuner.frontend.DvbsCodeRate.Builder setShortFrameEnabled(boolean);
- }
-
- public class DvbsFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
- method public long getInnerFecCapability();
- method public int getModulationCapability();
- method public int getStandardCapability();
- }
-
- public class DvbsFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
- method @NonNull public static android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder builder();
- method @Nullable public android.media.tv.tuner.frontend.DvbsCodeRate getCodeRate();
- method public int getInputStreamId();
- method public int getModulation();
- method public int getPilot();
- method public int getRolloff();
- method public int getScanType();
- method public int getStandard();
- method public int getSymbolRate();
- method public int getType();
- method public int getVcmMode();
- method public boolean isDiseqcRxMessage();
- field public static final int MODULATION_AUTO = 1; // 0x1
- field public static final int MODULATION_MOD_128APSK = 2048; // 0x800
- field public static final int MODULATION_MOD_16APSK = 256; // 0x100
- field public static final int MODULATION_MOD_16PSK = 16; // 0x10
- field public static final int MODULATION_MOD_16QAM = 8; // 0x8
- field public static final int MODULATION_MOD_256APSK = 4096; // 0x1000
- field public static final int MODULATION_MOD_32APSK = 512; // 0x200
- field public static final int MODULATION_MOD_32PSK = 32; // 0x20
- field public static final int MODULATION_MOD_64APSK = 1024; // 0x400
- field public static final int MODULATION_MOD_8APSK = 128; // 0x80
- field public static final int MODULATION_MOD_8PSK = 4; // 0x4
- field public static final int MODULATION_MOD_ACM = 64; // 0x40
- field public static final int MODULATION_MOD_QPSK = 2; // 0x2
- field public static final int MODULATION_MOD_RESERVED = 8192; // 0x2000
- field public static final int MODULATION_UNDEFINED = 0; // 0x0
- field public static final int PILOT_AUTO = 3; // 0x3
- field public static final int PILOT_OFF = 2; // 0x2
- field public static final int PILOT_ON = 1; // 0x1
- field public static final int PILOT_UNDEFINED = 0; // 0x0
- field public static final int ROLLOFF_0_10 = 5; // 0x5
- field public static final int ROLLOFF_0_15 = 4; // 0x4
- field public static final int ROLLOFF_0_20 = 3; // 0x3
- field public static final int ROLLOFF_0_25 = 2; // 0x2
- field public static final int ROLLOFF_0_35 = 1; // 0x1
- field public static final int ROLLOFF_0_5 = 6; // 0x6
- field public static final int ROLLOFF_UNDEFINED = 0; // 0x0
- field public static final int SCAN_TYPE_DIRECT = 1; // 0x1
- field public static final int SCAN_TYPE_DISEQC = 2; // 0x2
- field public static final int SCAN_TYPE_JESS = 4; // 0x4
- field public static final int SCAN_TYPE_UNDEFINED = 0; // 0x0
- field public static final int SCAN_TYPE_UNICABLE = 3; // 0x3
- field public static final int STANDARD_AUTO = 1; // 0x1
- field public static final int STANDARD_S = 2; // 0x2
- field public static final int STANDARD_S2 = 4; // 0x4
- field public static final int STANDARD_S2X = 8; // 0x8
- field public static final int VCM_MODE_AUTO = 1; // 0x1
- field public static final int VCM_MODE_MANUAL = 2; // 0x2
- field public static final int VCM_MODE_UNDEFINED = 0; // 0x0
- }
-
- public static class DvbsFrontendSettings.Builder {
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings build();
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCodeRate(@Nullable android.media.tv.tuner.frontend.DvbsCodeRate);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setDiseqcRxMessage(boolean);
- method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setFrequency(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setInputStreamId(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setModulation(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setPilot(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setRolloff(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setScanType(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setStandard(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setSymbolRate(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setVcmMode(int);
- }
-
- public class DvbtFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
- method public int getBandwidthCapability();
- method public int getCodeRateCapability();
- method public int getConstellationCapability();
- method public int getGuardIntervalCapability();
- method public int getHierarchyCapability();
- method public int getTransmissionModeCapability();
- method public boolean isMisoSupported();
- method public boolean isT2Supported();
- }
-
- public class DvbtFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
- method @NonNull public static android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder builder();
- method public int getBandwidth();
- method public int getConstellation();
- method public int getGuardInterval();
- method public int getHierarchy();
- method public int getHighPriorityCodeRate();
- method public int getLowPriorityCodeRate();
- method public int getPlpGroupId();
- method public int getPlpId();
- method public int getPlpMode();
- method public int getStandard();
- method public int getTransmissionMode();
- method public int getType();
- method public boolean isHighPriority();
- method public boolean isMiso();
- field public static final int BANDWIDTH_10MHZ = 64; // 0x40
- field public static final int BANDWIDTH_1_7MHZ = 32; // 0x20
- field public static final int BANDWIDTH_5MHZ = 16; // 0x10
- field public static final int BANDWIDTH_6MHZ = 8; // 0x8
- field public static final int BANDWIDTH_7MHZ = 4; // 0x4
- field public static final int BANDWIDTH_8MHZ = 2; // 0x2
- field public static final int BANDWIDTH_AUTO = 1; // 0x1
- field public static final int BANDWIDTH_UNDEFINED = 0; // 0x0
- field public static final int CODERATE_1_2 = 2; // 0x2
- field public static final int CODERATE_2_3 = 4; // 0x4
- field public static final int CODERATE_3_4 = 8; // 0x8
- field public static final int CODERATE_3_5 = 64; // 0x40
- field public static final int CODERATE_4_5 = 128; // 0x80
- field public static final int CODERATE_5_6 = 16; // 0x10
- field public static final int CODERATE_6_7 = 256; // 0x100
- field public static final int CODERATE_7_8 = 32; // 0x20
- field public static final int CODERATE_8_9 = 512; // 0x200
- field public static final int CODERATE_AUTO = 1; // 0x1
- field public static final int CODERATE_UNDEFINED = 0; // 0x0
- field public static final int CONSTELLATION_16QAM = 4; // 0x4
- field public static final int CONSTELLATION_16QAM_R = 64; // 0x40
- field public static final int CONSTELLATION_256QAM = 16; // 0x10
- field public static final int CONSTELLATION_256QAM_R = 256; // 0x100
- field public static final int CONSTELLATION_64QAM = 8; // 0x8
- field public static final int CONSTELLATION_64QAM_R = 128; // 0x80
- field public static final int CONSTELLATION_AUTO = 1; // 0x1
- field public static final int CONSTELLATION_QPSK = 2; // 0x2
- field public static final int CONSTELLATION_QPSK_R = 32; // 0x20
- field public static final int CONSTELLATION_UNDEFINED = 0; // 0x0
- field public static final int GUARD_INTERVAL_19_128 = 64; // 0x40
- field public static final int GUARD_INTERVAL_19_256 = 128; // 0x80
- field public static final int GUARD_INTERVAL_1_128 = 32; // 0x20
- field public static final int GUARD_INTERVAL_1_16 = 4; // 0x4
- field public static final int GUARD_INTERVAL_1_32 = 2; // 0x2
- field public static final int GUARD_INTERVAL_1_4 = 16; // 0x10
- field public static final int GUARD_INTERVAL_1_8 = 8; // 0x8
- field public static final int GUARD_INTERVAL_AUTO = 1; // 0x1
- field public static final int GUARD_INTERVAL_UNDEFINED = 0; // 0x0
- field public static final int HIERARCHY_1_INDEPTH = 64; // 0x40
- field public static final int HIERARCHY_1_NATIVE = 4; // 0x4
- field public static final int HIERARCHY_2_INDEPTH = 128; // 0x80
- field public static final int HIERARCHY_2_NATIVE = 8; // 0x8
- field public static final int HIERARCHY_4_INDEPTH = 256; // 0x100
- field public static final int HIERARCHY_4_NATIVE = 16; // 0x10
- field public static final int HIERARCHY_AUTO = 1; // 0x1
- field public static final int HIERARCHY_NON_INDEPTH = 32; // 0x20
- field public static final int HIERARCHY_NON_NATIVE = 2; // 0x2
- field public static final int HIERARCHY_UNDEFINED = 0; // 0x0
- field public static final int PLP_MODE_AUTO = 1; // 0x1
- field public static final int PLP_MODE_MANUAL = 2; // 0x2
- field public static final int PLP_MODE_UNDEFINED = 0; // 0x0
- field public static final int STANDARD_AUTO = 1; // 0x1
- field public static final int STANDARD_T = 2; // 0x2
- field public static final int STANDARD_T2 = 4; // 0x4
- field public static final int TRANSMISSION_MODE_16K = 32; // 0x20
- field public static final int TRANSMISSION_MODE_1K = 16; // 0x10
- field public static final int TRANSMISSION_MODE_2K = 2; // 0x2
- field public static final int TRANSMISSION_MODE_32K = 64; // 0x40
- field public static final int TRANSMISSION_MODE_4K = 8; // 0x8
- field public static final int TRANSMISSION_MODE_8K = 4; // 0x4
- field public static final int TRANSMISSION_MODE_AUTO = 1; // 0x1
- field public static final int TRANSMISSION_MODE_EXTENDED_16K = 256; // 0x100
- field public static final int TRANSMISSION_MODE_EXTENDED_32K = 512; // 0x200
- field public static final int TRANSMISSION_MODE_EXTENDED_8K = 128; // 0x80
- field public static final int TRANSMISSION_MODE_UNDEFINED = 0; // 0x0
- }
-
- public static class DvbtFrontendSettings.Builder {
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings build();
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setBandwidth(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setConstellation(int);
- method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setFrequency(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setGuardInterval(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHierarchy(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHighPriority(boolean);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHighPriorityCodeRate(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setLowPriorityCodeRate(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setMiso(boolean);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setPlpGroupId(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setPlpId(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setPlpMode(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setStandard(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setTransmissionMode(int);
- }
-
- public abstract class FrontendCapabilities {
- ctor public FrontendCapabilities();
- }
-
- public class FrontendInfo {
- method public int getAcquireRange();
- method public int getExclusiveGroupId();
- method @NonNull public android.util.Range<java.lang.Integer> getFrequencyRange();
- method @NonNull public android.media.tv.tuner.frontend.FrontendCapabilities getFrontendCapabilities();
- method public int getId();
- method @NonNull public int[] getStatusCapabilities();
- method @NonNull public android.util.Range<java.lang.Integer> getSymbolRateRange();
- method public int getType();
- }
-
- public abstract class FrontendSettings {
- method public int getEndFrequency();
- method public int getFrequency();
- method public int getFrontendSpectralInversion();
- method public abstract int getType();
- method @IntRange(from=1) public void setEndFrequency(int);
- method public void setSpectralInversion(int);
- field public static final long FEC_11_15 = 4194304L; // 0x400000L
- field public static final long FEC_11_20 = 8388608L; // 0x800000L
- field public static final long FEC_11_45 = 16777216L; // 0x1000000L
- field public static final long FEC_13_18 = 33554432L; // 0x2000000L
- field public static final long FEC_13_45 = 67108864L; // 0x4000000L
- field public static final long FEC_14_45 = 134217728L; // 0x8000000L
- field public static final long FEC_1_2 = 2L; // 0x2L
- field public static final long FEC_1_3 = 4L; // 0x4L
- field public static final long FEC_1_4 = 8L; // 0x8L
- field public static final long FEC_1_5 = 16L; // 0x10L
- field public static final long FEC_23_36 = 268435456L; // 0x10000000L
- field public static final long FEC_25_36 = 536870912L; // 0x20000000L
- field public static final long FEC_26_45 = 1073741824L; // 0x40000000L
- field public static final long FEC_28_45 = -2147483648L; // 0xffffffff80000000L
- field public static final long FEC_29_45 = 1L; // 0x1L
- field public static final long FEC_2_3 = 32L; // 0x20L
- field public static final long FEC_2_5 = 64L; // 0x40L
- field public static final long FEC_2_9 = 128L; // 0x80L
- field public static final long FEC_31_45 = 2L; // 0x2L
- field public static final long FEC_32_45 = 4L; // 0x4L
- field public static final long FEC_3_4 = 256L; // 0x100L
- field public static final long FEC_3_5 = 512L; // 0x200L
- field public static final long FEC_4_15 = 2048L; // 0x800L
- field public static final long FEC_4_5 = 1024L; // 0x400L
- field public static final long FEC_5_6 = 4096L; // 0x1000L
- field public static final long FEC_5_9 = 8192L; // 0x2000L
- field public static final long FEC_6_7 = 16384L; // 0x4000L
- field public static final long FEC_77_90 = 8L; // 0x8L
- field public static final long FEC_7_15 = 131072L; // 0x20000L
- field public static final long FEC_7_8 = 32768L; // 0x8000L
- field public static final long FEC_7_9 = 65536L; // 0x10000L
- field public static final long FEC_8_15 = 524288L; // 0x80000L
- field public static final long FEC_8_9 = 262144L; // 0x40000L
- field public static final long FEC_9_10 = 1048576L; // 0x100000L
- field public static final long FEC_9_20 = 2097152L; // 0x200000L
- field public static final long FEC_AUTO = 1L; // 0x1L
- field public static final long FEC_UNDEFINED = 0L; // 0x0L
- field public static final int FRONTEND_SPECTRAL_INVERSION_INVERTED = 2; // 0x2
- field public static final int FRONTEND_SPECTRAL_INVERSION_NORMAL = 1; // 0x1
- field public static final int FRONTEND_SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
- field public static final int TYPE_ANALOG = 1; // 0x1
- field public static final int TYPE_ATSC = 2; // 0x2
- field public static final int TYPE_ATSC3 = 3; // 0x3
- field public static final int TYPE_DTMB = 10; // 0xa
- field public static final int TYPE_DVBC = 4; // 0x4
- field public static final int TYPE_DVBS = 5; // 0x5
- field public static final int TYPE_DVBT = 6; // 0x6
- field public static final int TYPE_ISDBS = 7; // 0x7
- field public static final int TYPE_ISDBS3 = 8; // 0x8
- field public static final int TYPE_ISDBT = 9; // 0x9
- field public static final int TYPE_UNDEFINED = 0; // 0x0
- }
-
- public class FrontendStatus {
- method public int getAgc();
- method @NonNull public android.media.tv.tuner.frontend.FrontendStatus.Atsc3PlpTuningInfo[] getAtsc3PlpTuningInfo();
- method public int getBandwidth();
- method public int getBer();
- method @NonNull public int[] getBers();
- method @NonNull public int[] getCodeRates();
- method @NonNull public int[] getExtendedModulations();
- method public int getFreqOffset();
- method public int getGuardInterval();
- method public int getHierarchy();
- method public long getInnerFec();
- method @NonNull public int[] getInterleaving();
- method @IntRange(from=0, to=255) @NonNull public int[] getIsdbtSegment();
- method @NonNull public boolean[] getLayerErrors();
- method public int getLnbVoltage();
- method public int getMer();
- method public int getModulation();
- method public int getPer();
- method public int getPerBer();
- method public int getPlpId();
- method public int getSignalQuality();
- method public int getSignalStrength();
- method public int getSnr();
- method public int getSpectralInversion();
- method public int getSymbolRate();
- method @IntRange(from=0, to=65535) public int getSystemId();
- method public int getTransmissionMode();
- method @NonNull public int[] getTsDataRate();
- method public int getUec();
- method public boolean isDemodLocked();
- method public boolean isEwbs();
- method public boolean isLnaOn();
- method public boolean isRfLocked();
- field public static final int FRONTEND_STATUS_TYPE_AGC = 14; // 0xe
- field public static final int FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO = 21; // 0x15
- field public static final int FRONTEND_STATUS_TYPE_BANDWIDTH = 25; // 0x19
- field public static final int FRONTEND_STATUS_TYPE_BER = 2; // 0x2
- field public static final int FRONTEND_STATUS_TYPE_BERS = 23; // 0x17
- field public static final int FRONTEND_STATUS_TYPE_CODERATES = 24; // 0x18
- field public static final int FRONTEND_STATUS_TYPE_DEMOD_LOCK = 0; // 0x0
- field public static final int FRONTEND_STATUS_TYPE_EWBS = 13; // 0xd
- field public static final int FRONTEND_STATUS_TYPE_FEC = 8; // 0x8
- field public static final int FRONTEND_STATUS_TYPE_FREQ_OFFSET = 18; // 0x12
- field public static final int FRONTEND_STATUS_TYPE_GUARD_INTERVAL = 26; // 0x1a
- field public static final int FRONTEND_STATUS_TYPE_HIERARCHY = 19; // 0x13
- field public static final int FRONTEND_STATUS_TYPE_INTERLEAVINGS = 30; // 0x1e
- field public static final int FRONTEND_STATUS_TYPE_ISDBT_SEGMENTS = 31; // 0x1f
- field public static final int FRONTEND_STATUS_TYPE_LAYER_ERROR = 16; // 0x10
- field public static final int FRONTEND_STATUS_TYPE_LNA = 15; // 0xf
- field public static final int FRONTEND_STATUS_TYPE_LNB_VOLTAGE = 11; // 0xb
- field public static final int FRONTEND_STATUS_TYPE_MER = 17; // 0x11
- field public static final int FRONTEND_STATUS_TYPE_MODULATION = 9; // 0x9
- field public static final int FRONTEND_STATUS_TYPE_MODULATIONS_EXT = 22; // 0x16
- field public static final int FRONTEND_STATUS_TYPE_PER = 3; // 0x3
- field public static final int FRONTEND_STATUS_TYPE_PLP_ID = 12; // 0xc
- field public static final int FRONTEND_STATUS_TYPE_PRE_BER = 4; // 0x4
- field public static final int FRONTEND_STATUS_TYPE_RF_LOCK = 20; // 0x14
- field public static final int FRONTEND_STATUS_TYPE_SIGNAL_QUALITY = 5; // 0x5
- field public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH = 6; // 0x6
- field public static final int FRONTEND_STATUS_TYPE_SNR = 1; // 0x1
- field public static final int FRONTEND_STATUS_TYPE_SPECTRAL = 10; // 0xa
- field public static final int FRONTEND_STATUS_TYPE_SYMBOL_RATE = 7; // 0x7
- field public static final int FRONTEND_STATUS_TYPE_T2_SYSTEM_ID = 29; // 0x1d
- field public static final int FRONTEND_STATUS_TYPE_TRANSMISSION_MODE = 27; // 0x1b
- field public static final int FRONTEND_STATUS_TYPE_TS_DATA_RATES = 32; // 0x20
- field public static final int FRONTEND_STATUS_TYPE_UEC = 28; // 0x1c
- }
-
- public static class FrontendStatus.Atsc3PlpTuningInfo {
- method public int getPlpId();
- method public int getUec();
- method public boolean isLocked();
- }
-
- public class Isdbs3FrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
- method public int getCodeRateCapability();
- method public int getModulationCapability();
- }
-
- public class Isdbs3FrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
- method @NonNull public static android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder builder();
- method public int getCodeRate();
- method public int getModulation();
- method public int getRolloff();
- method public int getStreamId();
- method public int getStreamIdType();
- method public int getSymbolRate();
- method public int getType();
- field public static final int CODERATE_1_2 = 8; // 0x8
- field public static final int CODERATE_1_3 = 2; // 0x2
- field public static final int CODERATE_2_3 = 32; // 0x20
- field public static final int CODERATE_2_5 = 4; // 0x4
- field public static final int CODERATE_3_4 = 64; // 0x40
- field public static final int CODERATE_3_5 = 16; // 0x10
- field public static final int CODERATE_4_5 = 256; // 0x100
- field public static final int CODERATE_5_6 = 512; // 0x200
- field public static final int CODERATE_7_8 = 1024; // 0x400
- field public static final int CODERATE_7_9 = 128; // 0x80
- field public static final int CODERATE_9_10 = 2048; // 0x800
- field public static final int CODERATE_AUTO = 1; // 0x1
- field public static final int CODERATE_UNDEFINED = 0; // 0x0
- field public static final int MODULATION_AUTO = 1; // 0x1
- field public static final int MODULATION_MOD_16APSK = 16; // 0x10
- field public static final int MODULATION_MOD_32APSK = 32; // 0x20
- field public static final int MODULATION_MOD_8PSK = 8; // 0x8
- field public static final int MODULATION_MOD_BPSK = 2; // 0x2
- field public static final int MODULATION_MOD_QPSK = 4; // 0x4
- field public static final int MODULATION_UNDEFINED = 0; // 0x0
- field public static final int ROLLOFF_0_03 = 1; // 0x1
- field public static final int ROLLOFF_UNDEFINED = 0; // 0x0
- }
-
- public static class Isdbs3FrontendSettings.Builder {
- method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings build();
- method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setCodeRate(int);
- method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setFrequency(int);
- method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setModulation(int);
- method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setRolloff(int);
- method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setStreamId(int);
- method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setStreamIdType(int);
- method @NonNull public android.media.tv.tuner.frontend.Isdbs3FrontendSettings.Builder setSymbolRate(int);
- }
-
- public class IsdbsFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
- method public int getCodeRateCapability();
- method public int getModulationCapability();
- }
-
- public class IsdbsFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
- method @NonNull public static android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder builder();
- method public int getCodeRate();
- method public int getModulation();
- method public int getRolloff();
- method public int getStreamId();
- method public int getStreamIdType();
- method public int getSymbolRate();
- method public int getType();
- field public static final int CODERATE_1_2 = 2; // 0x2
- field public static final int CODERATE_2_3 = 4; // 0x4
- field public static final int CODERATE_3_4 = 8; // 0x8
- field public static final int CODERATE_5_6 = 16; // 0x10
- field public static final int CODERATE_7_8 = 32; // 0x20
- field public static final int CODERATE_AUTO = 1; // 0x1
- field public static final int CODERATE_UNDEFINED = 0; // 0x0
- field public static final int MODULATION_AUTO = 1; // 0x1
- field public static final int MODULATION_MOD_BPSK = 2; // 0x2
- field public static final int MODULATION_MOD_QPSK = 4; // 0x4
- field public static final int MODULATION_MOD_TC8PSK = 8; // 0x8
- field public static final int MODULATION_UNDEFINED = 0; // 0x0
- field public static final int ROLLOFF_0_35 = 1; // 0x1
- field public static final int ROLLOFF_UNDEFINED = 0; // 0x0
- field public static final int STREAM_ID_TYPE_ID = 0; // 0x0
- field public static final int STREAM_ID_TYPE_RELATIVE_NUMBER = 1; // 0x1
- }
-
- public static class IsdbsFrontendSettings.Builder {
- method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings build();
- method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setCodeRate(int);
- method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setFrequency(int);
- method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setModulation(int);
- method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setRolloff(int);
- method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setStreamId(int);
- method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setStreamIdType(int);
- method @NonNull public android.media.tv.tuner.frontend.IsdbsFrontendSettings.Builder setSymbolRate(int);
- }
-
- public class IsdbtFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
- method public int getBandwidthCapability();
- method public int getCodeRateCapability();
- method public int getGuardIntervalCapability();
- method public int getModeCapability();
- method public int getModulationCapability();
- }
-
- public class IsdbtFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
- method @NonNull public static android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder builder();
- method public int getBandwidth();
- method public int getCodeRate();
- method public int getGuardInterval();
- method public int getMode();
- method public int getModulation();
- method public int getServiceAreaId();
- method public int getType();
- field public static final int BANDWIDTH_6MHZ = 8; // 0x8
- field public static final int BANDWIDTH_7MHZ = 4; // 0x4
- field public static final int BANDWIDTH_8MHZ = 2; // 0x2
- field public static final int BANDWIDTH_AUTO = 1; // 0x1
- field public static final int BANDWIDTH_UNDEFINED = 0; // 0x0
- field public static final int MODE_1 = 2; // 0x2
- field public static final int MODE_2 = 4; // 0x4
- field public static final int MODE_3 = 8; // 0x8
- field public static final int MODE_AUTO = 1; // 0x1
- field public static final int MODE_UNDEFINED = 0; // 0x0
- field public static final int MODULATION_AUTO = 1; // 0x1
- field public static final int MODULATION_MOD_16QAM = 8; // 0x8
- field public static final int MODULATION_MOD_64QAM = 16; // 0x10
- field public static final int MODULATION_MOD_DQPSK = 2; // 0x2
- field public static final int MODULATION_MOD_QPSK = 4; // 0x4
- field public static final int MODULATION_UNDEFINED = 0; // 0x0
- }
-
- public static class IsdbtFrontendSettings.Builder {
- method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings build();
- method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setBandwidth(int);
- method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setCodeRate(int);
- method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setFrequency(int);
- method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setGuardInterval(int);
- method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setMode(int);
- method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setModulation(int);
- method @NonNull public android.media.tv.tuner.frontend.IsdbtFrontendSettings.Builder setServiceAreaId(int);
- }
-
- public interface OnTuneEventListener {
- method public void onTuneEvent(int);
- field public static final int SIGNAL_LOCKED = 0; // 0x0
- field public static final int SIGNAL_LOST_LOCK = 2; // 0x2
- field public static final int SIGNAL_NO_SIGNAL = 1; // 0x1
- }
-
- public interface ScanCallback {
- method public void onAnalogSifStandardReported(int);
- method public void onAtsc3PlpInfosReported(@NonNull android.media.tv.tuner.frontend.Atsc3PlpInfo[]);
- method public void onDvbsStandardReported(int);
- method public void onDvbtStandardReported(int);
- method public void onFrequenciesReported(@NonNull int[]);
- method public void onGroupIdsReported(@NonNull int[]);
- method public void onHierarchyReported(int);
- method public void onInputStreamIdsReported(@NonNull int[]);
- method public void onLocked();
- method public default void onModulationReported(int);
- method public void onPlpIdsReported(@NonNull int[]);
- method public default void onPriorityReported(boolean);
- method public void onProgress(@IntRange(from=0, to=100) int);
- method public void onScanStopped();
- method public void onSignalTypeReported(int);
- method public void onSymbolRatesReported(@NonNull int[]);
- }
-
-}
-
-package android.media.voice {
-
- public final class KeyphraseModelManager {
- method @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public void deleteKeyphraseSoundModel(int, @NonNull java.util.Locale);
- method @Nullable @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel getKeyphraseSoundModel(int, @NonNull java.util.Locale);
- method @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public void updateKeyphraseSoundModel(@NonNull android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel);
- }
-
-}
-
-package android.metrics {
-
- public class LogMaker {
- ctor public LogMaker(int);
- ctor public LogMaker(Object[]);
- method public android.metrics.LogMaker addTaggedData(int, Object);
- method public android.metrics.LogMaker clearCategory();
- method public android.metrics.LogMaker clearPackageName();
- method public android.metrics.LogMaker clearSubtype();
- method public android.metrics.LogMaker clearTaggedData(int);
- method public android.metrics.LogMaker clearType();
- method public void deserialize(Object[]);
- method public int getCategory();
- method public long getCounterBucket();
- method public String getCounterName();
- method public int getCounterValue();
- method public String getPackageName();
- method public int getProcessId();
- method public int getSubtype();
- method public Object getTaggedData(int);
- method public long getTimestamp();
- method public int getType();
- method public int getUid();
- method public boolean isLongCounterBucket();
- method public boolean isSubsetOf(android.metrics.LogMaker);
- method public boolean isValidValue(Object);
- method public Object[] serialize();
- method public android.metrics.LogMaker setCategory(int);
- method public android.metrics.LogMaker setPackageName(String);
- method public android.metrics.LogMaker setSubtype(int);
- method public android.metrics.LogMaker setType(int);
- }
-
- public class MetricsReader {
- ctor public MetricsReader();
- method public void checkpoint();
- method public boolean hasNext();
- method public android.metrics.LogMaker next();
- method public void read(long);
- method public void reset();
- }
-
-}
-
-package android.net {
-
- public class CaptivePortal implements android.os.Parcelable {
- method public void logEvent(int, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void reevaluateNetwork();
- method public void useNetwork();
- field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64
- field public static final int APP_RETURN_DISMISSED = 0; // 0x0
- field public static final int APP_RETURN_UNWANTED = 1; // 0x1
- field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
- }
-
- public final class CaptivePortalData implements android.os.Parcelable {
- method public int describeContents();
- method public long getByteLimit();
- method public long getExpiryTimeMillis();
- method public long getRefreshTimeMillis();
- method @Nullable public android.net.Uri getUserPortalUrl();
- method @Nullable public android.net.Uri getVenueInfoUrl();
- method public boolean isCaptive();
- method public boolean isSessionExtendable();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
- }
-
- public static class CaptivePortalData.Builder {
- ctor public CaptivePortalData.Builder();
- ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData);
- method @NonNull public android.net.CaptivePortalData build();
- method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long);
- method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean);
- method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long);
- method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
- method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
- method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
- }
-
- public class ConnectivityManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
- method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
- method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
- method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
- field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
- field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
- field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
- field public static final int TYPE_NONE = -1; // 0xffffffff
- field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
- }
-
- @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
- ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
- method @Deprecated public void onTetheringFailed();
- method @Deprecated public void onTetheringStarted();
- }
-
- @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
- method @Deprecated public void onTetheringEntitlementResult(int);
- }
-
- @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback {
- ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback();
- method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
- }
-
- public class EthernetManager {
- 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 {
- method public void onAvailable(@NonNull String);
- method public void onUnavailable();
- }
-
- public static class EthernetManager.TetheredInterfaceRequest {
- method public void release();
- }
-
- public final class InvalidPacketException extends java.lang.Exception {
- ctor public InvalidPacketException(int);
- method public int getError();
- field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
- field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
- field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
- }
-
- public final class IpConfiguration implements android.os.Parcelable {
- ctor public IpConfiguration();
- ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
- method public int describeContents();
- method @Nullable public android.net.ProxyInfo getHttpProxy();
- method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
- method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
- method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
- method public void setHttpProxy(@Nullable android.net.ProxyInfo);
- method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
- method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
- method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
- }
-
- public enum IpConfiguration.IpAssignment {
- enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP;
- enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC;
- enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED;
- }
-
- public enum IpConfiguration.ProxySettings {
- enum_constant public static final android.net.IpConfiguration.ProxySettings NONE;
- enum_constant public static final android.net.IpConfiguration.ProxySettings PAC;
- enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC;
- enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED;
- }
-
- public final class IpPrefix implements android.os.Parcelable {
- ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
- ctor public IpPrefix(@NonNull String);
- }
-
- public final class IpSecManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
- }
-
- public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
- method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
- method public void close();
- method @NonNull public String getInterfaceName();
- method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
- }
-
- public static class IpSecTransform.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- }
-
- public class KeepalivePacketData {
- ctor protected KeepalivePacketData(@NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull byte[]) throws android.net.InvalidPacketException;
- method @NonNull public java.net.InetAddress getDstAddress();
- method public int getDstPort();
- method @NonNull public byte[] getPacket();
- method @NonNull public java.net.InetAddress getSrcAddress();
- method public int getSrcPort();
- }
-
- public class LinkAddress implements android.os.Parcelable {
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
- ctor public LinkAddress(@NonNull String);
- ctor public LinkAddress(@NonNull String, int, int);
- method public long getDeprecationTime();
- method public long getExpirationTime();
- method public boolean isGlobalPreferred();
- method public boolean isIpv4();
- method public boolean isIpv6();
- method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
- field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
- field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
- }
-
- public final class LinkProperties implements android.os.Parcelable {
- ctor public LinkProperties(@Nullable android.net.LinkProperties);
- ctor public LinkProperties(@Nullable android.net.LinkProperties, boolean);
- method public boolean addDnsServer(@NonNull java.net.InetAddress);
- method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
- method public boolean addPcscfServer(@NonNull java.net.InetAddress);
- method @NonNull public java.util.List<java.net.InetAddress> getAddresses();
- method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames();
- method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses();
- method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes();
- method @Nullable public android.net.Uri getCaptivePortalApiUrl();
- method @Nullable public android.net.CaptivePortalData getCaptivePortalData();
- method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
- method @Nullable public String getTcpBufferSizes();
- method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
- method public boolean hasGlobalIpv6Address();
- method public boolean hasIpv4Address();
- method public boolean hasIpv4DefaultRoute();
- method public boolean hasIpv4DnsServer();
- method public boolean hasIpv6DefaultRoute();
- method public boolean hasIpv6DnsServer();
- method public boolean isIpv4Provisioned();
- method public boolean isIpv6Provisioned();
- method public boolean isProvisioned();
- method public boolean isReachable(@NonNull java.net.InetAddress);
- method public boolean removeDnsServer(@NonNull java.net.InetAddress);
- method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
- method public boolean removeRoute(@NonNull android.net.RouteInfo);
- method public void setCaptivePortalApiUrl(@Nullable android.net.Uri);
- method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData);
- method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
- method public void setPrivateDnsServerName(@Nullable String);
- method public void setTcpBufferSizes(@Nullable String);
- method public void setUsePrivateDns(boolean);
- method public void setValidatedPrivateDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
- }
-
- public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
- ctor public MatchAllNetworkSpecifier();
- method public int describeContents();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.MatchAllNetworkSpecifier> CREATOR;
- }
-
- public final class NattKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
- ctor public NattKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException;
- method public int describeContents();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NattKeepalivePacketData> CREATOR;
- }
-
- public class Network implements android.os.Parcelable {
- ctor public Network(@NonNull android.net.Network);
- method public int getNetId();
- method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
- }
-
- public abstract class NetworkAgent {
- ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
- method @Nullable public android.net.Network getNetwork();
- method public void markConnected();
- method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
- method public void onAutomaticReconnectDisabled();
- method public void onNetworkUnwanted();
- method public void onRemoveKeepalivePacketFilter(int);
- method public void onSaveAcceptUnvalidated(boolean);
- method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
- method public void onStartSocketKeepalive(int, @NonNull java.time.Duration, @NonNull android.net.KeepalivePacketData);
- method public void onStopSocketKeepalive(int);
- method public void onValidationStatus(int, @Nullable android.net.Uri);
- method @NonNull public android.net.Network register();
- method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
- method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
- method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
- method public final void sendSocketKeepaliveEvent(int, int);
- method public void unregister();
- field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
- field public static final int VALIDATION_STATUS_VALID = 1; // 0x1
- }
-
- public final class NetworkAgentConfig implements android.os.Parcelable {
- method public int describeContents();
- method public int getLegacyType();
- method @NonNull public String getLegacyTypeName();
- method public boolean isExplicitlySelected();
- method public boolean isPartialConnectivityAcceptable();
- method public boolean isUnvalidatedConnectivityAcceptable();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR;
- }
-
- public static final class NetworkAgentConfig.Builder {
- ctor public NetworkAgentConfig.Builder();
- method @NonNull public android.net.NetworkAgentConfig build();
- method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
- method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setUnvalidatedConnectivityAcceptable(boolean);
- }
-
- public final class NetworkCapabilities implements android.os.Parcelable {
- method @NonNull public int[] getAdministratorUids();
- method @Nullable public String getSsid();
- method @NonNull public int[] getTransportTypes();
- method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
- field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
- field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a
- field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
- }
-
- public static final class NetworkCapabilities.Builder {
- ctor public NetworkCapabilities.Builder();
- ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
- method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
- method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
- method @NonNull public android.net.NetworkCapabilities build();
- method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
- method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
- method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int);
- method @NonNull public android.net.NetworkCapabilities.Builder setLinkUpstreamBandwidthKbps(int);
- method @NonNull public android.net.NetworkCapabilities.Builder setNetworkSpecifier(@Nullable android.net.NetworkSpecifier);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setOwnerUid(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
- method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
- }
-
- public class NetworkKey implements android.os.Parcelable {
- ctor public NetworkKey(android.net.WifiKey);
- method @Nullable public static android.net.NetworkKey createFromScanResult(@NonNull android.net.wifi.ScanResult);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkKey> CREATOR;
- field public static final int TYPE_WIFI = 1; // 0x1
- field public final int type;
- field public final android.net.WifiKey wifiKey;
- }
-
- public class NetworkProvider {
- ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest);
- method public int getProviderId();
- method public void onNetworkRequestWithdrawn(@NonNull android.net.NetworkRequest);
- method public void onNetworkRequested(@NonNull android.net.NetworkRequest, @IntRange(from=0, to=99) int, int);
- field public static final int ID_NONE = -1; // 0xffffffff
- }
-
- public abstract class NetworkRecommendationProvider {
- ctor public NetworkRecommendationProvider(android.content.Context, java.util.concurrent.Executor);
- method public final android.os.IBinder getBinder();
- method public abstract void onRequestScores(android.net.NetworkKey[]);
- }
-
- public class NetworkRequest implements android.os.Parcelable {
- method @Nullable public String getRequestorPackageName();
- method public int getRequestorUid();
- }
-
- public static class NetworkRequest.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
- }
-
- public class NetworkScoreManager {
- method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean clearScores() throws java.lang.SecurityException;
- method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public void disableScoring() throws java.lang.SecurityException;
- method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public String getActiveScorerPackage();
- method @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public void registerNetworkScoreCallback(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkScoreManager.NetworkScoreCallback) throws java.lang.SecurityException;
- method @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public boolean requestScores(@NonNull java.util.Collection<android.net.NetworkKey>) throws java.lang.SecurityException;
- method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean setActiveScorer(String) throws java.lang.SecurityException;
- method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(@NonNull android.net.ScoredNetwork[]) throws java.lang.SecurityException;
- field @Deprecated public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
- field public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
- field public static final String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS";
- field public static final String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED";
- field @Deprecated public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
- field @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
- field public static final String EXTRA_NEW_SCORER = "newScorer";
- field @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName";
- field public static final int SCORE_FILTER_CURRENT_NETWORK = 1; // 0x1
- field public static final int SCORE_FILTER_NONE = 0; // 0x0
- field public static final int SCORE_FILTER_SCAN_RESULTS = 2; // 0x2
- }
-
- public abstract static class NetworkScoreManager.NetworkScoreCallback {
- ctor public NetworkScoreManager.NetworkScoreCallback();
- method public abstract void onScoresInvalidated();
- method public abstract void onScoresUpdated(@NonNull java.util.Collection<android.net.ScoredNetwork>);
- }
-
- public abstract class NetworkSpecifier {
- method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkSpecifier);
- method @Nullable public android.net.NetworkSpecifier redact();
- }
-
- public class NetworkStack {
- method @Nullable public static android.os.IBinder getService();
- field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK";
- }
-
- public final class NetworkStats implements android.os.Parcelable {
- ctor public NetworkStats(long, int);
- method @NonNull public android.net.NetworkStats add(@NonNull android.net.NetworkStats);
- method @NonNull public android.net.NetworkStats addEntry(@NonNull android.net.NetworkStats.Entry);
- method public int describeContents();
- method @NonNull public android.net.NetworkStats subtract(@NonNull android.net.NetworkStats);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStats> CREATOR;
- field public static final int DEFAULT_NETWORK_NO = 0; // 0x0
- field public static final int DEFAULT_NETWORK_YES = 1; // 0x1
- field public static final String IFACE_VT = "vt_data0";
- field public static final int METERED_NO = 0; // 0x0
- field public static final int METERED_YES = 1; // 0x1
- field public static final int ROAMING_NO = 0; // 0x0
- field public static final int ROAMING_YES = 1; // 0x1
- field public static final int SET_DEFAULT = 0; // 0x0
- field public static final int SET_FOREGROUND = 1; // 0x1
- field public static final int TAG_NONE = 0; // 0x0
- field public static final int UID_ALL = -1; // 0xffffffff
- field public static final int UID_TETHERING = -5; // 0xfffffffb
- }
-
- public static class NetworkStats.Entry {
- ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
- }
-
- public final class RouteInfo implements android.os.Parcelable {
- ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
- ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
- method public int getMtu();
- method public int getType();
- field public static final int RTN_THROW = 9; // 0x9
- field public static final int RTN_UNICAST = 1; // 0x1
- field public static final int RTN_UNREACHABLE = 7; // 0x7
- }
-
- public class RssiCurve implements android.os.Parcelable {
- ctor public RssiCurve(int, int, byte[]);
- ctor public RssiCurve(int, int, byte[], int);
- method public int describeContents();
- method public byte lookupScore(int);
- method public byte lookupScore(int, boolean);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.RssiCurve> CREATOR;
- field public final int activeNetworkRssiBoost;
- field public final int bucketWidth;
- field public final byte[] rssiBuckets;
- field public final int start;
- }
-
- public class ScoredNetwork implements android.os.Parcelable {
- ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve);
- ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean);
- ctor public ScoredNetwork(android.net.NetworkKey, android.net.RssiCurve, boolean, @Nullable android.os.Bundle);
- method public int calculateBadge(int);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final String ATTRIBUTES_KEY_BADGING_CURVE = "android.net.attributes.key.BADGING_CURVE";
- field public static final String ATTRIBUTES_KEY_HAS_CAPTIVE_PORTAL = "android.net.attributes.key.HAS_CAPTIVE_PORTAL";
- field public static final String ATTRIBUTES_KEY_RANKING_SCORE_OFFSET = "android.net.attributes.key.RANKING_SCORE_OFFSET";
- field @NonNull public static final android.os.Parcelable.Creator<android.net.ScoredNetwork> CREATOR;
- field @Nullable public final android.os.Bundle attributes;
- field public final boolean meteredHint;
- field public final android.net.NetworkKey networkKey;
- field public final android.net.RssiCurve rssiCurve;
- }
-
- public abstract class SocketKeepalive implements java.lang.AutoCloseable {
- field public static final int SUCCESS = 0; // 0x0
- }
-
- public final class StaticIpConfiguration implements android.os.Parcelable {
- ctor public StaticIpConfiguration();
- ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
- method public void addDnsServer(@NonNull java.net.InetAddress);
- method public void clear();
- method public int describeContents();
- method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
- method @Nullable public String getDomains();
- method @Nullable public java.net.InetAddress getGateway();
- method @Nullable public android.net.LinkAddress getIpAddress();
- method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
- }
-
- public static final class StaticIpConfiguration.Builder {
- ctor public StaticIpConfiguration.Builder();
- method @NonNull public android.net.StaticIpConfiguration build();
- method @NonNull public android.net.StaticIpConfiguration.Builder setDnsServers(@NonNull Iterable<java.net.InetAddress>);
- method @NonNull public android.net.StaticIpConfiguration.Builder setDomains(@Nullable String);
- method @NonNull public android.net.StaticIpConfiguration.Builder setGateway(@Nullable java.net.InetAddress);
- method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
- }
-
- public final class TetheredClient implements android.os.Parcelable {
- ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
- method public int describeContents();
- method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
- method @NonNull public android.net.MacAddress getMacAddress();
- method public int getTetheringType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
- }
-
- public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.LinkAddress getAddress();
- method @Nullable public String getHostname();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
- }
-
- public class TetheringManager {
- 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.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
- field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
- field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
- field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
- field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
- field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_ETHERNET = 5; // 0x5
- field public static final int TETHERING_INVALID = -1; // 0xffffffff
- field public static final int TETHERING_NCM = 4; // 0x4
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field public static final int TETHERING_WIFI_P2P = 3; // 0x3
- field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
- field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
- field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
- field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
- field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
- field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
- field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
- field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
- field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
- field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
- field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
- field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
- field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
- field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
- 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 {
- method public void onTetheringEntitlementResult(int);
- }
-
- public static interface TetheringManager.StartTetheringCallback {
- method public default void onTetheringFailed(int);
- method public default void onTetheringStarted();
- }
-
- public static interface TetheringManager.TetheringEventCallback {
- method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
- method public default void onError(@NonNull String, int);
- method public default void onOffloadStatusChanged(int);
- method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheringSupported(boolean);
- method public default void onUpstreamChanged(@Nullable android.net.Network);
- }
-
- public static class TetheringManager.TetheringRequest {
- method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
- method @Nullable public android.net.LinkAddress getLocalIpv4Address();
- method public boolean getShouldShowEntitlementUi();
- method public int getTetheringType();
- method public boolean isExemptFromEntitlementCheck();
- }
-
- public static class TetheringManager.TetheringRequest.Builder {
- ctor public TetheringManager.TetheringRequest.Builder(int);
- method @NonNull public android.net.TetheringManager.TetheringRequest build();
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
- }
-
- public class TrafficStats {
- method public static void setThreadStatsTagApp();
- method public static void setThreadStatsTagBackup();
- method public static void setThreadStatsTagRestore();
- field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = -113; // 0xffffff8f
- field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = -128; // 0xffffff80
- field public static final int TAG_NETWORK_STACK_RANGE_END = -257; // 0xfffffeff
- field public static final int TAG_NETWORK_STACK_RANGE_START = -768; // 0xfffffd00
- field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = -241; // 0xffffff0f
- field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = -256; // 0xffffff00
- }
-
- public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
- method @NonNull public String toSafeString();
- }
-
- public class VpnService extends android.app.Service {
- method @RequiresPermission(android.Manifest.permission.CONTROL_VPN) public static void prepareAndAuthorize(android.content.Context);
- }
-
- public class WebAddress {
- ctor public WebAddress(String) throws android.net.ParseException;
- }
-
- public class WifiKey implements android.os.Parcelable {
- ctor public WifiKey(String, String);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.WifiKey> CREATOR;
- field public final String bssid;
- field public final String ssid;
- }
-
-}
-
-package android.net.apf {
-
- public final class ApfCapabilities implements android.os.Parcelable {
- ctor public ApfCapabilities(int, int, int);
- method public int describeContents();
- method public static boolean getApfDrop8023Frames();
- method @NonNull public static int[] getApfEtherTypeBlackList();
- method public boolean hasDataAccess();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
- field public final int apfPacketFormat;
- field public final int apfVersionSupported;
- field public final int maximumApfProgramSize;
- }
-
-}
-
-package android.net.metrics {
-
- public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
- }
-
- public static final class ApfProgramEvent.Builder {
- ctor public ApfProgramEvent.Builder();
- method @NonNull public android.net.metrics.ApfProgramEvent build();
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
- method @NonNull public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
- }
-
- public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
- }
-
- public static final class ApfStats.Builder {
- ctor public ApfStats.Builder();
- method @NonNull public android.net.metrics.ApfStats build();
- method @NonNull public android.net.metrics.ApfStats.Builder setDroppedRas(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setDurationMs(long);
- method @NonNull public android.net.metrics.ApfStats.Builder setMatchingRas(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setParseErrors(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setReceivedRas(int);
- method @NonNull public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
- }
-
- public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
- }
-
- public static final class DhcpClientEvent.Builder {
- ctor public DhcpClientEvent.Builder();
- method @NonNull public android.net.metrics.DhcpClientEvent build();
- method @NonNull public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
- method @NonNull public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
- }
-
- public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event {
- ctor public DhcpErrorEvent(int);
- method public static int errorCodeWithOption(int, int);
- field public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000
- field public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000
- field public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000
- field public static final int DHCP_ERROR = 4; // 0x4
- field public static final int DHCP_INVALID_OPTION_LENGTH = 67305472; // 0x4030000
- field public static final int DHCP_NO_COOKIE = 67502080; // 0x4060000
- field public static final int DHCP_NO_MSG_TYPE = 67371008; // 0x4040000
- field public static final int DHCP_UNKNOWN_MSG_TYPE = 67436544; // 0x4050000
- field public static final int L2_ERROR = 1; // 0x1
- field public static final int L2_TOO_SHORT = 16842752; // 0x1010000
- field public static final int L2_WRONG_ETH_TYPE = 16908288; // 0x1020000
- field public static final int L3_ERROR = 2; // 0x2
- field public static final int L3_INVALID_IP = 33751040; // 0x2030000
- field public static final int L3_NOT_IPV4 = 33685504; // 0x2020000
- field public static final int L3_TOO_SHORT = 33619968; // 0x2010000
- field public static final int L4_ERROR = 3; // 0x3
- field public static final int L4_NOT_UDP = 50397184; // 0x3010000
- field public static final int L4_WRONG_PORT = 50462720; // 0x3020000
- field public static final int MISC_ERROR = 5; // 0x5
- field public static final int PARSING_ERROR = 84082688; // 0x5030000
- field public static final int RECEIVE_ERROR = 84017152; // 0x5020000
- }
-
- public class IpConnectivityLog {
- ctor public IpConnectivityLog();
- method public boolean log(long, @NonNull android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(@NonNull String, @NonNull android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(@NonNull android.net.Network, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(int, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(@NonNull android.net.metrics.IpConnectivityLog.Event);
- }
-
- public static interface IpConnectivityLog.Event extends android.os.Parcelable {
- }
-
- public final class IpManagerEvent implements android.net.metrics.IpConnectivityLog.Event {
- ctor public IpManagerEvent(int, long);
- field public static final int COMPLETE_LIFECYCLE = 3; // 0x3
- field public static final int ERROR_INTERFACE_NOT_FOUND = 8; // 0x8
- field public static final int ERROR_INVALID_PROVISIONING = 7; // 0x7
- field public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6; // 0x6
- field public static final int ERROR_STARTING_IPV4 = 4; // 0x4
- field public static final int ERROR_STARTING_IPV6 = 5; // 0x5
- field public static final int PROVISIONING_FAIL = 2; // 0x2
- field public static final int PROVISIONING_OK = 1; // 0x1
- }
-
- public final class IpReachabilityEvent implements android.net.metrics.IpConnectivityLog.Event {
- ctor public IpReachabilityEvent(int);
- field public static final int NUD_FAILED = 512; // 0x200
- field public static final int NUD_FAILED_ORGANIC = 1024; // 0x400
- field public static final int PROBE = 256; // 0x100
- field public static final int PROVISIONING_LOST = 768; // 0x300
- field public static final int PROVISIONING_LOST_ORGANIC = 1280; // 0x500
- }
-
- public final class NetworkEvent implements android.net.metrics.IpConnectivityLog.Event {
- ctor public NetworkEvent(int, long);
- ctor public NetworkEvent(int);
- field public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4
- field public static final int NETWORK_CONNECTED = 1; // 0x1
- field public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; // 0xc
- field public static final int NETWORK_DISCONNECTED = 7; // 0x7
- field public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa
- field public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8
- field public static final int NETWORK_LINGER = 5; // 0x5
- field public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; // 0xd
- field public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb
- field public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9
- field public static final int NETWORK_UNLINGER = 6; // 0x6
- field public static final int NETWORK_VALIDATED = 2; // 0x2
- field public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3
- }
-
- public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
- }
-
- public static final class RaEvent.Builder {
- ctor public RaEvent.Builder();
- method @NonNull public android.net.metrics.RaEvent build();
- method @NonNull public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
- method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
- method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
- method @NonNull public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
- method @NonNull public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
- method @NonNull public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
- }
-
- public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
- method @NonNull public static String getProbeName(int);
- field public static final int DNS_FAILURE = 0; // 0x0
- field public static final int DNS_SUCCESS = 1; // 0x1
- field public static final int PROBE_DNS = 0; // 0x0
- field public static final int PROBE_FALLBACK = 4; // 0x4
- field public static final int PROBE_HTTP = 1; // 0x1
- field public static final int PROBE_HTTPS = 2; // 0x2
- field public static final int PROBE_PAC = 3; // 0x3
- field public static final int PROBE_PRIVDNS = 5; // 0x5
- }
-
- public static final class ValidationProbeEvent.Builder {
- ctor public ValidationProbeEvent.Builder();
- method @NonNull public android.net.metrics.ValidationProbeEvent build();
- method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
- method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
- method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
- }
-
-}
-
-package android.net.netstats.provider {
-
- public abstract class NetworkStatsProvider {
- ctor public NetworkStatsProvider();
- method public void notifyAlertReached();
- method public void notifyLimitReached();
- method public void notifyStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats);
- method public abstract void onRequestStatsUpdate(int);
- method public abstract void onSetAlert(long);
- method public abstract void onSetLimit(@NonNull String, long);
- field public static final int QUOTA_UNLIMITED = -1; // 0xffffffff
- }
-
-}
-
-package android.net.sip {
-
- public class SipAudioCall {
- method @Nullable public android.net.rtp.AudioGroup getAudioGroup();
- method public void setAudioGroup(@NonNull android.net.rtp.AudioGroup);
- }
-
- public class SipManager {
- method @NonNull public java.util.List<android.net.sip.SipProfile> getProfiles() throws android.net.sip.SipException;
- field public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED";
- field public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL";
- field public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE";
- field public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP";
- field public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP";
- }
-
- public class SipProfile implements java.lang.Cloneable android.os.Parcelable java.io.Serializable {
- method public int getCallingUid();
- }
-
-}
-
-package android.net.util {
-
- public final class SocketUtils {
- method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
- method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
- method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
- method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
- method @Deprecated @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
- method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int, @NonNull byte[]);
- }
-
-}
-
-package android.net.wifi {
-
- public abstract class EasyConnectStatusCallback {
- ctor public EasyConnectStatusCallback();
- method public abstract void onConfiguratorSuccess(int);
- method public abstract void onEnrolleeSuccess(int);
- method public void onFailure(int);
- method public void onFailure(int, @Nullable String, @NonNull android.util.SparseArray<int[]>, @NonNull int[]);
- method public abstract void onProgress(int);
- field public static final int EASY_CONNECT_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0; // 0x0
- field public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_ACCEPTED = 3; // 0x3
- field public static final int EASY_CONNECT_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE = 2; // 0x2
- field public static final int EASY_CONNECT_EVENT_PROGRESS_RESPONSE_PENDING = 1; // 0x1
- field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_APPLIED = 1; // 0x1
- field public static final int EASY_CONNECT_EVENT_SUCCESS_CONFIGURATION_SENT = 0; // 0x0
- }
-
- @Deprecated public class RttManager {
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void disableResponder(android.net.wifi.RttManager.ResponderCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void enableResponder(android.net.wifi.RttManager.ResponderCallback);
- method @Deprecated public android.net.wifi.RttManager.Capabilities getCapabilities();
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.net.wifi.RttManager.RttCapabilities getRttCapabilities();
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startRanging(android.net.wifi.RttManager.RttParams[], android.net.wifi.RttManager.RttListener);
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopRanging(android.net.wifi.RttManager.RttListener);
- field @Deprecated public static final int BASE = 160256; // 0x27200
- field @Deprecated public static final int CMD_OP_ABORTED = 160260; // 0x27204
- field @Deprecated public static final int CMD_OP_DISABLE_RESPONDER = 160262; // 0x27206
- field @Deprecated public static final int CMD_OP_ENABLE_RESPONDER = 160261; // 0x27205
- field @Deprecated public static final int CMD_OP_ENALBE_RESPONDER_FAILED = 160264; // 0x27208
- field @Deprecated public static final int CMD_OP_ENALBE_RESPONDER_SUCCEEDED = 160263; // 0x27207
- field @Deprecated public static final int CMD_OP_FAILED = 160258; // 0x27202
- field @Deprecated public static final int CMD_OP_START_RANGING = 160256; // 0x27200
- field @Deprecated public static final int CMD_OP_STOP_RANGING = 160257; // 0x27201
- field @Deprecated public static final int CMD_OP_SUCCEEDED = 160259; // 0x27203
- field @Deprecated public static final String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description";
- field @Deprecated public static final int PREAMBLE_HT = 2; // 0x2
- field @Deprecated public static final int PREAMBLE_LEGACY = 1; // 0x1
- field @Deprecated public static final int PREAMBLE_VHT = 4; // 0x4
- field @Deprecated public static final int REASON_INITIATOR_NOT_ALLOWED_WHEN_RESPONDER_ON = -6; // 0xfffffffa
- field @Deprecated public static final int REASON_INVALID_LISTENER = -3; // 0xfffffffd
- field @Deprecated public static final int REASON_INVALID_REQUEST = -4; // 0xfffffffc
- field @Deprecated public static final int REASON_NOT_AVAILABLE = -2; // 0xfffffffe
- field @Deprecated public static final int REASON_PERMISSION_DENIED = -5; // 0xfffffffb
- field @Deprecated public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
- field @Deprecated public static final int RTT_BW_10_SUPPORT = 2; // 0x2
- field @Deprecated public static final int RTT_BW_160_SUPPORT = 32; // 0x20
- field @Deprecated public static final int RTT_BW_20_SUPPORT = 4; // 0x4
- field @Deprecated public static final int RTT_BW_40_SUPPORT = 8; // 0x8
- field @Deprecated public static final int RTT_BW_5_SUPPORT = 1; // 0x1
- field @Deprecated public static final int RTT_BW_80_SUPPORT = 16; // 0x10
- field @Deprecated public static final int RTT_CHANNEL_WIDTH_10 = 6; // 0x6
- field @Deprecated public static final int RTT_CHANNEL_WIDTH_160 = 3; // 0x3
- field @Deprecated public static final int RTT_CHANNEL_WIDTH_20 = 0; // 0x0
- field @Deprecated public static final int RTT_CHANNEL_WIDTH_40 = 1; // 0x1
- field @Deprecated public static final int RTT_CHANNEL_WIDTH_5 = 5; // 0x5
- field @Deprecated public static final int RTT_CHANNEL_WIDTH_80 = 2; // 0x2
- field @Deprecated public static final int RTT_CHANNEL_WIDTH_80P80 = 4; // 0x4
- field @Deprecated public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
- field @Deprecated public static final int RTT_PEER_NAN = 5; // 0x5
- field @Deprecated public static final int RTT_PEER_P2P_CLIENT = 4; // 0x4
- field @Deprecated public static final int RTT_PEER_P2P_GO = 3; // 0x3
- field @Deprecated public static final int RTT_PEER_TYPE_AP = 1; // 0x1
- field @Deprecated public static final int RTT_PEER_TYPE_STA = 2; // 0x2
- field @Deprecated public static final int RTT_PEER_TYPE_UNSPECIFIED = 0; // 0x0
- field @Deprecated public static final int RTT_STATUS_ABORTED = 8; // 0x8
- field @Deprecated public static final int RTT_STATUS_FAILURE = 1; // 0x1
- field @Deprecated public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6; // 0x6
- field @Deprecated public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12; // 0xc
- field @Deprecated public static final int RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE = 15; // 0xf
- field @Deprecated public static final int RTT_STATUS_FAIL_INVALID_TS = 9; // 0x9
- field @Deprecated public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4; // 0x4
- field @Deprecated public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7; // 0x7
- field @Deprecated public static final int RTT_STATUS_FAIL_NO_RSP = 2; // 0x2
- field @Deprecated public static final int RTT_STATUS_FAIL_PROTOCOL = 10; // 0xa
- field @Deprecated public static final int RTT_STATUS_FAIL_REJECTED = 3; // 0x3
- field @Deprecated public static final int RTT_STATUS_FAIL_SCHEDULE = 11; // 0xb
- field @Deprecated public static final int RTT_STATUS_FAIL_TM_TIMEOUT = 5; // 0x5
- field @Deprecated public static final int RTT_STATUS_INVALID_REQ = 13; // 0xd
- field @Deprecated public static final int RTT_STATUS_NO_WIFI = 14; // 0xe
- field @Deprecated public static final int RTT_STATUS_SUCCESS = 0; // 0x0
- field @Deprecated public static final int RTT_TYPE_11_MC = 4; // 0x4
- field @Deprecated public static final int RTT_TYPE_11_V = 2; // 0x2
- field @Deprecated public static final int RTT_TYPE_ONE_SIDED = 1; // 0x1
- field @Deprecated public static final int RTT_TYPE_TWO_SIDED = 2; // 0x2
- field @Deprecated public static final int RTT_TYPE_UNSPECIFIED = 0; // 0x0
- }
-
- @Deprecated public class RttManager.Capabilities {
- ctor @Deprecated public RttManager.Capabilities();
- field @Deprecated public int supportedPeerType;
- field @Deprecated public int supportedType;
- }
-
- @Deprecated public static class RttManager.ParcelableRttParams implements android.os.Parcelable {
- field @Deprecated @NonNull public android.net.wifi.RttManager.RttParams[] mParams;
- }
-
- @Deprecated public static class RttManager.ParcelableRttResults implements android.os.Parcelable {
- ctor @Deprecated public RttManager.ParcelableRttResults(android.net.wifi.RttManager.RttResult[]);
- field @Deprecated public android.net.wifi.RttManager.RttResult[] mResults;
- }
-
- @Deprecated public abstract static class RttManager.ResponderCallback {
- ctor @Deprecated public RttManager.ResponderCallback();
- method @Deprecated public abstract void onResponderEnableFailure(int);
- method @Deprecated public abstract void onResponderEnabled(android.net.wifi.RttManager.ResponderConfig);
- }
-
- @Deprecated public static class RttManager.ResponderConfig implements android.os.Parcelable {
- ctor @Deprecated public RttManager.ResponderConfig();
- method @Deprecated public int describeContents();
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.RttManager.ResponderConfig> CREATOR;
- field @Deprecated public int centerFreq0;
- field @Deprecated public int centerFreq1;
- field @Deprecated public int channelWidth;
- field @Deprecated public int frequency;
- field @Deprecated public String macAddress;
- field @Deprecated public int preamble;
- }
-
- @Deprecated public static class RttManager.RttCapabilities implements android.os.Parcelable {
- ctor @Deprecated public RttManager.RttCapabilities();
- field @Deprecated public int bwSupported;
- field @Deprecated public boolean lciSupported;
- field @Deprecated public boolean lcrSupported;
- field @Deprecated public int mcVersion;
- field @Deprecated public boolean oneSidedRttSupported;
- field @Deprecated public int preambleSupported;
- field @Deprecated public boolean responderSupported;
- field @Deprecated public boolean secureRttSupported;
- field @Deprecated public boolean supportedPeerType;
- field @Deprecated public boolean supportedType;
- field @Deprecated public boolean twoSided11McRttSupported;
- }
-
- @Deprecated public static interface RttManager.RttListener {
- method @Deprecated public void onAborted();
- method @Deprecated public void onFailure(int, String);
- method @Deprecated public void onSuccess(android.net.wifi.RttManager.RttResult[]);
- }
-
- @Deprecated public static class RttManager.RttParams {
- ctor @Deprecated public RttManager.RttParams();
- field @Deprecated public boolean LCIRequest;
- field @Deprecated public boolean LCRRequest;
- field @Deprecated public int bandwidth;
- field @Deprecated public String bssid;
- field @Deprecated public int burstTimeout;
- field @Deprecated public int centerFreq0;
- field @Deprecated public int centerFreq1;
- field @Deprecated public int channelWidth;
- field @Deprecated public int deviceType;
- field @Deprecated public int frequency;
- field @Deprecated public int interval;
- field @Deprecated public int numRetriesPerFTMR;
- field @Deprecated public int numRetriesPerMeasurementFrame;
- field @Deprecated public int numSamplesPerBurst;
- field @Deprecated public int num_retries;
- field @Deprecated public int num_samples;
- field @Deprecated public int numberBurst;
- field @Deprecated public int preamble;
- field @Deprecated public int requestType;
- field @Deprecated public boolean secure;
- }
-
- @Deprecated public static class RttManager.RttResult {
- ctor @Deprecated public RttManager.RttResult();
- field @Deprecated public android.net.wifi.RttManager.WifiInformationElement LCI;
- field @Deprecated public android.net.wifi.RttManager.WifiInformationElement LCR;
- field @Deprecated public String bssid;
- field @Deprecated public int burstDuration;
- field @Deprecated public int burstNumber;
- field @Deprecated public int distance;
- field @Deprecated public int distanceSpread;
- field @Deprecated public int distanceStandardDeviation;
- field @Deprecated public int distance_cm;
- field @Deprecated public int distance_sd_cm;
- field @Deprecated public int distance_spread_cm;
- field @Deprecated public int frameNumberPerBurstPeer;
- field @Deprecated public int measurementFrameNumber;
- field @Deprecated public int measurementType;
- field @Deprecated public int negotiatedBurstNum;
- field @Deprecated public int requestType;
- field @Deprecated public int retryAfterDuration;
- field @Deprecated public int rssi;
- field @Deprecated public int rssiSpread;
- field @Deprecated public int rssi_spread;
- field @Deprecated public long rtt;
- field @Deprecated public long rttSpread;
- field @Deprecated public long rttStandardDeviation;
- field @Deprecated public long rtt_ns;
- field @Deprecated public long rtt_sd_ns;
- field @Deprecated public long rtt_spread_ns;
- field @Deprecated public int rxRate;
- field @Deprecated public boolean secure;
- field @Deprecated public int status;
- field @Deprecated public int successMeasurementFrameNumber;
- field @Deprecated public long ts;
- field @Deprecated public int txRate;
- field @Deprecated public int tx_rate;
- }
-
- @Deprecated public static class RttManager.WifiInformationElement {
- ctor @Deprecated public RttManager.WifiInformationElement();
- field @Deprecated public byte[] data;
- field @Deprecated public byte id;
- }
-
- public final class ScanResult implements android.os.Parcelable {
- field public static final int CIPHER_CCMP = 3; // 0x3
- field public static final int CIPHER_GCMP_256 = 4; // 0x4
- field public static final int CIPHER_NONE = 0; // 0x0
- field public static final int CIPHER_NO_GROUP_ADDRESSED = 1; // 0x1
- field public static final int CIPHER_SMS4 = 5; // 0x5
- field public static final int CIPHER_TKIP = 2; // 0x2
- field public static final int KEY_MGMT_EAP = 2; // 0x2
- field public static final int KEY_MGMT_EAP_SHA256 = 6; // 0x6
- field public static final int KEY_MGMT_EAP_SUITE_B_192 = 10; // 0xa
- field public static final int KEY_MGMT_FT_EAP = 4; // 0x4
- field public static final int KEY_MGMT_FT_PSK = 3; // 0x3
- field public static final int KEY_MGMT_FT_SAE = 11; // 0xb
- field public static final int KEY_MGMT_NONE = 0; // 0x0
- field public static final int KEY_MGMT_OSEN = 7; // 0x7
- field public static final int KEY_MGMT_OWE = 9; // 0x9
- field public static final int KEY_MGMT_OWE_TRANSITION = 12; // 0xc
- field public static final int KEY_MGMT_PSK = 1; // 0x1
- field public static final int KEY_MGMT_PSK_SHA256 = 5; // 0x5
- field public static final int KEY_MGMT_SAE = 8; // 0x8
- field public static final int KEY_MGMT_WAPI_CERT = 14; // 0xe
- field public static final int KEY_MGMT_WAPI_PSK = 13; // 0xd
- field public static final int PROTOCOL_NONE = 0; // 0x0
- field public static final int PROTOCOL_OSEN = 3; // 0x3
- field public static final int PROTOCOL_RSN = 2; // 0x2
- field public static final int PROTOCOL_WAPI = 4; // 0x4
- field public static final int PROTOCOL_WPA = 1; // 0x1
- }
-
- public final class SoftApCapability implements android.os.Parcelable {
- method public boolean areFeaturesSupported(long);
- method public int describeContents();
- method public int getMaxSupportedClients();
- method @NonNull public int[] getSupportedChannelList(int);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApCapability> CREATOR;
- field public static final long SOFTAP_FEATURE_ACS_OFFLOAD = 1L; // 0x1L
- field public static final long SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 2L; // 0x2L
- field public static final long SOFTAP_FEATURE_MAC_ADDRESS_CUSTOMIZATION = 8L; // 0x8L
- field public static final long SOFTAP_FEATURE_WPA3_SAE = 4L; // 0x4L
- }
-
- public final class SoftApConfiguration implements android.os.Parcelable {
- method @NonNull public java.util.List<android.net.MacAddress> getAllowedClientList();
- method public int getBand();
- method @NonNull public int[] getBands();
- method @NonNull public java.util.List<android.net.MacAddress> getBlockedClientList();
- method public int getChannel();
- method @NonNull public android.util.SparseIntArray getChannels();
- method public int getMacRandomizationSetting();
- method public int getMaxNumberOfClients();
- method public long getShutdownTimeoutMillis();
- method public boolean isAutoShutdownEnabled();
- method public boolean isClientControlByUserEnabled();
- method @Nullable public android.net.wifi.WifiConfiguration toWifiConfiguration();
- field public static final int BAND_2GHZ = 1; // 0x1
- field public static final int BAND_5GHZ = 2; // 0x2
- field public static final int BAND_6GHZ = 4; // 0x4
- field @Deprecated public static final int BAND_ANY = 7; // 0x7
- field public static final int RANDOMIZATION_NONE = 0; // 0x0
- field public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1
- }
-
- public static final class SoftApConfiguration.Builder {
- ctor public SoftApConfiguration.Builder();
- ctor public SoftApConfiguration.Builder(@NonNull android.net.wifi.SoftApConfiguration);
- method @NonNull public android.net.wifi.SoftApConfiguration build();
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAllowedClientList(@NonNull java.util.List<android.net.MacAddress>);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAutoShutdownEnabled(boolean);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBands(@NonNull int[]);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBlockedClientList(@NonNull java.util.List<android.net.MacAddress>);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannels(@NonNull android.util.SparseIntArray);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientControlByUserEnabled(boolean);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMacRandomizationSetting(int);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(@IntRange(from=0) int);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setShutdownTimeoutMillis(@IntRange(from=0) long);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
- }
-
- public final class SoftApInfo implements android.os.Parcelable {
- method public int describeContents();
- method public int getBandwidth();
- method @Nullable public android.net.MacAddress getBssid();
- method public int getFrequency();
- method public int getWifiStandard();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int CHANNEL_WIDTH_160MHZ = 6; // 0x6
- field public static final int CHANNEL_WIDTH_20MHZ = 2; // 0x2
- field public static final int CHANNEL_WIDTH_20MHZ_NOHT = 1; // 0x1
- field public static final int CHANNEL_WIDTH_40MHZ = 3; // 0x3
- field public static final int CHANNEL_WIDTH_80MHZ = 4; // 0x4
- field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 5; // 0x5
- field public static final int CHANNEL_WIDTH_INVALID = 0; // 0x0
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApInfo> CREATOR;
- }
-
- public final class WifiClient implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.MacAddress getMacAddress();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiClient> CREATOR;
- }
-
- @Deprecated public class WifiConfiguration implements android.os.Parcelable {
- method @Deprecated public int getAuthType();
- method @Deprecated @NonNull public android.net.IpConfiguration getIpConfiguration();
- method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus getNetworkSelectionStatus();
- method @Deprecated @NonNull public String getPrintableSsid();
- method @Deprecated public int getRecentFailureReason();
- method @Deprecated public boolean hasNoInternetAccess();
- method @Deprecated public boolean isEphemeral();
- method @Deprecated public static boolean isMetered(@Nullable android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiInfo);
- method @Deprecated public boolean isNoInternetAccessExpected();
- method @Deprecated public void setIpConfiguration(@Nullable android.net.IpConfiguration);
- method @Deprecated public void setNetworkSelectionStatus(@NonNull android.net.wifi.WifiConfiguration.NetworkSelectionStatus);
- field @Deprecated public static final int INVALID_NETWORK_ID = -1; // 0xffffffff
- field @Deprecated public static final int METERED_OVERRIDE_METERED = 1; // 0x1
- field @Deprecated public static final int METERED_OVERRIDE_NONE = 0; // 0x0
- field @Deprecated public static final int METERED_OVERRIDE_NOT_METERED = 2; // 0x2
- field @Deprecated public static final int RANDOMIZATION_AUTO = 3; // 0x3
- field @Deprecated public static final int RANDOMIZATION_ENHANCED = 2; // 0x2
- field @Deprecated public static final int RANDOMIZATION_NONE = 0; // 0x0
- field @Deprecated public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1
- field @Deprecated public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11
- field @Deprecated public static final int RECENT_FAILURE_DISCONNECTION_AP_BUSY = 1004; // 0x3ec
- field @Deprecated public static final int RECENT_FAILURE_MBO_OCE_DISCONNECT = 1001; // 0x3e9
- field @Deprecated public static final int RECENT_FAILURE_NONE = 0; // 0x0
- field @Deprecated public static final int RECENT_FAILURE_POOR_CHANNEL_CONDITIONS = 1003; // 0x3eb
- field @Deprecated public static final int RECENT_FAILURE_REFUSED_TEMPORARILY = 1002; // 0x3ea
- field @Deprecated public boolean allowAutojoin;
- field @Deprecated public int carrierId;
- field @Deprecated public String creatorName;
- field @Deprecated public int creatorUid;
- field @Deprecated public boolean fromWifiNetworkSpecifier;
- field @Deprecated public boolean fromWifiNetworkSuggestion;
- field @Deprecated public String lastUpdateName;
- field @Deprecated public int lastUpdateUid;
- field @Deprecated public int macRandomizationSetting;
- field @Deprecated public boolean meteredHint;
- field @Deprecated public int meteredOverride;
- field @Deprecated public int numAssociation;
- field @Deprecated public int numScorerOverride;
- field @Deprecated public int numScorerOverrideAndSwitchedNetwork;
- field @Deprecated public boolean requirePmf;
- field @Deprecated public boolean shared;
- field @Deprecated public int subscriptionId;
- field @Deprecated public boolean useExternalScores;
- }
-
- @Deprecated public static class WifiConfiguration.KeyMgmt {
- field @Deprecated public static final int WAPI_CERT = 14; // 0xe
- field @Deprecated public static final int WAPI_PSK = 13; // 0xd
- field @Deprecated public static final int WPA2_PSK = 4; // 0x4
- }
-
- @Deprecated public static class WifiConfiguration.NetworkSelectionStatus {
- method @Deprecated public int getDisableReasonCounter(int);
- method @Deprecated public long getDisableTime();
- method @Deprecated public static int getMaxNetworkSelectionDisableReason();
- method @Deprecated public int getNetworkSelectionDisableReason();
- method @Deprecated @Nullable public static String getNetworkSelectionDisableReasonString(int);
- method @Deprecated public int getNetworkSelectionStatus();
- method @Deprecated @NonNull public String getNetworkStatusString();
- method @Deprecated public boolean hasEverConnected();
- field @Deprecated public static final int DISABLED_ASSOCIATION_REJECTION = 1; // 0x1
- field @Deprecated public static final int DISABLED_AUTHENTICATION_FAILURE = 2; // 0x2
- field @Deprecated public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5; // 0x5
- field @Deprecated public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9; // 0x9
- field @Deprecated public static final int DISABLED_BY_WIFI_MANAGER = 7; // 0x7
- field @Deprecated public static final int DISABLED_BY_WRONG_PASSWORD = 8; // 0x8
- field @Deprecated public static final int DISABLED_DHCP_FAILURE = 3; // 0x3
- field @Deprecated public static final int DISABLED_NONE = 0; // 0x0
- field @Deprecated public static final int DISABLED_NO_INTERNET_PERMANENT = 6; // 0x6
- field @Deprecated public static final int DISABLED_NO_INTERNET_TEMPORARY = 4; // 0x4
- field @Deprecated public static final int NETWORK_SELECTION_ENABLED = 0; // 0x0
- field @Deprecated public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2; // 0x2
- field @Deprecated public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1; // 0x1
- }
-
- @Deprecated public static final class WifiConfiguration.NetworkSelectionStatus.Builder {
- ctor @Deprecated public WifiConfiguration.NetworkSelectionStatus.Builder();
- method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus build();
- method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus.Builder setNetworkSelectionDisableReason(int);
- method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus.Builder setNetworkSelectionStatus(int);
- }
-
- public class WifiEnterpriseConfig implements android.os.Parcelable {
- method @Nullable public String[] getCaCertificateAliases();
- method @NonNull public String getCaPath();
- method @NonNull public String getClientCertificateAlias();
- method public int getOcsp();
- method @NonNull public String getWapiCertSuite();
- method public void setCaCertificateAliases(@Nullable String[]);
- method public void setCaPath(@NonNull String);
- method public void setClientCertificateAlias(@NonNull String);
- method public void setOcsp(int);
- method public void setWapiCertSuite(@NonNull String);
- field public static final int OCSP_NONE = 0; // 0x0
- field public static final int OCSP_REQUEST_CERT_STATUS = 1; // 0x1
- field public static final int OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS = 3; // 0x3
- field public static final int OCSP_REQUIRE_CERT_STATUS = 2; // 0x2
- }
-
- public class WifiFrameworkInitializer {
- method public static void registerServiceWrappers();
- }
-
- public class WifiInfo implements android.os.Parcelable {
- method public double getLostTxPacketsPerSecond();
- method @Nullable public String getRequestingPackageName();
- method public double getRetriedTxPacketsPerSecond();
- method public int getScore();
- method public double getSuccessfulRxPacketsPerSecond();
- method public double getSuccessfulTxPacketsPerSecond();
- method public boolean isEphemeral();
- method public boolean isOemPaid();
- method public boolean isOemPrivate();
- method public boolean isOsuAp();
- method public boolean isPasspointAp();
- method public boolean isTrusted();
- method @Nullable public static String sanitizeSsid(@Nullable String);
- field public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
- field public static final int INVALID_RSSI = -127; // 0xffffff81
- }
-
- public class WifiManager {
- method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoinGlobal(boolean);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoinPasspoint(@NonNull String, boolean);
- method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void clearWifiConnectedNetworkScorer();
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK}) public void disableEphemeralNetwork(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) 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.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>);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
- method @NonNull @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.Map<android.net.wifi.WifiNetworkSuggestion,java.util.List<android.net.wifi.ScanResult>> getMatchingScanResults(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>, @Nullable java.util.List<android.net.wifi.ScanResult>);
- method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
- method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void getWifiActivityEnergyInfoAsync(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
- method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(@NonNull java.util.List<android.net.wifi.ScanResult>);
- method public boolean is60GHzBandSupported();
- method public boolean isApMacRandomizationSupported();
- method public boolean isConnectedMacRandomizationSupported();
- method @Deprecated public boolean isDeviceToDeviceRttSupported();
- method public boolean isPortableHotspotSupported();
- method public boolean isVerboseLoggingEnabled();
- method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
- method public boolean isWifiScannerSupported();
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerNetworkRequestMatchCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
- method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]);
- method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public android.net.wifi.SoftApConfiguration restoreSoftApBackupData(@NonNull byte[]);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSupplicantBackupData(@NonNull byte[], @NonNull byte[]);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveBackupData();
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setAutoWakeupEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setPasspointMeteredOverride(@NonNull String, int);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanAlwaysAvailable(boolean);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanThrottleEnabled(boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setVerboseLoggingEnabled(boolean);
- method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
- method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public boolean setWifiConnectedNetworkScorer(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiConnectedNetworkScorer);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startLocalOnlyHotspot(@NonNull android.net.wifi.SoftApConfiguration, @Nullable java.util.concurrent.Executor, @Nullable android.net.wifi.WifiManager.LocalOnlyHotspotCallback);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startTetheredHotspot(@Nullable android.net.wifi.SoftApConfiguration);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean stopSoftAp();
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void updateInterfaceIpState(@Nullable String, int);
- method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void updateWifiUsabilityScore(int, int, int);
- field public static final String ACTION_LINK_CONFIGURATION_CHANGED = "android.net.wifi.LINK_CONFIGURATION_CHANGED";
- field @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public static final String ACTION_NETWORK_SETTINGS_RESET = "android.net.wifi.action.NETWORK_SETTINGS_RESET";
- field public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW = "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
- field public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
- field public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
- field public static final int CHANGE_REASON_ADDED = 0; // 0x0
- field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
- field public static final int CHANGE_REASON_REMOVED = 1; // 0x1
- field public static final String CONFIGURED_NETWORKS_CHANGED_ACTION = "android.net.wifi.CONFIGURED_NETWORKS_CHANGE";
- field public static final int DEVICE_MOBILITY_STATE_HIGH_MVMT = 1; // 0x1
- field public static final int DEVICE_MOBILITY_STATE_LOW_MVMT = 2; // 0x2
- field public static final int DEVICE_MOBILITY_STATE_STATIONARY = 3; // 0x3
- field public static final int DEVICE_MOBILITY_STATE_UNKNOWN = 0; // 0x0
- field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
- field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
- field public static final String EXTRA_CHANGE_REASON = "changeReason";
- field @Deprecated public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
- field @Deprecated public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
- field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
- field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
- field public static final String EXTRA_URL = "android.net.wifi.extra.URL";
- field public static final String EXTRA_WIFI_AP_FAILURE_REASON = "android.net.wifi.extra.WIFI_AP_FAILURE_REASON";
- field public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
- field public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
- field public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
- field @Deprecated public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
- field public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
- field public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
- field public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0; // 0x0
- field public static final int IFACE_IP_MODE_LOCAL_ONLY = 2; // 0x2
- field public static final int IFACE_IP_MODE_TETHERED = 1; // 0x1
- field public static final int IFACE_IP_MODE_UNSPECIFIED = -1; // 0xffffffff
- field public static final int PASSPOINT_HOME_NETWORK = 0; // 0x0
- field public static final int PASSPOINT_ROAMING_NETWORK = 1; // 0x1
- field public static final int SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER = 0; // 0x0
- field public static final int SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS = 1; // 0x1
- field public static final int SAP_START_FAILURE_GENERAL = 0; // 0x0
- field public static final int SAP_START_FAILURE_NO_CHANNEL = 1; // 0x1
- field public static final int SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION = 2; // 0x2
- field public static final String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED";
- field public static final int WIFI_AP_STATE_DISABLED = 11; // 0xb
- field public static final int WIFI_AP_STATE_DISABLING = 10; // 0xa
- field public static final int WIFI_AP_STATE_ENABLED = 13; // 0xd
- field public static final int WIFI_AP_STATE_ENABLING = 12; // 0xc
- field public static final int WIFI_AP_STATE_FAILED = 14; // 0xe
- field public static final String WIFI_CREDENTIAL_CHANGED_ACTION = "android.net.wifi.WIFI_CREDENTIAL_CHANGED";
- field public static final int WIFI_CREDENTIAL_FORGOT = 1; // 0x1
- field public static final int WIFI_CREDENTIAL_SAVED = 0; // 0x0
- }
-
- public static interface WifiManager.ActionListener {
- method public void onFailure(int);
- method public void onSuccess();
- }
-
- public static interface WifiManager.NetworkRequestMatchCallback {
- method public default void onAbort();
- method public default void onMatch(@NonNull java.util.List<android.net.wifi.ScanResult>);
- method public default void onUserSelectionCallbackRegistration(@NonNull android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback);
- method public default void onUserSelectionConnectFailure(@NonNull android.net.wifi.WifiConfiguration);
- method public default void onUserSelectionConnectSuccess(@NonNull android.net.wifi.WifiConfiguration);
- }
-
- public static interface WifiManager.NetworkRequestUserSelectionCallback {
- method public default void reject();
- method public default void select(@NonNull android.net.wifi.WifiConfiguration);
- }
-
- public static interface WifiManager.OnWifiActivityEnergyInfoListener {
- method public void onWifiActivityEnergyInfo(@Nullable android.os.connectivity.WifiActivityEnergyInfo);
- }
-
- public static interface WifiManager.OnWifiUsabilityStatsListener {
- method public void onWifiUsabilityStats(int, boolean, @NonNull android.net.wifi.WifiUsabilityStatsEntry);
- }
-
- public static interface WifiManager.ScoreUpdateObserver {
- method public void notifyScoreUpdate(int, int);
- method public void triggerUpdateOfWifiUsabilityStats(int);
- }
-
- public static interface WifiManager.SoftApCallback {
- method public default void onBlockedClientConnecting(@NonNull android.net.wifi.WifiClient, int);
- method public default void onCapabilityChanged(@NonNull android.net.wifi.SoftApCapability);
- method public default void onConnectedClientsChanged(@NonNull java.util.List<android.net.wifi.WifiClient>);
- method public default void onInfoChanged(@NonNull android.net.wifi.SoftApInfo);
- method public default void onStateChanged(int, int);
- }
-
- public static interface WifiManager.TrafficStateCallback {
- method public void onStateChanged(int);
- field public static final int DATA_ACTIVITY_IN = 1; // 0x1
- field public static final int DATA_ACTIVITY_INOUT = 3; // 0x3
- field public static final int DATA_ACTIVITY_NONE = 0; // 0x0
- field public static final int DATA_ACTIVITY_OUT = 2; // 0x2
- }
-
- public static interface WifiManager.WifiConnectedNetworkScorer {
- method public void onSetScoreUpdateObserver(@NonNull android.net.wifi.WifiManager.ScoreUpdateObserver);
- method public void onStart(int);
- method public void onStop(int);
- }
-
- public final class WifiMigration {
- method @Nullable public static java.io.InputStream convertAndRetrieveSharedConfigStoreFile(int);
- method @Nullable public static java.io.InputStream convertAndRetrieveUserConfigStoreFile(int, @NonNull android.os.UserHandle);
- method @NonNull public static android.net.wifi.WifiMigration.SettingsMigrationData loadFromSettings(@NonNull android.content.Context);
- method public static void removeSharedConfigStoreFile(int);
- method public static void removeUserConfigStoreFile(int, @NonNull android.os.UserHandle);
- field public static final int STORE_FILE_SHARED_GENERAL = 0; // 0x0
- field public static final int STORE_FILE_SHARED_SOFTAP = 1; // 0x1
- field public static final int STORE_FILE_USER_GENERAL = 2; // 0x2
- field public static final int STORE_FILE_USER_NETWORK_SUGGESTIONS = 3; // 0x3
- }
-
- public static final class WifiMigration.SettingsMigrationData implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public String getP2pDeviceName();
- method public boolean isP2pFactoryResetPending();
- method public boolean isScanAlwaysAvailable();
- method public boolean isScanThrottleEnabled();
- method public boolean isSoftApTimeoutEnabled();
- method public boolean isVerboseLoggingEnabled();
- method public boolean isWakeUpEnabled();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiMigration.SettingsMigrationData> CREATOR;
- }
-
- public static final class WifiMigration.SettingsMigrationData.Builder {
- ctor public WifiMigration.SettingsMigrationData.Builder();
- method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData build();
- method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setP2pDeviceName(@Nullable String);
- method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setP2pFactoryResetPending(boolean);
- method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setScanAlwaysAvailable(boolean);
- method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setScanThrottleEnabled(boolean);
- method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setSoftApTimeoutEnabled(boolean);
- method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setVerboseLoggingEnabled(boolean);
- method @NonNull public android.net.wifi.WifiMigration.SettingsMigrationData.Builder setWakeUpEnabled(boolean);
- }
-
- public class WifiNetworkConnectionStatistics implements android.os.Parcelable {
- ctor public WifiNetworkConnectionStatistics(int, int);
- ctor public WifiNetworkConnectionStatistics();
- ctor public WifiNetworkConnectionStatistics(android.net.wifi.WifiNetworkConnectionStatistics);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkConnectionStatistics> CREATOR;
- field public int numConnection;
- field public int numUsage;
- }
-
- public final class WifiNetworkSuggestion implements android.os.Parcelable {
- method @NonNull public android.net.wifi.WifiConfiguration getWifiConfiguration();
- method public boolean isOemPaid();
- method public boolean isOemPrivate();
- }
-
- public static final class WifiNetworkSuggestion.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public android.net.wifi.WifiNetworkSuggestion.Builder setCarrierId(int);
- method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setOemPaid(boolean);
- method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setOemPrivate(boolean);
- }
-
- public class WifiScanner {
- method @Deprecated public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]);
- method @Deprecated public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<java.lang.Integer> getAvailableChannels(int);
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean getScanResults();
- method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<android.net.wifi.ScanResult> getSingleScanResults();
- method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void registerScanListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiScanner.ScanListener);
- method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setScanningEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
- method @Deprecated public void startTrackingBssids(android.net.wifi.WifiScanner.BssidInfo[], int, android.net.wifi.WifiScanner.BssidListener);
- method @Deprecated public void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopBackgroundScan(android.net.wifi.WifiScanner.ScanListener);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopScan(android.net.wifi.WifiScanner.ScanListener);
- method @Deprecated public void stopTrackingBssids(android.net.wifi.WifiScanner.BssidListener);
- method @Deprecated public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
- method public void unregisterScanListener(@NonNull android.net.wifi.WifiScanner.ScanListener);
- field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
- field public static final int MIN_SCAN_PERIOD_MS = 1000; // 0x3e8
- field public static final int REASON_DUPLICATE_REQEUST = -5; // 0xfffffffb
- field public static final int REASON_INVALID_LISTENER = -2; // 0xfffffffe
- field public static final int REASON_INVALID_REQUEST = -3; // 0xfffffffd
- field public static final int REASON_NOT_AUTHORIZED = -4; // 0xfffffffc
- field public static final int REASON_SUCCEEDED = 0; // 0x0
- field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
- field @Deprecated public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0; // 0x0
- field public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; // 0x1
- field public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; // 0x2
- field public static final int REPORT_EVENT_NO_BATCH = 4; // 0x4
- field public static final int SCAN_TYPE_HIGH_ACCURACY = 2; // 0x2
- field public static final int SCAN_TYPE_LOW_LATENCY = 0; // 0x0
- field public static final int SCAN_TYPE_LOW_POWER = 1; // 0x1
- field public static final int WIFI_BAND_24_5_6_GHZ = 11; // 0xb
- field public static final int WIFI_BAND_24_5_WITH_DFS_6_GHZ = 15; // 0xf
- field public static final int WIFI_BAND_24_GHZ = 1; // 0x1
- field public static final int WIFI_BAND_5_GHZ = 2; // 0x2
- field public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; // 0x4
- field public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; // 0x6
- field public static final int WIFI_BAND_60_GHZ = 16; // 0x10
- field public static final int WIFI_BAND_6_GHZ = 8; // 0x8
- field public static final int WIFI_BAND_BOTH = 3; // 0x3
- field public static final int WIFI_BAND_BOTH_WITH_DFS = 7; // 0x7
- field public static final int WIFI_BAND_UNSPECIFIED = 0; // 0x0
- }
-
- public static interface WifiScanner.ActionListener {
- method public void onFailure(int, String);
- method public void onSuccess();
- }
-
- @Deprecated public static class WifiScanner.BssidInfo {
- ctor @Deprecated public WifiScanner.BssidInfo();
- field @Deprecated public String bssid;
- field @Deprecated public int frequencyHint;
- field @Deprecated public int high;
- field @Deprecated public int low;
- }
-
- @Deprecated public static interface WifiScanner.BssidListener extends android.net.wifi.WifiScanner.ActionListener {
- method @Deprecated public void onFound(android.net.wifi.ScanResult[]);
- method @Deprecated public void onLost(android.net.wifi.ScanResult[]);
- }
-
- public static class WifiScanner.ChannelSpec {
- ctor public WifiScanner.ChannelSpec(int);
- field public int frequency;
- }
-
- @Deprecated public static class WifiScanner.HotlistSettings implements android.os.Parcelable {
- ctor @Deprecated public WifiScanner.HotlistSettings();
- field @Deprecated public int apLostThreshold;
- field @Deprecated public android.net.wifi.WifiScanner.BssidInfo[] bssidInfos;
- }
-
- public static class WifiScanner.ParcelableScanData implements android.os.Parcelable {
- ctor public WifiScanner.ParcelableScanData(android.net.wifi.WifiScanner.ScanData[]);
- method public android.net.wifi.WifiScanner.ScanData[] getResults();
- field public android.net.wifi.WifiScanner.ScanData[] mResults;
- }
-
- public static class WifiScanner.ParcelableScanResults implements android.os.Parcelable {
- ctor public WifiScanner.ParcelableScanResults(android.net.wifi.ScanResult[]);
- method public android.net.wifi.ScanResult[] getResults();
- field public android.net.wifi.ScanResult[] mResults;
- }
-
- public static class WifiScanner.ScanData implements android.os.Parcelable {
- ctor public WifiScanner.ScanData(int, int, android.net.wifi.ScanResult[]);
- ctor public WifiScanner.ScanData(android.net.wifi.WifiScanner.ScanData);
- method public int getFlags();
- method public int getId();
- method public android.net.wifi.ScanResult[] getResults();
- }
-
- public static interface WifiScanner.ScanListener extends android.net.wifi.WifiScanner.ActionListener {
- method public void onFullResult(android.net.wifi.ScanResult);
- method @Deprecated public void onPeriodChanged(int);
- method public void onResults(android.net.wifi.WifiScanner.ScanData[]);
- }
-
- public static class WifiScanner.ScanSettings implements android.os.Parcelable {
- ctor public WifiScanner.ScanSettings();
- field public int band;
- field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
- field @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public final java.util.List<android.net.wifi.WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworks;
- field public boolean hideFromAppOps;
- field public boolean ignoreLocationSettings;
- field @Deprecated public int maxPeriodInMs;
- field @Deprecated public int maxScansToCache;
- field @Deprecated public int numBssidsPerScan;
- field @Deprecated public int periodInMs;
- field @Deprecated public int reportEvents;
- field @Deprecated public int stepCount;
- field @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public int type;
- }
-
- public static class WifiScanner.ScanSettings.HiddenNetwork {
- ctor public WifiScanner.ScanSettings.HiddenNetwork(@NonNull String);
- field @NonNull public final String ssid;
- }
-
- @Deprecated public static interface WifiScanner.WifiChangeListener extends android.net.wifi.WifiScanner.ActionListener {
- method @Deprecated public void onChanging(android.net.wifi.ScanResult[]);
- method @Deprecated public void onQuiescence(android.net.wifi.ScanResult[]);
- }
-
- @Deprecated public static class WifiScanner.WifiChangeSettings implements android.os.Parcelable {
- ctor @Deprecated public WifiScanner.WifiChangeSettings();
- field @Deprecated public android.net.wifi.WifiScanner.BssidInfo[] bssidInfos;
- field @Deprecated public int lostApSampleSize;
- field @Deprecated public int minApsBreachingThreshold;
- field @Deprecated public int periodInMs;
- field @Deprecated public int rssiSampleSize;
- field @Deprecated public int unchangedSampleSize;
- }
-
- public final class WifiUsabilityStatsEntry implements android.os.Parcelable {
- method public int describeContents();
- method public int getCellularDataNetworkType();
- method public int getCellularSignalStrengthDb();
- method public int getCellularSignalStrengthDbm();
- method public int getLinkSpeedMbps();
- method public int getProbeElapsedTimeSinceLastUpdateMillis();
- method public int getProbeMcsRateSinceLastUpdate();
- method public int getProbeStatusSinceLastUpdate();
- method public int getRssi();
- method public int getRxLinkSpeedMbps();
- method public long getTimeStampMillis();
- method public long getTotalBackgroundScanTimeMillis();
- method public long getTotalBeaconRx();
- method public long getTotalCcaBusyFreqTimeMillis();
- method public long getTotalHotspot2ScanTimeMillis();
- method public long getTotalNanScanTimeMillis();
- method public long getTotalPnoScanTimeMillis();
- method public long getTotalRadioOnFreqTimeMillis();
- method public long getTotalRadioOnTimeMillis();
- method public long getTotalRadioRxTimeMillis();
- method public long getTotalRadioTxTimeMillis();
- method public long getTotalRoamScanTimeMillis();
- method public long getTotalRxSuccess();
- method public long getTotalScanTimeMillis();
- method public long getTotalTxBad();
- method public long getTotalTxRetries();
- method public long getTotalTxSuccess();
- method public boolean isSameRegisteredCell();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiUsabilityStatsEntry> CREATOR;
- field public static final int PROBE_STATUS_FAILURE = 3; // 0x3
- field public static final int PROBE_STATUS_NO_PROBE = 1; // 0x1
- field public static final int PROBE_STATUS_SUCCESS = 2; // 0x2
- field public static final int PROBE_STATUS_UNKNOWN = 0; // 0x0
- }
-
-}
-
-package android.net.wifi.aware {
-
- public class DiscoverySession implements java.lang.AutoCloseable {
- method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPmk(@NonNull android.net.wifi.aware.PeerHandle, @NonNull byte[]);
- }
-
- public class WifiAwareManager {
- method public void enableInstantCommunicationMode(boolean);
- }
-
- public class WifiAwareSession implements java.lang.AutoCloseable {
- method public android.net.NetworkSpecifier createNetworkSpecifierPmk(int, @NonNull byte[], @NonNull byte[]);
- }
-
-}
-
-package android.net.wifi.hotspot2 {
-
- public final class OsuProvider implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public String getFriendlyName();
- method @Nullable public android.net.Uri getServerUri();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.OsuProvider> CREATOR;
- }
-
- public final class PasspointConfiguration implements android.os.Parcelable {
- method public int getMeteredOverride();
- method public boolean isAutojoinEnabled();
- method public boolean isMacRandomizationEnabled();
- }
-
- public abstract class ProvisioningCallback {
- ctor public ProvisioningCallback();
- method public abstract void onProvisioningComplete();
- method public abstract void onProvisioningFailure(int);
- method public abstract void onProvisioningStatus(int);
- field public static final int OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION = 22; // 0x16
- field public static final int OSU_FAILURE_AP_CONNECTION = 1; // 0x1
- field public static final int OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU = 8; // 0x8
- field public static final int OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE = 17; // 0x11
- field public static final int OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE = 21; // 0x15
- field public static final int OSU_FAILURE_NO_OSU_ACTIVITY_FOUND = 14; // 0xe
- field public static final int OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE = 19; // 0x13
- field public static final int OSU_FAILURE_NO_PPS_MO = 16; // 0x10
- field public static final int OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE = 18; // 0x12
- field public static final int OSU_FAILURE_OSU_PROVIDER_NOT_FOUND = 23; // 0x17
- field public static final int OSU_FAILURE_PROVISIONING_ABORTED = 6; // 0x6
- field public static final int OSU_FAILURE_PROVISIONING_NOT_AVAILABLE = 7; // 0x7
- field public static final int OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES = 20; // 0x14
- field public static final int OSU_FAILURE_SERVER_CONNECTION = 3; // 0x3
- field public static final int OSU_FAILURE_SERVER_URL_INVALID = 2; // 0x2
- field public static final int OSU_FAILURE_SERVER_VALIDATION = 4; // 0x4
- field public static final int OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION = 5; // 0x5
- field public static final int OSU_FAILURE_SOAP_MESSAGE_EXCHANGE = 11; // 0xb
- field public static final int OSU_FAILURE_START_REDIRECT_LISTENER = 12; // 0xc
- field public static final int OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER = 13; // 0xd
- field public static final int OSU_FAILURE_UNEXPECTED_COMMAND_TYPE = 9; // 0x9
- field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS = 15; // 0xf
- field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE = 10; // 0xa
- field public static final int OSU_STATUS_AP_CONNECTED = 2; // 0x2
- field public static final int OSU_STATUS_AP_CONNECTING = 1; // 0x1
- field public static final int OSU_STATUS_INIT_SOAP_EXCHANGE = 6; // 0x6
- field public static final int OSU_STATUS_REDIRECT_RESPONSE_RECEIVED = 8; // 0x8
- field public static final int OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS = 11; // 0xb
- field public static final int OSU_STATUS_SECOND_SOAP_EXCHANGE = 9; // 0x9
- field public static final int OSU_STATUS_SERVER_CONNECTED = 5; // 0x5
- field public static final int OSU_STATUS_SERVER_CONNECTING = 3; // 0x3
- field public static final int OSU_STATUS_SERVER_VALIDATED = 4; // 0x4
- field public static final int OSU_STATUS_THIRD_SOAP_EXCHANGE = 10; // 0xa
- field public static final int OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE = 7; // 0x7
- }
-
-}
-
-package android.net.wifi.nl80211 {
-
- public final class DeviceWiphyCapabilities implements android.os.Parcelable {
- ctor public DeviceWiphyCapabilities();
- method public int describeContents();
- method public int getMaxNumberRxSpatialStreams();
- method public int getMaxNumberTxSpatialStreams();
- method public boolean isChannelWidthSupported(int);
- method public boolean isWifiStandardSupported(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;
- }
-
- public final class NativeScanResult implements android.os.Parcelable {
- ctor public NativeScanResult();
- method public int describeContents();
- method @Nullable public android.net.MacAddress getBssid();
- method public int getCapabilities();
- method public int getFrequencyMhz();
- method @NonNull public byte[] getInformationElements();
- method @NonNull public java.util.List<android.net.wifi.nl80211.RadioChainInfo> getRadioChainInfos();
- method public int getSignalMbm();
- method @NonNull public byte[] getSsid();
- method public long getTsf();
- method public boolean isAssociated();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int BSS_CAPABILITY_APSD = 2048; // 0x800
- field public static final int BSS_CAPABILITY_CF_POLLABLE = 4; // 0x4
- field public static final int BSS_CAPABILITY_CF_POLL_REQUEST = 8; // 0x8
- field public static final int BSS_CAPABILITY_CHANNEL_AGILITY = 128; // 0x80
- field public static final int BSS_CAPABILITY_DELAYED_BLOCK_ACK = 16384; // 0x4000
- field public static final int BSS_CAPABILITY_DMG_ESS = 3; // 0x3
- field public static final int BSS_CAPABILITY_DMG_IBSS = 1; // 0x1
- field public static final int BSS_CAPABILITY_DSSS_OFDM = 8192; // 0x2000
- field public static final int BSS_CAPABILITY_ESS = 1; // 0x1
- field public static final int BSS_CAPABILITY_IBSS = 2; // 0x2
- field public static final int BSS_CAPABILITY_IMMEDIATE_BLOCK_ACK = 32768; // 0x8000
- field public static final int BSS_CAPABILITY_PBCC = 64; // 0x40
- field public static final int BSS_CAPABILITY_PRIVACY = 16; // 0x10
- field public static final int BSS_CAPABILITY_QOS = 512; // 0x200
- field public static final int BSS_CAPABILITY_RADIO_MANAGEMENT = 4096; // 0x1000
- field public static final int BSS_CAPABILITY_SHORT_PREAMBLE = 32; // 0x20
- field public static final int BSS_CAPABILITY_SHORT_SLOT_TIME = 1024; // 0x400
- field public static final int BSS_CAPABILITY_SPECTRUM_MANAGEMENT = 256; // 0x100
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.NativeScanResult> CREATOR;
- }
-
- public final class NativeWifiClient implements android.os.Parcelable {
- ctor public NativeWifiClient(@Nullable android.net.MacAddress);
- method public int describeContents();
- method @Nullable public android.net.MacAddress getMacAddress();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.NativeWifiClient> CREATOR;
- }
-
- public final class PnoNetwork implements android.os.Parcelable {
- ctor public PnoNetwork();
- method public int describeContents();
- method @NonNull public int[] getFrequenciesMhz();
- method @NonNull public byte[] getSsid();
- method public boolean isHidden();
- method public void setFrequenciesMhz(@NonNull int[]);
- method public void setHidden(boolean);
- method public void setSsid(@NonNull byte[]);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.PnoNetwork> CREATOR;
- }
-
- public final class PnoSettings implements android.os.Parcelable {
- ctor public PnoSettings();
- method public int describeContents();
- method public long getIntervalMillis();
- method public int getMin2gRssiDbm();
- method public int getMin5gRssiDbm();
- method public int getMin6gRssiDbm();
- method @NonNull public java.util.List<android.net.wifi.nl80211.PnoNetwork> getPnoNetworks();
- method public void setIntervalMillis(long);
- method public void setMin2gRssiDbm(int);
- method public void setMin5gRssiDbm(int);
- method public void setMin6gRssiDbm(int);
- method public void setPnoNetworks(@NonNull java.util.List<android.net.wifi.nl80211.PnoNetwork>);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.PnoSettings> CREATOR;
- }
-
- public final class RadioChainInfo implements android.os.Parcelable {
- ctor public RadioChainInfo(int, int);
- method public int describeContents();
- method public int getChainId();
- method public int getLevelDbm();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.RadioChainInfo> CREATOR;
- }
-
- public class WifiNl80211Manager {
- method public void abortScan(@NonNull String);
- method public void enableVerboseLogging(boolean);
- method @NonNull public int[] getChannelsMhzForBand(int);
- method @Nullable public android.net.wifi.nl80211.DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String);
- method @NonNull public java.util.List<android.net.wifi.nl80211.NativeScanResult> getScanResults(@NonNull String, int);
- method @Nullable public android.net.wifi.nl80211.WifiNl80211Manager.TxPacketCounters getTxPacketCounters(@NonNull String);
- method @Nullable public static android.net.wifi.nl80211.WifiNl80211Manager.OemSecurityType parseOemSecurityTypeElement(int, int, @NonNull byte[]);
- method @Deprecated public boolean registerApCallback(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.SoftApCallback);
- method public void sendMgmtFrame(@NonNull String, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.SendMgmtFrameCallback);
- method public void setOnServiceDeadCallback(@NonNull Runnable);
- method public boolean setupInterfaceForClientMode(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.ScanEventCallback, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.ScanEventCallback);
- method public boolean setupInterfaceForSoftApMode(@NonNull String);
- method @Nullable public android.net.wifi.nl80211.WifiNl80211Manager.SignalPollResult signalPoll(@NonNull String);
- method public boolean startPnoScan(@NonNull String, @NonNull android.net.wifi.nl80211.PnoSettings, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.PnoScanRequestCallback);
- method public boolean startScan(@NonNull String, int, @Nullable java.util.Set<java.lang.Integer>, @Nullable java.util.List<byte[]>);
- method public boolean stopPnoScan(@NonNull String);
- method public boolean tearDownClientInterface(@NonNull String);
- method public boolean tearDownInterfaces();
- method public boolean tearDownSoftApInterface(@NonNull String);
- field public static final int SCAN_TYPE_PNO_SCAN = 1; // 0x1
- field public static final int SCAN_TYPE_SINGLE_SCAN = 0; // 0x0
- field public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5; // 0x5
- field public static final int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2; // 0x2
- field public static final int SEND_MGMT_FRAME_ERROR_NO_ACK = 3; // 0x3
- field public static final int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4; // 0x4
- field public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1; // 0x1
- }
-
- public static class WifiNl80211Manager.OemSecurityType {
- ctor public WifiNl80211Manager.OemSecurityType(int, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>, int);
- field public final int groupCipher;
- field @NonNull public final java.util.List<java.lang.Integer> keyManagement;
- field @NonNull public final java.util.List<java.lang.Integer> pairwiseCipher;
- field public final int protocol;
- }
-
- public static interface WifiNl80211Manager.PnoScanRequestCallback {
- method public void onPnoRequestFailed();
- method public void onPnoRequestSucceeded();
- }
-
- public static interface WifiNl80211Manager.ScanEventCallback {
- method public void onScanFailed();
- method public void onScanResultReady();
- }
-
- public static interface WifiNl80211Manager.SendMgmtFrameCallback {
- method public void onAck(int);
- method public void onFailure(int);
- }
-
- public static class WifiNl80211Manager.SignalPollResult {
- field public final int associationFrequencyMHz;
- field public final int currentRssiDbm;
- field public final int rxBitrateMbps;
- field public final int txBitrateMbps;
- }
-
- @Deprecated public static interface WifiNl80211Manager.SoftApCallback {
- method @Deprecated public void onConnectedClientsChanged(@NonNull android.net.wifi.nl80211.NativeWifiClient, boolean);
- method @Deprecated public void onFailure();
- method @Deprecated public void onSoftApChannelSwitched(int, int);
- }
-
- public static class WifiNl80211Manager.TxPacketCounters {
- field public final int txPacketFailed;
- field public final int txPacketSucceeded;
- }
-
-}
-
-package android.net.wifi.p2p {
-
- public final class WifiP2pGroupList implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public java.util.List<android.net.wifi.p2p.WifiP2pGroup> getGroupList();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pGroupList> CREATOR;
- }
-
- public class WifiP2pManager {
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void deletePersistentGroup(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public void requestPersistentGroupInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.PersistentGroupInfoListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setDeviceName(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull String, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
- method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setMiracastMode(int);
- method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setWfdInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pWfdInfo, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setWifiP2pChannels(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void startListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
- method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void stopListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
- field public static final String ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED = "android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED";
- field public static final int MIRACAST_DISABLED = 0; // 0x0
- field public static final int MIRACAST_SINK = 2; // 0x2
- field public static final int MIRACAST_SOURCE = 1; // 0x1
- }
-
- public static interface WifiP2pManager.PersistentGroupInfoListener {
- method public void onPersistentGroupInfoAvailable(@NonNull android.net.wifi.p2p.WifiP2pGroupList);
- }
-
-}
-
-package android.net.wifi.rtt {
-
- public static final class RangingRequest.Builder {
- method public android.net.wifi.rtt.RangingRequest.Builder addResponder(@NonNull android.net.wifi.rtt.ResponderConfig);
- }
-
- public final class RangingResult implements android.os.Parcelable {
- method @NonNull public byte[] getLci();
- method @NonNull public byte[] getLcr();
- }
-
- public final class ResponderConfig implements android.os.Parcelable {
- ctor public ResponderConfig(@NonNull android.net.MacAddress, int, boolean, int, int, int, int, int);
- ctor public ResponderConfig(@NonNull android.net.wifi.aware.PeerHandle, int, boolean, int, int, int, int, int);
- method public int describeContents();
- method public static android.net.wifi.rtt.ResponderConfig fromScanResult(android.net.wifi.ScanResult);
- method public static android.net.wifi.rtt.ResponderConfig fromWifiAwarePeerHandleWithDefaults(android.net.wifi.aware.PeerHandle);
- method public static android.net.wifi.rtt.ResponderConfig fromWifiAwarePeerMacAddressWithDefaults(android.net.MacAddress);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3
- field public static final int CHANNEL_WIDTH_20MHZ = 0; // 0x0
- field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
- field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
- field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.rtt.ResponderConfig> CREATOR;
- field public static final int PREAMBLE_HE = 3; // 0x3
- field public static final int PREAMBLE_HT = 1; // 0x1
- field public static final int PREAMBLE_LEGACY = 0; // 0x0
- field public static final int PREAMBLE_VHT = 2; // 0x2
- field public static final int RESPONDER_AP = 0; // 0x0
- field public static final int RESPONDER_AWARE = 4; // 0x4
- field public static final int RESPONDER_P2P_CLIENT = 3; // 0x3
- field public static final int RESPONDER_P2P_GO = 2; // 0x2
- field public static final int RESPONDER_STA = 1; // 0x1
- field public final int centerFreq0;
- field public final int centerFreq1;
- field public final int channelWidth;
- field public final int frequency;
- field public final android.net.MacAddress macAddress;
- field public final android.net.wifi.aware.PeerHandle peerHandle;
- field public final int preamble;
- field public final int responderType;
- field public final boolean supports80211mc;
- }
-
- public final class ResponderLocation implements android.os.Parcelable {
- method public boolean getExtraInfoOnAssociationIndication();
- }
-
- public class WifiRttManager {
- method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE}) public void cancelRanging(@Nullable android.os.WorkSource);
- method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.ACCESS_WIFI_STATE}) public void startRanging(@Nullable android.os.WorkSource, @NonNull android.net.wifi.rtt.RangingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.rtt.RangingResultCallback);
- }
-
-}
-
-package android.nfc {
-
- public final class NfcAdapter {
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, String[]);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disableNdefPush();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
- method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
- field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
- }
-
- public static interface NfcAdapter.NfcUnlockHandler {
- method public boolean onUnlockAttempted(android.nfc.Tag);
- }
-
-}
-
-package android.os {
-
- public class BatteryManager {
- method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setChargingStateUpdateDelayMillis(int);
- field public static final String EXTRA_EVENTS = "android.os.extra.EVENTS";
- field public static final String EXTRA_EVENT_TIMESTAMP = "android.os.extra.EVENT_TIMESTAMP";
- }
-
- public final class BatterySaverPolicyConfig implements android.os.Parcelable {
- method public int describeContents();
- method public float getAdjustBrightnessFactor();
- method public boolean getAdvertiseIsEnabled();
- method public boolean getDeferFullBackup();
- method public boolean getDeferKeyValueBackup();
- method @NonNull public java.util.Map<java.lang.String,java.lang.String> getDeviceSpecificSettings();
- method public boolean getDisableAnimation();
- method public boolean getDisableAod();
- method public boolean getDisableLaunchBoost();
- method public boolean getDisableOptionalSensors();
- method public boolean getDisableSoundTrigger();
- method public boolean getDisableVibration();
- method public boolean getEnableAdjustBrightness();
- method public boolean getEnableDataSaver();
- method public boolean getEnableFirewall();
- method public boolean getEnableNightMode();
- method public boolean getEnableQuickDoze();
- method public boolean getForceAllAppsStandby();
- method public boolean getForceBackgroundCheck();
- method public int getLocationMode();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.os.BatterySaverPolicyConfig> CREATOR;
- }
-
- public static final class BatterySaverPolicyConfig.Builder {
- ctor public BatterySaverPolicyConfig.Builder();
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder addDeviceSpecificSetting(@NonNull String, @NonNull String);
- method @NonNull public android.os.BatterySaverPolicyConfig build();
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setAdjustBrightnessFactor(float);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setAdvertiseIsEnabled(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDeferFullBackup(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDeferKeyValueBackup(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableAnimation(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableAod(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableLaunchBoost(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableOptionalSensors(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableSoundTrigger(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableVibration(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableAdjustBrightness(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableDataSaver(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableFirewall(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableNightMode(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableQuickDoze(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setForceAllAppsStandby(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setForceBackgroundCheck(boolean);
- method @NonNull public android.os.BatterySaverPolicyConfig.Builder setLocationMode(int);
- }
-
- public final class BatteryStatsManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.CellularBatteryStats getCellularBatteryStats();
- method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.WifiBatteryStats getWifiBatteryStats();
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource);
- 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(@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);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStartedFromSource(@NonNull android.os.WorkSource);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStoppedFromSource(@NonNull android.os.WorkSource);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiState(int, @Nullable String);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiSupplicantStateChanged(int, boolean);
- field public static final int WIFI_STATE_OFF = 0; // 0x0
- field public static final int WIFI_STATE_OFF_SCANNING = 1; // 0x1
- field public static final int WIFI_STATE_ON_CONNECTED_P2P = 5; // 0x5
- field public static final int WIFI_STATE_ON_CONNECTED_STA = 4; // 0x4
- field public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6; // 0x6
- field public static final int WIFI_STATE_ON_DISCONNECTED = 3; // 0x3
- field public static final int WIFI_STATE_ON_NO_NETWORKS = 2; // 0x2
- field public static final int WIFI_STATE_SOFT_AP = 7; // 0x7
- field public static final int WIFI_SUPPL_STATE_ASSOCIATED = 7; // 0x7
- field public static final int WIFI_SUPPL_STATE_ASSOCIATING = 6; // 0x6
- field public static final int WIFI_SUPPL_STATE_AUTHENTICATING = 5; // 0x5
- field public static final int WIFI_SUPPL_STATE_COMPLETED = 10; // 0xa
- field public static final int WIFI_SUPPL_STATE_DISCONNECTED = 1; // 0x1
- field public static final int WIFI_SUPPL_STATE_DORMANT = 11; // 0xb
- field public static final int WIFI_SUPPL_STATE_FOUR_WAY_HANDSHAKE = 8; // 0x8
- field public static final int WIFI_SUPPL_STATE_GROUP_HANDSHAKE = 9; // 0x9
- field public static final int WIFI_SUPPL_STATE_INACTIVE = 3; // 0x3
- field public static final int WIFI_SUPPL_STATE_INTERFACE_DISABLED = 2; // 0x2
- field public static final int WIFI_SUPPL_STATE_INVALID = 0; // 0x0
- field public static final int WIFI_SUPPL_STATE_SCANNING = 4; // 0x4
- field public static final int WIFI_SUPPL_STATE_UNINITIALIZED = 12; // 0xc
- }
-
- public class Binder implements android.os.IBinder {
- method public int handleShellCommand(@NonNull android.os.ParcelFileDescriptor, @NonNull android.os.ParcelFileDescriptor, @NonNull android.os.ParcelFileDescriptor, @NonNull String[]);
- method public static void setProxyTransactListener(@Nullable android.os.Binder.ProxyTransactListener);
- }
-
- public static interface Binder.ProxyTransactListener {
- method public void onTransactEnded(@Nullable Object);
- method @Nullable public Object onTransactStarted(@NonNull android.os.IBinder, int);
- }
-
- public final class BugreportManager {
- method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
- method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
- method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
- }
-
- public abstract static class BugreportManager.BugreportCallback {
- ctor public BugreportManager.BugreportCallback();
- method public void onError(int);
- method public void onFinished();
- method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
- field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
- field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
- field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
- field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
- field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3
- }
-
- public final class BugreportParams {
- ctor public BugreportParams(int);
- method public int getMode();
- field public static final int BUGREPORT_MODE_FULL = 0; // 0x0
- field public static final int BUGREPORT_MODE_INTERACTIVE = 1; // 0x1
- field public static final int BUGREPORT_MODE_REMOTE = 2; // 0x2
- field public static final int BUGREPORT_MODE_TELEPHONY = 4; // 0x4
- field public static final int BUGREPORT_MODE_WEAR = 3; // 0x3
- field public static final int BUGREPORT_MODE_WIFI = 5; // 0x5
- }
-
- public static class Build.VERSION {
- field @NonNull public static final String PREVIEW_SDK_FINGERPRINT;
- }
-
- public final class ConfigUpdate {
- field public static final String ACTION_UPDATE_CARRIER_ID_DB = "android.os.action.UPDATE_CARRIER_ID_DB";
- field public static final String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
- field public static final String ACTION_UPDATE_CONVERSATION_ACTIONS = "android.intent.action.UPDATE_CONVERSATION_ACTIONS";
- field public static final String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
- field public static final String ACTION_UPDATE_EMERGENCY_NUMBER_DB = "android.os.action.UPDATE_EMERGENCY_NUMBER_DB";
- field public static final String ACTION_UPDATE_INTENT_FIREWALL = "android.intent.action.UPDATE_INTENT_FIREWALL";
- field public static final String ACTION_UPDATE_LANG_ID = "android.intent.action.UPDATE_LANG_ID";
- field public static final String ACTION_UPDATE_NETWORK_WATCHLIST = "android.intent.action.UPDATE_NETWORK_WATCHLIST";
- field public static final String ACTION_UPDATE_PINS = "android.intent.action.UPDATE_PINS";
- field public static final String ACTION_UPDATE_SMART_SELECTION = "android.intent.action.UPDATE_SMART_SELECTION";
- field public static final String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
- field public static final String EXTRA_REQUIRED_HASH = "android.os.extra.REQUIRED_HASH";
- field public static final String EXTRA_VERSION = "android.os.extra.VERSION";
- }
-
- public class DeviceIdleManager {
- method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void endIdle(@NonNull String);
- }
-
- public class Environment {
- method @NonNull public static java.util.Collection<java.io.File> getInternalMediaDirectories();
- method @NonNull public static java.io.File getOdmDirectory();
- method @NonNull public static java.io.File getOemDirectory();
- method @NonNull public static java.io.File getProductDirectory();
- method @Deprecated @NonNull public static java.io.File getProductServicesDirectory();
- method @NonNull public static java.io.File getSystemExtDirectory();
- method @NonNull public static java.io.File getVendorDirectory();
- }
-
- public class HidlMemory implements java.io.Closeable {
- ctor public HidlMemory(@NonNull String, @IntRange(from=0) long, @Nullable android.os.NativeHandle);
- method public void close() throws java.io.IOException;
- method @NonNull public android.os.HidlMemory dup() throws java.io.IOException;
- method protected void finalize();
- method @Nullable public android.os.NativeHandle getHandle();
- method @NonNull public String getName();
- method public long getSize();
- method @Nullable public android.os.NativeHandle releaseHandle();
- }
-
- public class HidlSupport {
- method public static boolean deepEquals(Object, Object);
- method public static int deepHashCode(Object);
- method public static int getPidIfSharable();
- method public static boolean interfacesEqual(android.os.IHwInterface, Object);
- }
-
- public abstract class HwBinder implements android.os.IHwBinder {
- ctor public HwBinder();
- method public static final void configureRpcThreadpool(long, boolean);
- method public static void enableInstrumentation();
- method public static final android.os.IHwBinder getService(String, String) throws java.util.NoSuchElementException, android.os.RemoteException;
- method public static final android.os.IHwBinder getService(String, String, boolean) throws java.util.NoSuchElementException, android.os.RemoteException;
- method public static final void joinRpcThreadpool();
- method public abstract void onTransact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
- method public final void registerService(String) throws android.os.RemoteException;
- method public final void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
- }
-
- public class HwBlob {
- ctor public HwBlob(int);
- method public final void copyToBoolArray(long, boolean[], int);
- method public final void copyToDoubleArray(long, double[], int);
- method public final void copyToFloatArray(long, float[], int);
- method public final void copyToInt16Array(long, short[], int);
- method public final void copyToInt32Array(long, int[], int);
- method public final void copyToInt64Array(long, long[], int);
- method public final void copyToInt8Array(long, byte[], int);
- method public final boolean getBool(long);
- method public final double getDouble(long);
- method public final long getFieldHandle(long);
- method public final float getFloat(long);
- method public final short getInt16(long);
- method public final int getInt32(long);
- method public final long getInt64(long);
- method public final byte getInt8(long);
- method public final String getString(long);
- method public final long handle();
- method public final void putBlob(long, android.os.HwBlob);
- method public final void putBool(long, boolean);
- method public final void putBoolArray(long, boolean[]);
- method public final void putDouble(long, double);
- method public final void putDoubleArray(long, double[]);
- method public final void putFloat(long, float);
- method public final void putFloatArray(long, float[]);
- method public final void putHidlMemory(long, @NonNull android.os.HidlMemory);
- method public final void putInt16(long, short);
- method public final void putInt16Array(long, short[]);
- method public final void putInt32(long, int);
- method public final void putInt32Array(long, int[]);
- method public final void putInt64(long, long);
- method public final void putInt64Array(long, long[]);
- method public final void putInt8(long, byte);
- method public final void putInt8Array(long, byte[]);
- method public final void putNativeHandle(long, @Nullable android.os.NativeHandle);
- method public final void putString(long, String);
- method public static Boolean[] wrapArray(@NonNull boolean[]);
- method public static Long[] wrapArray(@NonNull long[]);
- method public static Byte[] wrapArray(@NonNull byte[]);
- method public static Short[] wrapArray(@NonNull short[]);
- method public static Integer[] wrapArray(@NonNull int[]);
- method public static Float[] wrapArray(@NonNull float[]);
- method public static Double[] wrapArray(@NonNull double[]);
- }
-
- public class HwParcel {
- ctor public HwParcel();
- method public final void enforceInterface(String);
- method public final boolean readBool();
- method public final java.util.ArrayList<java.lang.Boolean> readBoolVector();
- method public final android.os.HwBlob readBuffer(long);
- method public final double readDouble();
- method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
- method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
- method @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long);
- method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
- method public final float readFloat();
- method public final java.util.ArrayList<java.lang.Float> readFloatVector();
- method @NonNull public final android.os.HidlMemory readHidlMemory();
- method public final short readInt16();
- method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
- method public final int readInt32();
- method public final java.util.ArrayList<java.lang.Integer> readInt32Vector();
- method public final long readInt64();
- method public final java.util.ArrayList<java.lang.Long> readInt64Vector();
- method public final byte readInt8();
- method public final java.util.ArrayList<java.lang.Byte> readInt8Vector();
- method @Nullable public final android.os.NativeHandle readNativeHandle();
- method @NonNull public final java.util.ArrayList<android.os.NativeHandle> readNativeHandleVector();
- method public final String readString();
- method public final java.util.ArrayList<java.lang.String> readStringVector();
- method public final android.os.IHwBinder readStrongBinder();
- method public final void release();
- method public final void releaseTemporaryStorage();
- method public final void send();
- method public final void verifySuccess();
- method public final void writeBool(boolean);
- method public final void writeBoolVector(java.util.ArrayList<java.lang.Boolean>);
- method public final void writeBuffer(android.os.HwBlob);
- method public final void writeDouble(double);
- method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
- method public final void writeFloat(float);
- method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
- method public final void writeHidlMemory(@NonNull android.os.HidlMemory);
- method public final void writeInt16(short);
- method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
- method public final void writeInt32(int);
- method public final void writeInt32Vector(java.util.ArrayList<java.lang.Integer>);
- method public final void writeInt64(long);
- method public final void writeInt64Vector(java.util.ArrayList<java.lang.Long>);
- method public final void writeInt8(byte);
- method public final void writeInt8Vector(java.util.ArrayList<java.lang.Byte>);
- method public final void writeInterfaceToken(String);
- method public final void writeNativeHandle(@Nullable android.os.NativeHandle);
- method public final void writeNativeHandleVector(@NonNull java.util.ArrayList<android.os.NativeHandle>);
- method public final void writeStatus(int);
- method public final void writeString(String);
- method public final void writeStringVector(java.util.ArrayList<java.lang.String>);
- method public final void writeStrongBinder(android.os.IHwBinder);
- field public static final int STATUS_SUCCESS = 0; // 0x0
- }
-
- public interface IHwBinder {
- method public boolean linkToDeath(android.os.IHwBinder.DeathRecipient, long);
- method public android.os.IHwInterface queryLocalInterface(String);
- method public void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
- method public boolean unlinkToDeath(android.os.IHwBinder.DeathRecipient);
- }
-
- public static interface IHwBinder.DeathRecipient {
- method public void serviceDied(long);
- }
-
- public interface IHwInterface {
- method public android.os.IHwBinder asBinder();
- }
-
- public class IncidentManager {
- method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public void approveReport(android.net.Uri);
- method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void cancelAuthorization(android.os.IncidentManager.AuthListener);
- method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void deleteIncidentReports(android.net.Uri);
- method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public void denyReport(android.net.Uri);
- method @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public android.os.IncidentManager.IncidentReport getIncidentReport(android.net.Uri);
- method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public java.util.List<android.net.Uri> getIncidentReportList(String);
- method @RequiresPermission(android.Manifest.permission.APPROVE_INCIDENT_REPORTS) public java.util.List<android.os.IncidentManager.PendingReport> getPendingReports();
- method public void registerSection(int, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.os.IncidentManager.DumpCallback);
- method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void reportIncident(android.os.IncidentReportArgs);
- method @RequiresPermission("android.permission.REQUEST_INCIDENT_REPORT_APPROVAL") public void requestAuthorization(int, String, int, android.os.IncidentManager.AuthListener);
- method public void unregisterSection(int);
- field public static final int FLAG_CONFIRMATION_DIALOG = 1; // 0x1
- field public static final int PRIVACY_POLICY_AUTO = 200; // 0xc8
- field public static final int PRIVACY_POLICY_EXPLICIT = 100; // 0x64
- field public static final int PRIVACY_POLICY_LOCAL = 0; // 0x0
- }
-
- public static class IncidentManager.AuthListener {
- ctor public IncidentManager.AuthListener();
- method public void onReportApproved();
- method public void onReportDenied();
- }
-
- public static class IncidentManager.DumpCallback {
- ctor public IncidentManager.DumpCallback();
- method public void onDumpSection(int, @NonNull java.io.OutputStream);
- }
-
- public static class IncidentManager.IncidentReport implements java.io.Closeable android.os.Parcelable {
- ctor public IncidentManager.IncidentReport(android.os.Parcel);
- method public void close();
- method public int describeContents();
- method public java.io.InputStream getInputStream() throws java.io.IOException;
- method public long getPrivacyPolicy();
- method public long getTimestamp();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.os.IncidentManager.IncidentReport> CREATOR;
- }
-
- public static class IncidentManager.PendingReport {
- ctor public IncidentManager.PendingReport(@NonNull android.net.Uri);
- method public int getFlags();
- method @NonNull public String getRequestingPackage();
- method public long getTimestamp();
- method @NonNull public android.net.Uri getUri();
- }
-
- public final class IncidentReportArgs implements android.os.Parcelable {
- ctor public IncidentReportArgs();
- ctor public IncidentReportArgs(android.os.Parcel);
- method public void addHeader(byte[]);
- method public void addSection(int);
- method public boolean containsSection(int);
- method public int describeContents();
- method public boolean isAll();
- method public void readFromParcel(android.os.Parcel);
- method public int sectionCount();
- method public void setAll(boolean);
- method public void setPrivacyPolicy(int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
- }
-
- public final class NativeHandle implements java.io.Closeable {
- ctor public NativeHandle();
- ctor public NativeHandle(@NonNull java.io.FileDescriptor, boolean);
- ctor public NativeHandle(@NonNull java.io.FileDescriptor[], @NonNull int[], boolean);
- method public void close() throws java.io.IOException;
- method @NonNull public android.os.NativeHandle dup() throws java.io.IOException;
- method @NonNull public java.io.FileDescriptor getFileDescriptor();
- method @NonNull public java.io.FileDescriptor[] getFileDescriptors();
- method @NonNull public int[] getInts();
- method public boolean hasSingleFileDescriptor();
- }
-
- public interface Parcelable {
- field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0
- field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1
- }
-
- public final class ParcelableHolder implements android.os.Parcelable {
- ctor public ParcelableHolder(int);
- method public int describeContents();
- method @Nullable public <T extends android.os.Parcelable> T getParcelable(@NonNull Class<T>);
- method public int getStability();
- method public void readFromParcel(@NonNull android.os.Parcel);
- method public boolean setParcelable(@Nullable android.os.Parcelable);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.os.ParcelableHolder> CREATOR;
- }
-
- 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();
- method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public int getPowerSaveModeTrigger();
- method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplayAvailable();
- method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressed();
- method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressedForToken(@NonNull String);
- method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSaveEnabled(boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig);
- method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean);
- method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSaveHint(boolean, int);
- method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void suppressAmbientDisplay(@NonNull String, boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.USER_ACTIVITY}) public void userActivity(long, int, int);
- field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
- field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
- field public static final String REBOOT_USERSPACE = "userspace";
- field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
- field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
- field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
- field public static final int USER_ACTIVITY_EVENT_TOUCH = 2; // 0x2
- field public static final int USER_ACTIVITY_FLAG_INDIRECT = 2; // 0x2
- field public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1; // 0x1
- }
-
- public class PowerWhitelistManager {
- method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
- method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void removeFromWhitelist(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long);
- method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String);
- field public static final int EVENT_MMS = 2; // 0x2
- field public static final int EVENT_SMS = 1; // 0x1
- field public static final int EVENT_UNSPECIFIED = 0; // 0x0
- }
-
- public class RecoverySystem {
- method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void cancelScheduledUpdate(android.content.Context) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void clearPrepareForUnattendedUpdate(@NonNull android.content.Context) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void installPackage(android.content.Context, java.io.File, boolean) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void prepareForUnattendedUpdate(@NonNull android.content.Context, @NonNull String, @Nullable android.content.IntentSender) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener, android.os.Handler) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void rebootAndApply(@NonNull android.content.Context, @NonNull String, @NonNull String) throws java.io.IOException;
- method @RequiresPermission(allOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void rebootWipeAb(android.content.Context, java.io.File, String) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
- method public static boolean verifyPackageCompatibility(java.io.File) throws java.io.IOException;
- }
-
- public final class RemoteCallback implements android.os.Parcelable {
- ctor public RemoteCallback(android.os.RemoteCallback.OnResultListener);
- ctor public RemoteCallback(@NonNull android.os.RemoteCallback.OnResultListener, @Nullable android.os.Handler);
- method public int describeContents();
- method public void sendResult(@Nullable android.os.Bundle);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.os.RemoteCallback> CREATOR;
- }
-
- public static interface RemoteCallback.OnResultListener {
- method public void onResult(@Nullable android.os.Bundle);
- }
-
- public class ServiceSpecificException extends java.lang.RuntimeException {
- ctor public ServiceSpecificException(int, @Nullable String);
- ctor public ServiceSpecificException(int);
- field public final int errorCode;
- }
-
- public final class StatsDimensionsValue implements android.os.Parcelable {
- method public int describeContents();
- method public boolean getBooleanValue();
- method public int getField();
- method public float getFloatValue();
- method public int getIntValue();
- method public long getLongValue();
- method public String getStringValue();
- method public java.util.List<android.os.StatsDimensionsValue> getTupleValueList();
- method public int getValueType();
- method public boolean isValueType(int);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int BOOLEAN_VALUE_TYPE = 5; // 0x5
- field @NonNull public static final android.os.Parcelable.Creator<android.os.StatsDimensionsValue> CREATOR;
- field public static final int FLOAT_VALUE_TYPE = 6; // 0x6
- field public static final int INT_VALUE_TYPE = 3; // 0x3
- field public static final int LONG_VALUE_TYPE = 4; // 0x4
- field public static final int STRING_VALUE_TYPE = 2; // 0x2
- field public static final int TUPLE_VALUE_TYPE = 7; // 0x7
- }
-
- public class SystemConfigManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
- }
-
- public class SystemProperties {
- method @NonNull public static String get(@NonNull String);
- method @NonNull public static String get(@NonNull String, @Nullable String);
- method public static boolean getBoolean(@NonNull String, boolean);
- method public static int getInt(@NonNull String, int);
- method public static long getLong(@NonNull String, long);
- }
-
- public class SystemUpdateManager {
- method @RequiresPermission(anyOf={android.Manifest.permission.READ_SYSTEM_UPDATE_INFO, android.Manifest.permission.RECOVERY}) public android.os.Bundle retrieveSystemUpdateInfo();
- method @RequiresPermission(android.Manifest.permission.RECOVERY) public void updateSystemUpdateInfo(android.os.PersistableBundle);
- field public static final String KEY_IS_SECURITY_UPDATE = "is_security_update";
- field public static final String KEY_STATUS = "status";
- field public static final String KEY_TARGET_BUILD_FINGERPRINT = "target_build_fingerprint";
- field public static final String KEY_TARGET_SECURITY_PATCH_LEVEL = "target_security_patch_level";
- field public static final String KEY_TITLE = "title";
- field public static final int STATUS_IDLE = 1; // 0x1
- field public static final int STATUS_IN_PROGRESS = 3; // 0x3
- field public static final int STATUS_UNKNOWN = 0; // 0x0
- field public static final int STATUS_WAITING_DOWNLOAD = 2; // 0x2
- field public static final int STATUS_WAITING_INSTALL = 4; // 0x4
- field public static final int STATUS_WAITING_REBOOT = 5; // 0x5
- }
-
- public class UpdateEngine {
- ctor public UpdateEngine();
- method @NonNull @WorkerThread public android.os.UpdateEngine.AllocateSpaceResult allocateSpace(@NonNull String, @NonNull String[]);
- method public void applyPayload(String, long, long, String[]);
- method public void applyPayload(@NonNull android.content.res.AssetFileDescriptor, @NonNull String[]);
- method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler);
- method public boolean bind(android.os.UpdateEngineCallback);
- method public void cancel();
- method @WorkerThread public int cleanupAppliedPayload();
- method public void resetStatus();
- method public void resume();
- method public void suspend();
- method public boolean unbind();
- method public boolean verifyPayloadMetadata(String);
- }
-
- public static final class UpdateEngine.AllocateSpaceResult {
- method public int getErrorCode();
- method public long getFreeSpaceRequired();
- }
-
- public static final class UpdateEngine.ErrorCodeConstants {
- ctor public UpdateEngine.ErrorCodeConstants();
- field public static final int DEVICE_CORRUPTED = 61; // 0x3d
- field public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12; // 0xc
- field public static final int DOWNLOAD_TRANSFER_ERROR = 9; // 0x9
- field public static final int ERROR = 1; // 0x1
- field public static final int FILESYSTEM_COPIER_ERROR = 4; // 0x4
- field public static final int INSTALL_DEVICE_OPEN_ERROR = 7; // 0x7
- field public static final int KERNEL_DEVICE_OPEN_ERROR = 8; // 0x8
- field public static final int NOT_ENOUGH_SPACE = 60; // 0x3c
- field public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; // 0xa
- field public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6; // 0x6
- field public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; // 0xb
- field public static final int PAYLOAD_TIMESTAMP_ERROR = 51; // 0x33
- field public static final int POST_INSTALL_RUNNER_ERROR = 5; // 0x5
- field public static final int SUCCESS = 0; // 0x0
- field public static final int UPDATED_BUT_NOT_ACTIVE = 52; // 0x34
- }
-
- public static final class UpdateEngine.UpdateStatusConstants {
- ctor public UpdateEngine.UpdateStatusConstants();
- field public static final int ATTEMPTING_ROLLBACK = 8; // 0x8
- field public static final int CHECKING_FOR_UPDATE = 1; // 0x1
- field public static final int DISABLED = 9; // 0x9
- field public static final int DOWNLOADING = 3; // 0x3
- field public static final int FINALIZING = 5; // 0x5
- field public static final int IDLE = 0; // 0x0
- field public static final int REPORTING_ERROR_EVENT = 7; // 0x7
- field public static final int UPDATED_NEED_REBOOT = 6; // 0x6
- field public static final int UPDATE_AVAILABLE = 2; // 0x2
- field public static final int VERIFYING = 4; // 0x4
- }
-
- public abstract class UpdateEngineCallback {
- ctor public UpdateEngineCallback();
- method public abstract void onPayloadApplicationComplete(int);
- method public abstract void onStatusUpdate(int, float);
- }
-
- public final class UserHandle implements android.os.Parcelable {
- method @NonNull public static String formatUid(int);
- method public static int getAppId(int);
- method public int getIdentifier();
- method @Deprecated public boolean isOwner();
- method public boolean isSystem();
- method public static int myUserId();
- method public static android.os.UserHandle of(int);
- field @NonNull public static final android.os.UserHandle ALL;
- field @NonNull public static final android.os.UserHandle CURRENT;
- field @NonNull public static final android.os.UserHandle SYSTEM;
- }
-
- public class UserManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearSeedAccountData();
- method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle createProfile(@NonNull String, @NonNull String, @NonNull java.util.Set<java.lang.String>) throws android.os.UserManager.UserOperationException;
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getAllProfiles();
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public java.util.List<android.os.UserHandle> getEnabledProfiles();
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountType();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserHandle> getUserHandles(boolean);
- method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon();
- method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
- method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public int getUserSwitchability();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean hasRestrictedProfiles();
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isAdminUser();
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isGuestUser();
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isPrimaryUser();
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isProfile();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile();
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle);
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public boolean isUserNameSet();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUserOfType(@NonNull String);
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isUserUnlockingOrUnlocked(@NonNull android.os.UserHandle);
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean removeUser(@NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap) throws android.os.UserManager.UserOperationException;
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String);
- field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
- field @Deprecated public static final String DISALLOW_OEM_UNLOCK = "no_oem_unlock";
- field public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background";
- field public static final int RESTRICTION_NOT_SET = 0; // 0x0
- field public static final int RESTRICTION_SOURCE_DEVICE_OWNER = 2; // 0x2
- field public static final int RESTRICTION_SOURCE_PROFILE_OWNER = 4; // 0x4
- field public static final int RESTRICTION_SOURCE_SYSTEM = 1; // 0x1
- field public static final int SWITCHABILITY_STATUS_OK = 0; // 0x0
- field public static final int SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED = 4; // 0x4
- field public static final int SWITCHABILITY_STATUS_USER_IN_CALL = 1; // 0x1
- field public static final int SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED = 2; // 0x2
- field public static final String USER_TYPE_FULL_SECONDARY = "android.os.usertype.full.SECONDARY";
- field public static final String USER_TYPE_FULL_SYSTEM = "android.os.usertype.full.SYSTEM";
- field public static final String USER_TYPE_PROFILE_MANAGED = "android.os.usertype.profile.MANAGED";
- field public static final String USER_TYPE_SYSTEM_HEADLESS = "android.os.usertype.system.HEADLESS";
- }
-
- public static final class UserManager.EnforcingUser implements android.os.Parcelable {
- method public int describeContents();
- method public android.os.UserHandle getUserHandle();
- method @android.os.UserManager.UserRestrictionSource public int getUserRestrictionSource();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.os.UserManager.EnforcingUser> CREATOR;
- }
-
- @IntDef(flag=true, prefix={"RESTRICTION_"}, value={android.os.UserManager.RESTRICTION_NOT_SET, android.os.UserManager.RESTRICTION_SOURCE_SYSTEM, android.os.UserManager.RESTRICTION_SOURCE_DEVICE_OWNER, android.os.UserManager.RESTRICTION_SOURCE_PROFILE_OWNER}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface UserManager.UserRestrictionSource {
- }
-
- public abstract class Vibrator {
- method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void addVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener);
- method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void addVibratorStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.Vibrator.OnVibratorStateChangedListener);
- method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public boolean isVibrating();
- method @RequiresPermission(android.Manifest.permission.ACCESS_VIBRATOR_STATE) public void removeVibratorStateListener(@NonNull android.os.Vibrator.OnVibratorStateChangedListener);
- }
-
- public static interface Vibrator.OnVibratorStateChangedListener {
- method public void onVibratorStateChanged(boolean);
- }
-
- public class WorkSource implements android.os.Parcelable {
- ctor public WorkSource(int);
- ctor public WorkSource(int, @NonNull String);
- method public android.os.WorkSource.WorkChain createWorkChain();
- method @Nullable public String getPackageName(int);
- method public int getUid(int);
- method @Nullable public java.util.List<android.os.WorkSource.WorkChain> getWorkChains();
- method public boolean isEmpty();
- method public int size();
- method @NonNull public android.os.WorkSource withoutNames();
- }
-
- public static final class WorkSource.WorkChain implements android.os.Parcelable {
- ctor public WorkSource.WorkChain();
- method public android.os.WorkSource.WorkChain addNode(int, @Nullable String);
- method public int describeContents();
- method public String getAttributionTag();
- method public int getAttributionUid();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.os.WorkSource.WorkChain> CREATOR;
- }
-
-}
-
-package android.os.connectivity {
-
- public final class CellularBatteryStats implements android.os.Parcelable {
- method public int describeContents();
- method public long getEnergyConsumedMaMillis();
- method public long getIdleTimeMillis();
- method public long getKernelActiveTimeMillis();
- method public long getLoggingDurationMillis();
- method public long getMonitoredRailChargeConsumedMaMillis();
- method public long getNumBytesRx();
- method public long getNumBytesTx();
- method public long getNumPacketsRx();
- method public long getNumPacketsTx();
- method public long getRxTimeMillis();
- method public long getSleepTimeMillis();
- method @NonNull public long getTimeInRatMicros(int);
- method @NonNull public long getTimeInRxSignalStrengthLevelMicros(@IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) int);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.os.connectivity.CellularBatteryStats> CREATOR;
- }
-
- public final class WifiActivityEnergyInfo implements android.os.Parcelable {
- ctor public WifiActivityEnergyInfo(long, int, @IntRange(from=0) long, @IntRange(from=0) long, @IntRange(from=0) long, @IntRange(from=0) long);
- method public int describeContents();
- method @IntRange(from=0) public long getControllerEnergyUsedMicroJoules();
- method @IntRange(from=0) public long getControllerIdleDurationMillis();
- method @IntRange(from=0) public long getControllerRxDurationMillis();
- method @IntRange(from=0) public long getControllerScanDurationMillis();
- method @IntRange(from=0) public long getControllerTxDurationMillis();
- method public int getStackState();
- method public long getTimeSinceBootMillis();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.os.connectivity.WifiActivityEnergyInfo> CREATOR;
- field public static final int STACK_STATE_INVALID = 0; // 0x0
- field public static final int STACK_STATE_STATE_ACTIVE = 1; // 0x1
- field public static final int STACK_STATE_STATE_IDLE = 3; // 0x3
- field public static final int STACK_STATE_STATE_SCANNING = 2; // 0x2
- }
-
- public final class WifiBatteryStats implements android.os.Parcelable {
- method public int describeContents();
- method public long getAppScanRequestCount();
- method public long getEnergyConsumedMaMillis();
- method public long getIdleTimeMillis();
- method public long getKernelActiveTimeMillis();
- method public long getLoggingDurationMillis();
- method public long getMonitoredRailChargeConsumedMaMillis();
- method public long getNumBytesRx();
- method public long getNumBytesTx();
- method public long getNumPacketsRx();
- method public long getNumPacketsTx();
- method public long getRxTimeMillis();
- method public long getScanTimeMillis();
- method public long getSleepTimeMillis();
- method public long getTxTimeMillis();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.os.connectivity.WifiBatteryStats> CREATOR;
- }
-
-}
-
-package android.os.ext {
-
- public class SdkExtensions {
- method public static int getExtensionVersion(int);
- }
-
-}
-
-package android.os.image {
-
- public class DynamicSystemClient {
- ctor public DynamicSystemClient(@NonNull android.content.Context);
- method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void bind();
- method public void setOnStatusChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.image.DynamicSystemClient.OnStatusChangedListener);
- method public void setOnStatusChangedListener(@NonNull android.os.image.DynamicSystemClient.OnStatusChangedListener);
- method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void start(@NonNull android.net.Uri, long);
- method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void start(@NonNull android.net.Uri, long, long);
- method @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM) public void unbind();
- field public static final int CAUSE_ERROR_EXCEPTION = 6; // 0x6
- field public static final int CAUSE_ERROR_INVALID_URL = 4; // 0x4
- field public static final int CAUSE_ERROR_IO = 3; // 0x3
- field public static final int CAUSE_ERROR_IPC = 5; // 0x5
- field public static final int CAUSE_INSTALL_CANCELLED = 2; // 0x2
- field public static final int CAUSE_INSTALL_COMPLETED = 1; // 0x1
- field public static final int CAUSE_NOT_SPECIFIED = 0; // 0x0
- field public static final int STATUS_IN_PROGRESS = 2; // 0x2
- field public static final int STATUS_IN_USE = 4; // 0x4
- field public static final int STATUS_NOT_STARTED = 1; // 0x1
- field public static final int STATUS_READY = 3; // 0x3
- field public static final int STATUS_UNKNOWN = 0; // 0x0
- }
-
- public static interface DynamicSystemClient.OnStatusChangedListener {
- method public void onStatusChanged(int, int, long, @Nullable Throwable);
- }
-
-}
-
-package android.os.storage {
-
- public class StorageManager {
- method @WorkerThread public void allocateBytes(@NonNull java.util.UUID, long, @RequiresPermission int) throws java.io.IOException;
- method @WorkerThread public void allocateBytes(java.io.FileDescriptor, long, @RequiresPermission int) throws java.io.IOException;
- method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID, @RequiresPermission int) throws java.io.IOException;
- method public static boolean hasIsolatedStorage();
- method public void updateExternalStorageFileQuotaType(@NonNull java.io.File, int) throws java.io.IOException;
- field @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
- field public static final int QUOTA_TYPE_MEDIA_AUDIO = 2; // 0x2
- field public static final int QUOTA_TYPE_MEDIA_IMAGE = 1; // 0x1
- field public static final int QUOTA_TYPE_MEDIA_NONE = 0; // 0x0
- field public static final int QUOTA_TYPE_MEDIA_VIDEO = 3; // 0x3
- }
-
- public final class StorageVolume implements android.os.Parcelable {
- method @NonNull public String getId();
- }
-
-}
-
-package android.permission {
-
- public final class PermissionControllerManager {
- method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>);
- method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle);
- field public static final int COUNT_ONLY_WHEN_GRANTED = 1; // 0x1
- field public static final int COUNT_WHEN_SYSTEM = 2; // 0x2
- field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2
- field public static final int REASON_MALWARE = 1; // 0x1
- }
-
- public abstract static class PermissionControllerManager.OnRevokeRuntimePermissionsCallback {
- ctor public PermissionControllerManager.OnRevokeRuntimePermissionsCallback();
- method public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>);
- }
-
- public abstract class PermissionControllerService extends android.app.Service {
- ctor public PermissionControllerService();
- method @BinderThread public void onApplyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @NonNull public final android.os.IBinder onBind(android.content.Intent);
- method @BinderThread public abstract void onCountPermissionApps(@NonNull java.util.List<java.lang.String>, int, @NonNull java.util.function.IntConsumer);
- method @BinderThread public abstract void onGetAppPermissions(@NonNull String, @NonNull java.util.function.Consumer<java.util.List<android.permission.RuntimePermissionPresentationInfo>>);
- method @BinderThread public abstract void onGetPermissionUsages(boolean, long, @NonNull java.util.function.Consumer<java.util.List<android.permission.RuntimePermissionUsageInfo>>);
- method @BinderThread public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream, @NonNull Runnable);
- method @BinderThread public abstract void onGrantOrUpgradeDefaultRuntimePermissions(@NonNull Runnable);
- method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String);
- method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
- method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
- method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
- method @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
- method @BinderThread public void onUpdateUserSensitivePermissionFlags(int, @NonNull java.util.concurrent.Executor, @NonNull Runnable);
- method @BinderThread public void onUpdateUserSensitivePermissionFlags(int, @NonNull Runnable);
- field public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
- }
-
- public final class PermissionManager {
- method public int checkDeviceIdentifierAccess(@Nullable String, @Nullable String, @Nullable String, int, int);
- method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionGrantedPackages();
- method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set<java.lang.String> getAutoRevokeExemptionRequestedPackages();
- method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
- method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
- method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String);
- }
-
- public static final class PermissionManager.SplitPermissionInfo {
- method @NonNull public java.util.List<java.lang.String> getNewPermissions();
- method @NonNull public String getSplitPermission();
- method public int getTargetSdk();
- }
-
- public final class RuntimePermissionPresentationInfo implements android.os.Parcelable {
- ctor public RuntimePermissionPresentationInfo(@NonNull CharSequence, boolean, boolean);
- method public int describeContents();
- method @NonNull public CharSequence getLabel();
- method public boolean isGranted();
- method public boolean isStandard();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionPresentationInfo> CREATOR;
- }
-
- public final class RuntimePermissionUsageInfo implements android.os.Parcelable {
- ctor public RuntimePermissionUsageInfo(@NonNull String, int);
- method public int describeContents();
- method public int getAppAccessCount();
- method @NonNull public String getName();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionUsageInfo> CREATOR;
- }
-
-}
-
-package android.permissionpresenterservice {
-
- @Deprecated public abstract class RuntimePermissionPresenterService extends android.app.Service {
- ctor @Deprecated public RuntimePermissionPresenterService();
- method @Deprecated public final void attachBaseContext(android.content.Context);
- method @Deprecated public final android.os.IBinder onBind(android.content.Intent);
- method @Deprecated public abstract java.util.List<android.content.pm.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(@NonNull String);
- field @Deprecated public static final String SERVICE_INTERFACE = "android.permissionpresenterservice.RuntimePermissionPresenterService";
- }
-
-}
-
-package android.preference {
-
- @Deprecated public class PreferenceManager {
- method @Deprecated public boolean isStorageCredentialProtected();
- method @Deprecated public void setStorageCredentialProtected();
- }
-
-}
-
-package android.print {
-
- public final class PrintManager {
- method @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS) public void addPrintServiceRecommendationsChangeListener(@NonNull android.print.PrintManager.PrintServiceRecommendationsChangeListener, @Nullable android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICES) public void addPrintServicesChangeListener(@NonNull android.print.PrintManager.PrintServicesChangeListener, @Nullable android.os.Handler);
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS) public java.util.List<android.printservice.recommendation.RecommendationInfo> getPrintServiceRecommendations();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICES) public java.util.List<android.printservice.PrintServiceInfo> getPrintServices(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS) public void removePrintServiceRecommendationsChangeListener(@NonNull android.print.PrintManager.PrintServiceRecommendationsChangeListener);
- method @RequiresPermission(android.Manifest.permission.READ_PRINT_SERVICES) public void removePrintServicesChangeListener(@NonNull android.print.PrintManager.PrintServicesChangeListener);
- field public static final int ENABLED_SERVICES = 1; // 0x1
- }
-
- public static interface PrintManager.PrintServiceRecommendationsChangeListener {
- method public void onPrintServiceRecommendationsChanged();
- }
-
- public static interface PrintManager.PrintServicesChangeListener {
- method public void onPrintServicesChanged();
- }
-
-}
-
-package android.printservice {
-
- public final class PrintServiceInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.content.ComponentName getComponentName();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.printservice.PrintServiceInfo> CREATOR;
- }
-
-}
-
-package android.printservice.recommendation {
-
- public final class RecommendationInfo implements android.os.Parcelable {
- ctor public RecommendationInfo(@NonNull CharSequence, @NonNull CharSequence, @NonNull java.util.List<java.net.InetAddress>, boolean);
- ctor @Deprecated public RecommendationInfo(@NonNull CharSequence, @NonNull CharSequence, @IntRange(from=0) int, boolean);
- method public int describeContents();
- method @NonNull public java.util.List<java.net.InetAddress> getDiscoveredPrinters();
- method public CharSequence getName();
- method public int getNumDiscoveredPrinters();
- method public CharSequence getPackageName();
- method public boolean recommendsMultiVendorService();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.printservice.recommendation.RecommendationInfo> CREATOR;
- }
-
- public abstract class RecommendationService extends android.app.Service {
- ctor public RecommendationService();
- method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract void onConnected();
- method public abstract void onDisconnected();
- method public final void updateRecommendations(@Nullable java.util.List<android.printservice.recommendation.RecommendationInfo>);
- field public static final String SERVICE_INTERFACE = "android.printservice.recommendation.RecommendationService";
- }
-
-}
-
-package android.provider {
-
- @Deprecated public static final class ContactsContract.MetadataSync implements android.provider.BaseColumns android.provider.ContactsContract.MetadataSyncColumns {
- field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata";
- field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata";
- field @Deprecated public static final android.net.Uri CONTENT_URI;
- field @Deprecated public static final String METADATA_AUTHORITY = "com.android.contacts.metadata";
- field @Deprecated public static final android.net.Uri METADATA_AUTHORITY_URI;
- }
-
- @Deprecated protected static interface ContactsContract.MetadataSyncColumns {
- field @Deprecated public static final String ACCOUNT_NAME = "account_name";
- field @Deprecated public static final String ACCOUNT_TYPE = "account_type";
- field @Deprecated public static final String DATA = "data";
- field @Deprecated public static final String DATA_SET = "data_set";
- field @Deprecated public static final String DELETED = "deleted";
- field @Deprecated public static final String RAW_CONTACT_BACKUP_ID = "raw_contact_backup_id";
- }
-
- @Deprecated public static final class ContactsContract.MetadataSyncState implements android.provider.BaseColumns android.provider.ContactsContract.MetadataSyncStateColumns {
- field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata_sync_state";
- field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata_sync_state";
- field @Deprecated public static final android.net.Uri CONTENT_URI;
- }
-
- @Deprecated protected static interface ContactsContract.MetadataSyncStateColumns {
- field @Deprecated public static final String ACCOUNT_NAME = "account_name";
- field @Deprecated public static final String ACCOUNT_TYPE = "account_type";
- field @Deprecated public static final String DATA_SET = "data_set";
- field @Deprecated public static final String STATE = "state";
- }
-
- public final class DeviceConfig {
- method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
- method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(@NonNull String, @NonNull String, boolean);
- method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(@NonNull String, @NonNull String, float);
- method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static int getInt(@NonNull String, @NonNull String, int);
- method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static long getLong(@NonNull String, @NonNull String, long);
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static android.provider.DeviceConfig.Properties getProperties(@NonNull String, @NonNull java.lang.String...);
- method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(@NonNull String, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(@NonNull String, @NonNull String, @Nullable String);
- method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
- method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
- method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperties(@NonNull android.provider.DeviceConfig.Properties) throws android.provider.DeviceConfig.BadConfigException;
- method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
- field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
- field public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = "activity_manager_native_boot";
- field public static final String NAMESPACE_APP_COMPAT = "app_compat";
- 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_BLUETOOTH = "bluetooth";
- 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";
- field public static final String NAMESPACE_DISPLAY_MANAGER = "display_manager";
- field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
- field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
- field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
- field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
- field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
- field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
- field public static final String NAMESPACE_PERMISSIONS = "permissions";
- field public static final String NAMESPACE_PRIVACY = "privacy";
- field public static final String NAMESPACE_PROFCOLLECT_NATIVE_BOOT = "profcollect_native_boot";
- field public static final String NAMESPACE_ROLLBACK = "rollback";
- field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
- field public static final String NAMESPACE_RUNTIME = "runtime";
- field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
- field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
- field public static final String NAMESPACE_SCHEDULER = "scheduler";
- field @Deprecated public static final String NAMESPACE_STORAGE = "storage";
- field public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
- field public static final String NAMESPACE_SYSTEMUI = "systemui";
- field public static final String NAMESPACE_TELEPHONY = "telephony";
- field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
- field public static final String NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT = "window_manager_native_boot";
- }
-
- public static class DeviceConfig.BadConfigException extends java.lang.Exception {
- ctor public DeviceConfig.BadConfigException();
- }
-
- public static interface DeviceConfig.OnPropertiesChangedListener {
- method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
- }
-
- public static class DeviceConfig.Properties {
- method public boolean getBoolean(@NonNull String, boolean);
- method public float getFloat(@NonNull String, float);
- method public int getInt(@NonNull String, int);
- method @NonNull public java.util.Set<java.lang.String> getKeyset();
- method public long getLong(@NonNull String, long);
- method @NonNull public String getNamespace();
- method @Nullable public String getString(@NonNull String, @Nullable String);
- }
-
- public static final class DeviceConfig.Properties.Builder {
- ctor public DeviceConfig.Properties.Builder(@NonNull String);
- method @NonNull public android.provider.DeviceConfig.Properties build();
- method @NonNull public android.provider.DeviceConfig.Properties.Builder setBoolean(@NonNull String, boolean);
- method @NonNull public android.provider.DeviceConfig.Properties.Builder setFloat(@NonNull String, float);
- method @NonNull public android.provider.DeviceConfig.Properties.Builder setInt(@NonNull String, int);
- method @NonNull public android.provider.DeviceConfig.Properties.Builder setLong(@NonNull String, long);
- method @NonNull public android.provider.DeviceConfig.Properties.Builder setString(@NonNull String, @Nullable String);
- }
-
- public final class DocumentsContract {
- method @NonNull public static android.net.Uri buildDocumentUriAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
- method public static boolean isManageMode(@NonNull android.net.Uri);
- method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri);
- field public static final String ACTION_DOCUMENT_ROOT_SETTINGS = "android.provider.action.DOCUMENT_ROOT_SETTINGS";
- field public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT";
- field public static final String EXTRA_SHOW_ADVANCED = "android.provider.extra.SHOW_ADVANCED";
- }
-
- public static final class DocumentsContract.Root {
- field public static final int FLAG_ADVANCED = 65536; // 0x10000
- field public static final int FLAG_HAS_SETTINGS = 131072; // 0x20000
- field public static final int FLAG_REMOVABLE_SD = 262144; // 0x40000
- field public static final int FLAG_REMOVABLE_USB = 524288; // 0x80000
- }
-
- public final class MediaStore {
- method @NonNull public static android.net.Uri rewriteToLegacy(@NonNull android.net.Uri);
- 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;
- }
-
- public abstract class SearchIndexableData {
- ctor public SearchIndexableData();
- ctor public SearchIndexableData(android.content.Context);
- field public String className;
- field public android.content.Context context;
- field public boolean enabled;
- field public int iconResId;
- field public String intentAction;
- field public String intentTargetClass;
- field public String intentTargetPackage;
- field public String key;
- field public java.util.Locale locale;
- field public String packageName;
- field public int rank;
- field public int userId;
- }
-
- public class SearchIndexableResource extends android.provider.SearchIndexableData {
- ctor public SearchIndexableResource(int, int, String, int);
- ctor public SearchIndexableResource(android.content.Context);
- field public int xmlResId;
- }
-
- public class SearchIndexablesContract {
- ctor public SearchIndexablesContract();
- field public static final int COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE = 0; // 0x0
- field public static final int COLUMN_INDEX_RAW_CLASS_NAME = 7; // 0x7
- field public static final int COLUMN_INDEX_RAW_ENTRIES = 4; // 0x4
- field public static final int COLUMN_INDEX_RAW_ICON_RESID = 8; // 0x8
- field public static final int COLUMN_INDEX_RAW_INTENT_ACTION = 9; // 0x9
- field public static final int COLUMN_INDEX_RAW_INTENT_TARGET_CLASS = 11; // 0xb
- field public static final int COLUMN_INDEX_RAW_INTENT_TARGET_PACKAGE = 10; // 0xa
- field public static final int COLUMN_INDEX_RAW_KEY = 12; // 0xc
- field public static final int COLUMN_INDEX_RAW_KEYWORDS = 5; // 0x5
- field public static final int COLUMN_INDEX_RAW_RANK = 0; // 0x0
- field public static final int COLUMN_INDEX_RAW_SCREEN_TITLE = 6; // 0x6
- field public static final int COLUMN_INDEX_RAW_SUMMARY_OFF = 3; // 0x3
- field public static final int COLUMN_INDEX_RAW_SUMMARY_ON = 2; // 0x2
- field public static final int COLUMN_INDEX_RAW_TITLE = 1; // 0x1
- field public static final int COLUMN_INDEX_RAW_USER_ID = 13; // 0xd
- field public static final int COLUMN_INDEX_XML_RES_CLASS_NAME = 2; // 0x2
- field public static final int COLUMN_INDEX_XML_RES_ICON_RESID = 3; // 0x3
- field public static final int COLUMN_INDEX_XML_RES_INTENT_ACTION = 4; // 0x4
- field public static final int COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS = 6; // 0x6
- field public static final int COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE = 5; // 0x5
- field public static final int COLUMN_INDEX_XML_RES_RANK = 0; // 0x0
- field public static final int COLUMN_INDEX_XML_RES_RESID = 1; // 0x1
- field public static final String DYNAMIC_INDEXABLES_RAW = "dynamic_indexables_raw";
- field public static final String DYNAMIC_INDEXABLES_RAW_PATH = "settings/dynamic_indexables_raw";
- field public static final String INDEXABLES_RAW = "indexables_raw";
- field public static final String[] INDEXABLES_RAW_COLUMNS;
- field public static final String INDEXABLES_RAW_PATH = "settings/indexables_raw";
- field public static final String INDEXABLES_XML_RES = "indexables_xml_res";
- field public static final String[] INDEXABLES_XML_RES_COLUMNS;
- field public static final String INDEXABLES_XML_RES_PATH = "settings/indexables_xml_res";
- field public static final String NON_INDEXABLES_KEYS = "non_indexables_key";
- field public static final String[] NON_INDEXABLES_KEYS_COLUMNS;
- field public static final String NON_INDEXABLES_KEYS_PATH = "settings/non_indexables_key";
- field public static final String PROVIDER_INTERFACE = "android.content.action.SEARCH_INDEXABLES_PROVIDER";
- field public static final String SLICE_URI_PAIRS = "slice_uri_pairs";
- field @NonNull public static final String[] SLICE_URI_PAIRS_COLUMNS;
- field public static final String SLICE_URI_PAIRS_PATH = "settings/slice_uri_pairs";
- }
-
- public static class SearchIndexablesContract.BaseColumns {
- field public static final String COLUMN_CLASS_NAME = "className";
- field public static final String COLUMN_ICON_RESID = "iconResId";
- field public static final String COLUMN_INTENT_ACTION = "intentAction";
- field public static final String COLUMN_INTENT_TARGET_CLASS = "intentTargetClass";
- field public static final String COLUMN_INTENT_TARGET_PACKAGE = "intentTargetPackage";
- field public static final String COLUMN_RANK = "rank";
- }
-
- public static final class SearchIndexablesContract.NonIndexableKey extends android.provider.SearchIndexablesContract.BaseColumns {
- field public static final String COLUMN_KEY_VALUE = "key";
- field public static final String MIME_TYPE = "vnd.android.cursor.dir/non_indexables_key";
- }
-
- public static final class SearchIndexablesContract.RawData extends android.provider.SearchIndexablesContract.BaseColumns {
- field public static final String COLUMN_ENTRIES = "entries";
- field public static final String COLUMN_KEY = "key";
- field public static final String COLUMN_KEYWORDS = "keywords";
- field public static final String COLUMN_SCREEN_TITLE = "screenTitle";
- field public static final String COLUMN_SUMMARY_OFF = "summaryOff";
- field public static final String COLUMN_SUMMARY_ON = "summaryOn";
- field public static final String COLUMN_TITLE = "title";
- field public static final String COLUMN_USER_ID = "user_id";
- field public static final String MIME_TYPE = "vnd.android.cursor.dir/indexables_raw";
- }
-
- public static final class SearchIndexablesContract.SliceUriPairColumns {
- field public static final String KEY = "key";
- field public static final String SLICE_URI = "slice_uri";
- }
-
- public static final class SearchIndexablesContract.XmlResource extends android.provider.SearchIndexablesContract.BaseColumns {
- field public static final String COLUMN_XML_RESID = "xmlResId";
- field public static final String MIME_TYPE = "vnd.android.cursor.dir/indexables_xml_res";
- }
-
- public abstract class SearchIndexablesProvider extends android.content.ContentProvider {
- ctor public SearchIndexablesProvider();
- method public final int delete(android.net.Uri, String, String[]);
- method public String getType(android.net.Uri);
- method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
- method public android.database.Cursor query(android.net.Uri, String[], String, String[], String);
- method @Nullable public android.database.Cursor queryDynamicRawData(@Nullable String[]);
- method public abstract android.database.Cursor queryNonIndexableKeys(String[]);
- method public abstract android.database.Cursor queryRawData(String[]);
- method @Nullable public android.database.Cursor querySliceUriPairs();
- method public abstract android.database.Cursor queryXmlResources(String[]);
- method public final int update(android.net.Uri, android.content.ContentValues, String, String[]);
- }
-
- public final class Settings {
- method @Deprecated public static boolean checkAndNoteWriteSettingsOperation(@NonNull android.content.Context, int, @NonNull String, boolean);
- method public static boolean checkAndNoteWriteSettingsOperation(@NonNull android.content.Context, int, @NonNull String, @Nullable String, boolean);
- field public static final String ACTION_ACCESSIBILITY_DETAILS_SETTINGS = "android.settings.ACCESSIBILITY_DETAILS_SETTINGS";
- field public static final String ACTION_BUGREPORT_HANDLER_SETTINGS = "android.settings.BUGREPORT_HANDLER_SETTINGS";
- field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
- field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS";
- field public static final String ACTION_MANAGE_APP_OVERLAY_PERMISSION = "android.settings.MANAGE_APP_OVERLAY_PERMISSION";
- field public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS";
- field public static final String ACTION_MANAGE_MORE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_MORE_DEFAULT_APPS_SETTINGS";
- field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS";
- field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
- field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
- field public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI";
- field public static final String ACTION_TETHER_SETTINGS = "android.settings.TETHER_SETTINGS";
- }
-
- public static final class Settings.Global extends android.provider.Settings.NameValueTable {
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, @Nullable String, boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
- field public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
- field public static final String APP_STANDBY_ENABLED = "app_standby_enabled";
- field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
- field public static final String CARRIER_APP_NAMES = "carrier_app_names";
- field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
- field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
- field public static final String DEVICE_DEMO_MODE = "device_demo_mode";
- field public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data";
- field public static final String EUICC_PROVISIONED = "euicc_provisioned";
- field public static final String EUICC_SUPPORTED_COUNTRIES = "euicc_supported_countries";
- field public static final String EUICC_UNSUPPORTED_COUNTRIES = "euicc_unsupported_countries";
- field public static final String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT = "install_carrier_app_notification_persistent";
- field public static final String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis";
- field public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update";
- field public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt";
- field public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled";
- field public static final String TETHER_SUPPORTED = "tether_supported";
- field public static final String THEATER_MODE_ON = "theater_mode_on";
- field public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
- field public static final String WIFI_BADGING_THRESHOLDS = "wifi_badging_thresholds";
- field @Deprecated public static final String WIFI_WAKEUP_ENABLED = "wifi_wakeup_enabled";
- }
-
- public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, @Nullable String, boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
- field @Deprecated public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED = "accessibility_display_magnification_navbar_enabled";
- field public static final String ASSIST_GESTURE_SETUP_COMPLETE = "assist_gesture_setup_complete";
- field public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
- field public static final String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count";
- field public static final String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size";
- field public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
- field public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
- field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
- field public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled";
- field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
- field public static final String DOZE_ALWAYS_ON = "doze_always_on";
- field public static final String HUSH_GESTURE_USED = "hush_gesture_used";
- field public static final String INSTANT_APPS_ENABLED = "instant_apps_enabled";
- field public static final String LAST_SETUP_SHOWN = "last_setup_shown";
- field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
- field public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = "location_access_check_interval_millis";
- field public static final int LOCATION_MODE_ON = 3; // 0x3
- field @Deprecated public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE = "location_permissions_upgrade_to_q_mode";
- field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications";
- field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications";
- field public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
- field public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = "theme_customization_overlay_packages";
- field public static final String USER_SETUP_COMPLETE = "user_setup_complete";
- field public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; // 0xa
- field public static final int USER_SETUP_PERSONALIZATION_NOT_STARTED = 0; // 0x0
- field public static final int USER_SETUP_PERSONALIZATION_PAUSED = 2; // 0x2
- field public static final int USER_SETUP_PERSONALIZATION_STARTED = 1; // 0x1
- field public static final String USER_SETUP_PERSONALIZATION_STATE = "user_setup_personalization_state";
- field public static final String VOLUME_HUSH_GESTURE = "volume_hush_gesture";
- field public static final int VOLUME_HUSH_MUTE = 2; // 0x2
- field public static final int VOLUME_HUSH_OFF = 0; // 0x0
- field public static final int VOLUME_HUSH_VIBRATE = 1; // 0x1
- }
-
- public static final class Settings.System extends android.provider.Settings.NameValueTable {
- method @RequiresPermission(android.Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, boolean);
- }
-
- public static final class Telephony.Carriers implements android.provider.BaseColumns {
- field public static final String APN_SET_ID = "apn_set_id";
- field public static final int CARRIER_EDITED = 4; // 0x4
- field public static final String EDITED_STATUS = "edited";
- field public static final int MATCH_ALL_APN_SET_ID = -1; // 0xffffffff
- field public static final String MAX_CONNECTIONS = "max_conns";
- field public static final String MODEM_PERSIST = "modem_cognitive";
- field public static final String MTU = "mtu";
- field public static final int NO_APN_SET_ID = 0; // 0x0
- field public static final String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time";
- field public static final int UNEDITED = 0; // 0x0
- field public static final int USER_DELETED = 2; // 0x2
- field public static final String USER_EDITABLE = "user_editable";
- field public static final int USER_EDITED = 1; // 0x1
- field public static final String USER_VISIBLE = "user_visible";
- field public static final String WAIT_TIME_RETRY = "wait_time";
- }
-
- public static final class Telephony.CellBroadcasts implements android.provider.BaseColumns {
- field @NonNull public static final String AUTHORITY_LEGACY = "cellbroadcast-legacy";
- field @NonNull public static final android.net.Uri AUTHORITY_LEGACY_URI;
- field @NonNull public static final String CALL_METHOD_GET_PREFERENCE = "get_preference";
- field public static final String CID = "cid";
- field public static final String CMAS_CATEGORY = "cmas_category";
- field public static final String CMAS_CERTAINTY = "cmas_certainty";
- field public static final String CMAS_MESSAGE_CLASS = "cmas_message_class";
- field public static final String CMAS_RESPONSE_TYPE = "cmas_response_type";
- field public static final String CMAS_SEVERITY = "cmas_severity";
- field public static final String CMAS_URGENCY = "cmas_urgency";
- field @NonNull public static final android.net.Uri CONTENT_URI;
- field public static final String DATA_CODING_SCHEME = "dcs";
- field public static final String DEFAULT_SORT_ORDER = "date DESC";
- field public static final String DELIVERY_TIME = "date";
- field public static final String ETWS_IS_PRIMARY = "etws_is_primary";
- field public static final String ETWS_WARNING_TYPE = "etws_warning_type";
- field public static final String GEOGRAPHICAL_SCOPE = "geo_scope";
- field public static final String GEOMETRIES = "geometries";
- field public static final String LAC = "lac";
- field public static final String LANGUAGE_CODE = "language";
- field public static final String LOCATION_CHECK_TIME = "location_check_time";
- field public static final String MAXIMUM_WAIT_TIME = "maximum_wait_time";
- field public static final String MESSAGE_BODY = "body";
- field public static final String MESSAGE_BROADCASTED = "message_broadcasted";
- field public static final String MESSAGE_DISPLAYED = "message_displayed";
- field public static final String MESSAGE_FORMAT = "format";
- field @NonNull @RequiresPermission(android.Manifest.permission.READ_CELL_BROADCASTS) public static final android.net.Uri MESSAGE_HISTORY_URI;
- field public static final String MESSAGE_PRIORITY = "priority";
- field public static final String MESSAGE_READ = "read";
- field public static final String PLMN = "plmn";
- field public static final String RECEIVED_TIME = "received_time";
- field public static final String SERIAL_NUMBER = "serial_number";
- field public static final String SERVICE_CATEGORY = "service_category";
- field public static final String SLOT_INDEX = "slot_index";
- field public static final String SUBSCRIPTION_ID = "sub_id";
- }
-
- public static final class Telephony.CellBroadcasts.Preference {
- field @NonNull public static final String ENABLE_ALERT_VIBRATION_PREF = "enable_alert_vibrate";
- field @NonNull public static final String ENABLE_AREA_UPDATE_INFO_PREF = "enable_area_update_info_alerts";
- field @NonNull public static final String ENABLE_CMAS_AMBER_PREF = "enable_cmas_amber_alerts";
- field @NonNull public static final String ENABLE_CMAS_EXTREME_THREAT_PREF = "enable_cmas_extreme_threat_alerts";
- field @NonNull public static final String ENABLE_CMAS_IN_SECOND_LANGUAGE_PREF = "receive_cmas_in_second_language";
- field @NonNull public static final String ENABLE_CMAS_PRESIDENTIAL_PREF = "enable_cmas_presidential_alerts";
- field @NonNull public static final String ENABLE_CMAS_SEVERE_THREAT_PREF = "enable_cmas_severe_threat_alerts";
- field @NonNull public static final String ENABLE_EMERGENCY_PERF = "enable_emergency_alerts";
- field @NonNull public static final String ENABLE_PUBLIC_SAFETY_PREF = "enable_public_safety_messages";
- field @NonNull public static final String ENABLE_STATE_LOCAL_TEST_PREF = "enable_state_local_test_alerts";
- field @NonNull public static final String ENABLE_TEST_ALERT_PREF = "enable_test_alerts";
- }
-
- public static final class Telephony.Sms.Intents {
- field public static final String ACTION_SMS_EMERGENCY_CB_RECEIVED = "android.provider.action.SMS_EMERGENCY_CB_RECEIVED";
- }
-
- public final class TimeZoneRulesDataContract {
- field public static final String AUTHORITY = "com.android.timezone";
- }
-
- public static final class TimeZoneRulesDataContract.Operation {
- field public static final String COLUMN_DISTRO_MAJOR_VERSION = "distro_major_version";
- field public static final String COLUMN_DISTRO_MINOR_VERSION = "distro_minor_version";
- field public static final String COLUMN_REVISION = "revision";
- field public static final String COLUMN_RULES_VERSION = "rules_version";
- field public static final String COLUMN_TYPE = "type";
- field public static final android.net.Uri CONTENT_URI;
- field public static final String TYPE_INSTALL = "INSTALL";
- field public static final String TYPE_NO_OP = "NOOP";
- field public static final String TYPE_UNINSTALL = "UNINSTALL";
- }
-
-}
-
-package android.se.omapi {
-
- public final class Reader {
- method @RequiresPermission(android.Manifest.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION) public boolean reset();
- }
-
-}
-
-package android.security.keystore {
-
- public class AndroidKeyStoreProvider extends java.security.Provider {
- method @NonNull public static java.security.KeyStore getKeyStoreForUid(int) throws java.security.KeyStoreException, java.security.NoSuchProviderException;
- }
-
- public abstract class AttestationUtils {
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException;
- field public static final int ID_TYPE_IMEI = 2; // 0x2
- field public static final int ID_TYPE_MEID = 3; // 0x3
- field public static final int ID_TYPE_SERIAL = 1; // 0x1
- field public static final int USE_INDIVIDUAL_ATTESTATION = 4; // 0x4
- }
-
- public class DeviceIdAttestationException extends java.lang.Exception {
- ctor public DeviceIdAttestationException(@Nullable String);
- ctor public DeviceIdAttestationException(@Nullable String, @Nullable Throwable);
- }
-
- public static final class KeyGenParameterSpec.Builder {
- method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
- }
-
-}
-
-package android.security.keystore.recovery {
-
- public class DecryptionFailedException extends java.security.GeneralSecurityException {
- ctor public DecryptionFailedException(String);
- }
-
- public class InternalRecoveryServiceException extends java.security.GeneralSecurityException {
- ctor public InternalRecoveryServiceException(String);
- ctor public InternalRecoveryServiceException(String, Throwable);
- }
-
- public final class KeyChainProtectionParams implements android.os.Parcelable {
- method public void clearSecret();
- method public int describeContents();
- method @NonNull public android.security.keystore.recovery.KeyDerivationParams getKeyDerivationParams();
- method public int getLockScreenUiFormat();
- method @NonNull public byte[] getSecret();
- method public int getUserSecretType();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.security.keystore.recovery.KeyChainProtectionParams> CREATOR;
- field public static final int TYPE_LOCKSCREEN = 100; // 0x64
- field public static final int UI_FORMAT_PASSWORD = 2; // 0x2
- field public static final int UI_FORMAT_PATTERN = 3; // 0x3
- field public static final int UI_FORMAT_PIN = 1; // 0x1
- }
-
- public static class KeyChainProtectionParams.Builder {
- ctor public KeyChainProtectionParams.Builder();
- method @NonNull public android.security.keystore.recovery.KeyChainProtectionParams build();
- method @NonNull public android.security.keystore.recovery.KeyChainProtectionParams.Builder setKeyDerivationParams(@NonNull android.security.keystore.recovery.KeyDerivationParams);
- method @NonNull public android.security.keystore.recovery.KeyChainProtectionParams.Builder setLockScreenUiFormat(int);
- method @NonNull public android.security.keystore.recovery.KeyChainProtectionParams.Builder setSecret(@NonNull byte[]);
- method @NonNull public android.security.keystore.recovery.KeyChainProtectionParams.Builder setUserSecretType(int);
- }
-
- public final class KeyChainSnapshot implements android.os.Parcelable {
- method public int describeContents();
- method public long getCounterId();
- method @NonNull public byte[] getEncryptedRecoveryKeyBlob();
- method @NonNull public java.util.List<android.security.keystore.recovery.KeyChainProtectionParams> getKeyChainProtectionParams();
- method public int getMaxAttempts();
- method @NonNull public byte[] getServerParams();
- method public int getSnapshotVersion();
- method @NonNull public java.security.cert.CertPath getTrustedHardwareCertPath();
- method @NonNull public java.util.List<android.security.keystore.recovery.WrappedApplicationKey> getWrappedApplicationKeys();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.security.keystore.recovery.KeyChainSnapshot> CREATOR;
- }
-
- public final class KeyDerivationParams implements android.os.Parcelable {
- method @NonNull public static android.security.keystore.recovery.KeyDerivationParams createScryptParams(@NonNull byte[], int);
- method @NonNull public static android.security.keystore.recovery.KeyDerivationParams createSha256Params(@NonNull byte[]);
- method public int describeContents();
- method public int getAlgorithm();
- method public int getMemoryDifficulty();
- method @NonNull public byte[] getSalt();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int ALGORITHM_SCRYPT = 2; // 0x2
- field public static final int ALGORITHM_SHA256 = 1; // 0x1
- field @NonNull public static final android.os.Parcelable.Creator<android.security.keystore.recovery.KeyDerivationParams> CREATOR;
- }
-
- public class LockScreenRequiredException extends java.security.GeneralSecurityException {
- ctor public LockScreenRequiredException(String);
- }
-
- public class RecoveryController {
- method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public android.security.keystore.recovery.RecoverySession createRecoverySession();
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key generateKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
- method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key generateKey(@NonNull String, @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
- method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.util.List<java.lang.String> getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public static android.security.keystore.recovery.RecoveryController getInstance(@NonNull android.content.Context);
- method @Nullable @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key getKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException, java.security.UnrecoverableKeyException;
- method @Nullable @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public android.security.keystore.recovery.KeyChainSnapshot getKeyChainSnapshot() throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public int getRecoveryStatus(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.util.Map<java.lang.String,java.security.cert.X509Certificate> getRootCertificates();
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key importKey(@NonNull String, @NonNull byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
- method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.security.Key importKey(@NonNull String, @NonNull byte[], @Nullable byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
- method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void initRecoveryService(@NonNull String, @NonNull byte[], @NonNull byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
- method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public static boolean isRecoverableKeyStoreEnabled(@NonNull android.content.Context);
- method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void removeKey(@NonNull String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void setRecoverySecretTypes(@NonNull int[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void setRecoveryStatus(@NonNull String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void setServerParams(@NonNull byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void setSnapshotCreatedPendingIntent(@Nullable android.app.PendingIntent) throws android.security.keystore.recovery.InternalRecoveryServiceException;
- field public static final int RECOVERY_STATUS_PERMANENT_FAILURE = 3; // 0x3
- field public static final int RECOVERY_STATUS_SYNCED = 0; // 0x0
- field public static final int RECOVERY_STATUS_SYNC_IN_PROGRESS = 1; // 0x1
- }
-
- public class RecoverySession implements java.lang.AutoCloseable {
- method @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void close();
- method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public java.util.Map<java.lang.String,java.security.Key> recoverKeyChainSnapshot(@NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
- method @NonNull @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public byte[] start(@NonNull String, @NonNull java.security.cert.CertPath, @NonNull byte[], @NonNull byte[], @NonNull java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
- }
-
- public class SessionExpiredException extends java.security.GeneralSecurityException {
- ctor public SessionExpiredException(String);
- }
-
- public final class WrappedApplicationKey implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public String getAlias();
- method @NonNull public byte[] getEncryptedKeyMaterial();
- method @Nullable public byte[] getMetadata();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.security.keystore.recovery.WrappedApplicationKey> CREATOR;
- }
-
- public static class WrappedApplicationKey.Builder {
- ctor public WrappedApplicationKey.Builder();
- method @NonNull public android.security.keystore.recovery.WrappedApplicationKey build();
- method @NonNull public android.security.keystore.recovery.WrappedApplicationKey.Builder setAlias(@NonNull String);
- method @NonNull public android.security.keystore.recovery.WrappedApplicationKey.Builder setEncryptedKeyMaterial(@NonNull byte[]);
- method @NonNull public android.security.keystore.recovery.WrappedApplicationKey.Builder setMetadata(@Nullable byte[]);
- }
-
-}
-
-package android.service.appprediction {
-
- public abstract class AppPredictionService extends android.app.Service {
- ctor public AppPredictionService();
- method @MainThread public abstract void onAppTargetEvent(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull android.app.prediction.AppTargetEvent);
- method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method public void onCreatePredictionSession(@NonNull android.app.prediction.AppPredictionContext, @NonNull android.app.prediction.AppPredictionSessionId);
- method @MainThread public void onDestroyPredictionSession(@NonNull android.app.prediction.AppPredictionSessionId);
- method @MainThread public abstract void onLaunchLocationShown(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
- method @MainThread public abstract void onRequestPredictionUpdate(@NonNull android.app.prediction.AppPredictionSessionId);
- method @MainThread public abstract void onSortAppTargets(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
- method @MainThread public void onStartPredictionUpdates();
- method @MainThread public void onStopPredictionUpdates();
- method public final void updatePredictions(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull java.util.List<android.app.prediction.AppTarget>);
- }
-
-}
-
-package android.service.attention {
-
- public abstract class AttentionService extends android.app.Service {
- ctor public AttentionService();
- method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method public abstract void onCancelAttentionCheck(@NonNull android.service.attention.AttentionService.AttentionCallback);
- method public abstract void onCheckAttention(@NonNull android.service.attention.AttentionService.AttentionCallback);
- field public static final int ATTENTION_FAILURE_CAMERA_PERMISSION_ABSENT = 6; // 0x6
- field public static final int ATTENTION_FAILURE_CANCELLED = 3; // 0x3
- field public static final int ATTENTION_FAILURE_PREEMPTED = 4; // 0x4
- field public static final int ATTENTION_FAILURE_TIMED_OUT = 5; // 0x5
- field public static final int ATTENTION_FAILURE_UNKNOWN = 2; // 0x2
- field public static final int ATTENTION_SUCCESS_ABSENT = 0; // 0x0
- field public static final int ATTENTION_SUCCESS_PRESENT = 1; // 0x1
- field public static final String SERVICE_INTERFACE = "android.service.attention.AttentionService";
- }
-
- public static final class AttentionService.AttentionCallback {
- method public void onFailure(int);
- method public void onSuccess(int, long);
- }
-
-}
-
-package android.service.autofill {
-
- public abstract class AutofillFieldClassificationService extends android.app.Service {
- ctor public AutofillFieldClassificationService();
- method public android.os.IBinder onBind(android.content.Intent);
- method @Nullable public float[][] onCalculateScores(@NonNull java.util.List<android.view.autofill.AutofillValue>, @NonNull java.util.List<java.lang.String>, @NonNull java.util.List<java.lang.String>, @Nullable String, @Nullable android.os.Bundle, @Nullable java.util.Map, @Nullable java.util.Map);
- method @Deprecated @Nullable public float[][] onGetScores(@Nullable String, @Nullable android.os.Bundle, @NonNull java.util.List<android.view.autofill.AutofillValue>, @NonNull java.util.List<java.lang.String>);
- field public static final String REQUIRED_ALGORITHM_CREDIT_CARD = "CREDIT_CARD";
- field public static final String REQUIRED_ALGORITHM_EDIT_DISTANCE = "EDIT_DISTANCE";
- field public static final String REQUIRED_ALGORITHM_EXACT_MATCH = "EXACT_MATCH";
- field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService";
- field public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = "android.autofill.field_classification.available_algorithms";
- field public static final String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM = "android.autofill.field_classification.default_algorithm";
- }
-
- public static final class Dataset.Builder {
- ctor public Dataset.Builder(@NonNull android.service.autofill.InlinePresentation);
- method @NonNull public android.service.autofill.Dataset.Builder setContent(@NonNull android.view.autofill.AutofillId, @Nullable android.content.ClipData);
- method @NonNull public android.service.autofill.Dataset.Builder setFieldInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation);
- }
-
- public abstract class InlineSuggestionRenderService extends android.app.Service {
- ctor public InlineSuggestionRenderService();
- method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method @NonNull public android.os.Bundle onGetInlineSuggestionsRendererInfo();
- method @Nullable public android.view.View onRenderSuggestion(@NonNull android.service.autofill.InlinePresentation, int, int);
- method public final void startIntentSender(@NonNull android.content.IntentSender);
- field public static final String SERVICE_INTERFACE = "android.service.autofill.InlineSuggestionRenderService";
- }
-
-}
-
-package android.service.autofill.augmented {
-
- public abstract class AugmentedAutofillService extends android.app.Service {
- ctor public AugmentedAutofillService();
- method protected final void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
- method protected void dump(@NonNull java.io.PrintWriter, @NonNull String[]);
- method @Nullable public final android.service.autofill.FillEventHistory getFillEventHistory();
- method public void onConnected();
- method public void onDisconnected();
- method public void onFillRequest(@NonNull android.service.autofill.augmented.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.augmented.FillController, @NonNull android.service.autofill.augmented.FillCallback);
- method public final boolean requestAutofill(@NonNull android.content.ComponentName, @NonNull android.view.autofill.AutofillId);
- field public static final String SERVICE_INTERFACE = "android.service.autofill.augmented.AugmentedAutofillService";
- }
-
- public final class FillCallback {
- method public void onSuccess(@Nullable android.service.autofill.augmented.FillResponse);
- }
-
- public final class FillController {
- method public void autofill(@NonNull java.util.List<android.util.Pair<android.view.autofill.AutofillId,android.view.autofill.AutofillValue>>);
- }
-
- public final class FillRequest {
- method @NonNull public android.content.ComponentName getActivityComponent();
- method @NonNull public android.view.autofill.AutofillId getFocusedId();
- method @NonNull public android.view.autofill.AutofillValue getFocusedValue();
- method @Nullable public android.view.inputmethod.InlineSuggestionsRequest getInlineSuggestionsRequest();
- method @Nullable public android.service.autofill.augmented.PresentationParams getPresentationParams();
- method public int getTaskId();
- }
-
- public final class FillResponse {
- }
-
- 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(@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 setInlineSuggestions(@NonNull java.util.List<android.service.autofill.Dataset>);
- }
-
- public final class FillWindow implements java.lang.AutoCloseable {
- ctor public FillWindow();
- method public void destroy();
- method public boolean update(@NonNull android.service.autofill.augmented.PresentationParams.Area, @NonNull android.view.View, long);
- }
-
- public abstract class PresentationParams {
- method @Nullable public android.service.autofill.augmented.PresentationParams.Area getSuggestionArea();
- }
-
- public abstract static class PresentationParams.Area {
- method @NonNull public android.graphics.Rect getBounds();
- }
-
-}
-
-package android.service.carrier {
-
- public abstract class ApnService extends android.app.Service {
- ctor public ApnService();
- method @NonNull public android.os.IBinder onBind(@Nullable android.content.Intent);
- method @NonNull @WorkerThread public abstract java.util.List<android.content.ContentValues> onRestoreApns(int);
- }
-
-}
-
-package android.service.contentcapture {
-
- public final class ActivityEvent implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.content.ComponentName getComponentName();
- method public int getEventType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.ActivityEvent> CREATOR;
- field public static final int TYPE_ACTIVITY_DESTROYED = 24; // 0x18
- field public static final int TYPE_ACTIVITY_PAUSED = 2; // 0x2
- field public static final int TYPE_ACTIVITY_RESUMED = 1; // 0x1
- field public static final int TYPE_ACTIVITY_STOPPED = 23; // 0x17
- }
-
- public abstract class ContentCaptureService extends android.app.Service {
- ctor public ContentCaptureService();
- method public final void disableSelf();
- method public void onActivityEvent(@NonNull android.service.contentcapture.ActivityEvent);
- method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData);
- method public void onConnected();
- method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent);
- method public void onCreateContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext, @NonNull android.view.contentcapture.ContentCaptureSessionId);
- method public void onDataRemovalRequest(@NonNull android.view.contentcapture.DataRemovalRequest);
- method public void onDataShareRequest(@NonNull android.view.contentcapture.DataShareRequest, @NonNull android.service.contentcapture.DataShareCallback);
- method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId);
- method public void onDisconnected();
- method public final void setContentCaptureConditions(@NonNull String, @Nullable java.util.Set<android.view.contentcapture.ContentCaptureCondition>);
- method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>);
- field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
- field public static final String SERVICE_META_DATA = "android.content_capture";
- }
-
- public interface DataShareCallback {
- method public void onAccept(@NonNull java.util.concurrent.Executor, @NonNull android.service.contentcapture.DataShareReadAdapter);
- method public void onReject();
- }
-
- public interface DataShareReadAdapter {
- method public void onError(int);
- method public void onStart(@NonNull android.os.ParcelFileDescriptor);
- }
-
- public final class SnapshotData implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public android.app.assist.AssistContent getAssistContent();
- method @NonNull public android.os.Bundle getAssistData();
- method @NonNull public android.app.assist.AssistStructure getAssistStructure();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.SnapshotData> CREATOR;
- }
-
-}
-
-package android.service.contentsuggestions {
-
- public abstract class ContentSuggestionsService extends android.app.Service {
- ctor public ContentSuggestionsService();
- method public abstract void onClassifyContentSelections(@NonNull android.app.contentsuggestions.ClassificationsRequest, @NonNull android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback);
- method public abstract void onNotifyInteraction(@NonNull String, @NonNull android.os.Bundle);
- method public abstract void onProcessContextImage(int, @Nullable android.graphics.Bitmap, @NonNull android.os.Bundle);
- method public abstract void onSuggestContentSelections(@NonNull android.app.contentsuggestions.SelectionsRequest, @NonNull android.app.contentsuggestions.ContentSuggestionsManager.SelectionsCallback);
- field public static final String SERVICE_INTERFACE = "android.service.contentsuggestions.ContentSuggestionsService";
- }
-
-}
-
-package android.service.dataloader {
-
- public abstract class DataLoaderService extends android.app.Service {
- ctor public DataLoaderService();
- method @Nullable public android.service.dataloader.DataLoaderService.DataLoader onCreateDataLoader(@NonNull android.content.pm.DataLoaderParams);
- }
-
- public static interface DataLoaderService.DataLoader {
- method public boolean onCreate(@NonNull android.content.pm.DataLoaderParams, @NonNull android.service.dataloader.DataLoaderService.FileSystemConnector);
- method public boolean onPrepareImage(@NonNull java.util.Collection<android.content.pm.InstallationFile>, @NonNull java.util.Collection<java.lang.String>);
- }
-
- public static final class DataLoaderService.FileSystemConnector {
- method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void writeData(@NonNull String, long, long, @NonNull android.os.ParcelFileDescriptor) throws java.io.IOException;
- }
-
-}
-
-package android.service.euicc {
-
- public final class DownloadSubscriptionResult implements android.os.Parcelable {
- ctor public DownloadSubscriptionResult(int, int, int);
- method public int describeContents();
- method public int getCardId();
- method public int getResolvableErrors();
- method public int getResult();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.euicc.DownloadSubscriptionResult> CREATOR;
- }
-
- public final class EuiccProfileInfo implements android.os.Parcelable {
- method public int describeContents();
- method public android.service.carrier.CarrierIdentifier getCarrierIdentifier();
- method public String getIccid();
- method @Nullable public String getNickname();
- method @android.service.euicc.EuiccProfileInfo.PolicyRule public int getPolicyRules();
- method @android.service.euicc.EuiccProfileInfo.ProfileClass public int getProfileClass();
- method public String getProfileName();
- method public String getServiceProviderName();
- method @android.service.euicc.EuiccProfileInfo.ProfileState public int getState();
- method @Nullable public java.util.List<android.telephony.UiccAccessRule> getUiccAccessRules();
- method public boolean hasPolicyRule(@android.service.euicc.EuiccProfileInfo.PolicyRule int);
- method public boolean hasPolicyRules();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.euicc.EuiccProfileInfo> CREATOR;
- field public static final int POLICY_RULE_DELETE_AFTER_DISABLING = 4; // 0x4
- field public static final int POLICY_RULE_DO_NOT_DELETE = 2; // 0x2
- field public static final int POLICY_RULE_DO_NOT_DISABLE = 1; // 0x1
- field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
- field public static final int PROFILE_CLASS_PROVISIONING = 1; // 0x1
- field public static final int PROFILE_CLASS_TESTING = 0; // 0x0
- field public static final int PROFILE_STATE_DISABLED = 0; // 0x0
- field public static final int PROFILE_STATE_ENABLED = 1; // 0x1
- }
-
- public static final class EuiccProfileInfo.Builder {
- ctor public EuiccProfileInfo.Builder(String);
- ctor public EuiccProfileInfo.Builder(android.service.euicc.EuiccProfileInfo);
- method public android.service.euicc.EuiccProfileInfo build();
- method public android.service.euicc.EuiccProfileInfo.Builder setCarrierIdentifier(android.service.carrier.CarrierIdentifier);
- method public android.service.euicc.EuiccProfileInfo.Builder setIccid(String);
- method public android.service.euicc.EuiccProfileInfo.Builder setNickname(String);
- method public android.service.euicc.EuiccProfileInfo.Builder setPolicyRules(@android.service.euicc.EuiccProfileInfo.PolicyRule int);
- method public android.service.euicc.EuiccProfileInfo.Builder setProfileClass(@android.service.euicc.EuiccProfileInfo.ProfileClass int);
- method public android.service.euicc.EuiccProfileInfo.Builder setProfileName(String);
- method public android.service.euicc.EuiccProfileInfo.Builder setServiceProviderName(String);
- method public android.service.euicc.EuiccProfileInfo.Builder setState(@android.service.euicc.EuiccProfileInfo.ProfileState int);
- method public android.service.euicc.EuiccProfileInfo.Builder setUiccAccessRule(@Nullable java.util.List<android.telephony.UiccAccessRule>);
- }
-
- @IntDef(flag=true, prefix={"POLICY_RULE_"}, value={android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DISABLE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE, android.service.euicc.EuiccProfileInfo.POLICY_RULE_DELETE_AFTER_DISABLING}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccProfileInfo.PolicyRule {
- }
-
- @IntDef(prefix={"PROFILE_CLASS_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_TESTING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_PROVISIONING, android.service.euicc.EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL, 0xffffffff}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccProfileInfo.ProfileClass {
- }
-
- @IntDef(prefix={"PROFILE_STATE_"}, value={android.service.euicc.EuiccProfileInfo.PROFILE_STATE_DISABLED, android.service.euicc.EuiccProfileInfo.PROFILE_STATE_ENABLED, 0xffffffff}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccProfileInfo.ProfileState {
- }
-
- public abstract class EuiccService extends android.app.Service {
- ctor public EuiccService();
- method public void dump(@NonNull java.io.PrintWriter);
- method public int encodeSmdxSubjectAndReasonCode(@Nullable String, @Nullable String);
- method @CallSuper public android.os.IBinder onBind(android.content.Intent);
- method public abstract int onDeleteSubscription(int, String);
- method public android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle);
- method @Deprecated public int onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean);
- method @Deprecated public abstract int onEraseSubscriptions(int);
- method public int onEraseSubscriptions(int, @android.telephony.euicc.EuiccCardManager.ResetOption int);
- method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean);
- method public abstract android.service.euicc.GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(int, android.telephony.euicc.DownloadableSubscription, boolean);
- method public abstract String onGetEid(int);
- method @NonNull public abstract android.telephony.euicc.EuiccInfo onGetEuiccInfo(int);
- method @NonNull public abstract android.service.euicc.GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int);
- method @android.telephony.euicc.EuiccManager.OtaStatus public abstract int onGetOtaStatus(int);
- method public abstract int onRetainSubscriptionsForFactoryReset(int);
- method public abstract void onStartOtaIfNecessary(int, android.service.euicc.EuiccService.OtaStatusChangedCallback);
- method public abstract int onSwitchToSubscription(int, @Nullable String, boolean);
- method public abstract int onUpdateSubscriptionNickname(int, String, String);
- field public static final String ACTION_BIND_CARRIER_PROVISIONING_SERVICE = "android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE";
- field public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = "android.service.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED";
- field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
- field public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
- field public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED = "android.service.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
- field @Deprecated public static final String ACTION_RESOLVE_CONFIRMATION_CODE = "android.service.euicc.action.RESOLVE_CONFIRMATION_CODE";
- field public static final String ACTION_RESOLVE_DEACTIVATE_SIM = "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
- field public static final String ACTION_RESOLVE_NO_PRIVILEGES = "android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
- field public static final String ACTION_RESOLVE_RESOLVABLE_ERRORS = "android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS";
- field public static final String ACTION_START_CARRIER_ACTIVATION = "android.service.euicc.action.START_CARRIER_ACTIVATION";
- field public static final String ACTION_START_EUICC_ACTIVATION = "android.service.euicc.action.START_EUICC_ACTIVATION";
- field public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = "android.service.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED";
- field public static final String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI";
- field public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService";
- field public static final String EXTRA_RESOLUTION_ALLOW_POLICY_RULES = "android.service.euicc.extra.RESOLUTION_ALLOW_POLICY_RULES";
- field public static final String EXTRA_RESOLUTION_CALLING_PACKAGE = "android.service.euicc.extra.RESOLUTION_CALLING_PACKAGE";
- field public static final String EXTRA_RESOLUTION_CARD_ID = "android.service.euicc.extra.RESOLUTION_CARD_ID";
- field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE";
- field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
- field public static final String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT";
- field public static final String EXTRA_RESOLVABLE_ERRORS = "android.service.euicc.extra.RESOLVABLE_ERRORS";
- field public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1; // 0x1
- field public static final int RESOLVABLE_ERROR_POLICY_RULES = 2; // 0x2
- field public static final int RESULT_FIRST_USER = 1; // 0x1
- field public static final int RESULT_MUST_DEACTIVATE_SIM = -1; // 0xffffffff
- field @Deprecated public static final int RESULT_NEED_CONFIRMATION_CODE = -2; // 0xfffffffe
- field public static final int RESULT_OK = 0; // 0x0
- field public static final int RESULT_RESOLVABLE_ERRORS = -2; // 0xfffffffe
- }
-
- public abstract static class EuiccService.OtaStatusChangedCallback {
- ctor public EuiccService.OtaStatusChangedCallback();
- method public abstract void onOtaStatusChanged(int);
- }
-
- public final class GetDefaultDownloadableSubscriptionListResult implements android.os.Parcelable {
- ctor public GetDefaultDownloadableSubscriptionListResult(int, @Nullable android.telephony.euicc.DownloadableSubscription[]);
- method public int describeContents();
- method @Nullable public java.util.List<android.telephony.euicc.DownloadableSubscription> getDownloadableSubscriptions();
- method public int getResult();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.euicc.GetDefaultDownloadableSubscriptionListResult> CREATOR;
- }
-
- public final class GetDownloadableSubscriptionMetadataResult implements android.os.Parcelable {
- ctor public GetDownloadableSubscriptionMetadataResult(int, @Nullable android.telephony.euicc.DownloadableSubscription);
- method public int describeContents();
- method @Nullable public android.telephony.euicc.DownloadableSubscription getDownloadableSubscription();
- method public int getResult();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.euicc.GetDownloadableSubscriptionMetadataResult> CREATOR;
- }
-
- public final class GetEuiccProfileInfoListResult implements android.os.Parcelable {
- ctor public GetEuiccProfileInfoListResult(int, @Nullable android.service.euicc.EuiccProfileInfo[], boolean);
- method public int describeContents();
- method public boolean getIsRemovable();
- method @Nullable public java.util.List<android.service.euicc.EuiccProfileInfo> getProfiles();
- method public int getResult();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.euicc.GetEuiccProfileInfoListResult> CREATOR;
- }
-
-}
-
-package android.service.notification {
-
- public final class Adjustment implements android.os.Parcelable {
- ctor public Adjustment(String, String, android.os.Bundle, CharSequence, int);
- ctor public Adjustment(@NonNull String, @NonNull String, @NonNull android.os.Bundle, @NonNull CharSequence, @NonNull android.os.UserHandle);
- ctor protected Adjustment(android.os.Parcel);
- method public int describeContents();
- method @NonNull public CharSequence getExplanation();
- method @NonNull public String getKey();
- method @NonNull public String getPackage();
- method @NonNull public android.os.Bundle getSignals();
- method public int getUser();
- method @NonNull public android.os.UserHandle getUserHandle();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
- field public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions";
- field public static final String KEY_IMPORTANCE = "key_importance";
- field public static final String KEY_NOT_CONVERSATION = "key_not_conversation";
- field public static final String KEY_PEOPLE = "key_people";
- field public static final String KEY_RANKING_SCORE = "key_ranking_score";
- field public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
- field public static final String KEY_TEXT_REPLIES = "key_text_replies";
- field public static final String KEY_USER_SENTIMENT = "key_user_sentiment";
- }
-
- public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
- ctor public NotificationAssistantService();
- method public final void adjustNotification(@NonNull android.service.notification.Adjustment);
- method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
- method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
- method public void onAllowedAdjustmentsChanged();
- method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method public void onNotificationDirectReplied(@NonNull String);
- method @Nullable public abstract android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification);
- method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
- method public void onNotificationExpansionChanged(@NonNull String, boolean, boolean);
- method public abstract void onNotificationSnoozedUntilContext(@NonNull android.service.notification.StatusBarNotification, @NonNull String);
- method public void onNotificationVisibilityChanged(@NonNull String, boolean);
- method public void onNotificationsSeen(@NonNull java.util.List<java.lang.String>);
- method public void onPanelHidden();
- method public void onPanelRevealed(int);
- method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int);
- method public final void unsnoozeNotification(@NonNull String);
- field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
- field public static final int SOURCE_FROM_APP = 0; // 0x0
- field public static final int SOURCE_FROM_ASSISTANT = 1; // 0x1
- }
-
- public abstract class NotificationListenerService extends android.app.Service {
- method public void onNotificationRemoved(@NonNull android.service.notification.StatusBarNotification, @NonNull android.service.notification.NotificationListenerService.RankingMap, @NonNull android.service.notification.NotificationStats, int);
- }
-
- public final class NotificationStats implements android.os.Parcelable {
- ctor public NotificationStats();
- ctor protected NotificationStats(android.os.Parcel);
- method public int describeContents();
- method public int getDismissalSentiment();
- method public int getDismissalSurface();
- method public boolean hasDirectReplied();
- method public boolean hasExpanded();
- method public boolean hasInteracted();
- method public boolean hasSeen();
- method public boolean hasSnoozed();
- method public boolean hasViewedSettings();
- method public void setDirectReplied();
- method public void setDismissalSentiment(int);
- method public void setDismissalSurface(int);
- method public void setExpanded();
- method public void setSeen();
- method public void setSnoozed();
- method public void setViewedSettings();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.NotificationStats> CREATOR;
- field public static final int DISMISSAL_AOD = 2; // 0x2
- field public static final int DISMISSAL_NOT_DISMISSED = -1; // 0xffffffff
- field public static final int DISMISSAL_OTHER = 0; // 0x0
- field public static final int DISMISSAL_PEEK = 1; // 0x1
- field public static final int DISMISSAL_SHADE = 3; // 0x3
- field public static final int DISMISS_SENTIMENT_NEGATIVE = 0; // 0x0
- field public static final int DISMISS_SENTIMENT_NEUTRAL = 1; // 0x1
- field public static final int DISMISS_SENTIMENT_POSITIVE = 2; // 0x2
- field public static final int DISMISS_SENTIMENT_UNKNOWN = -1000; // 0xfffffc18
- }
-
- public final class SnoozeCriterion implements android.os.Parcelable {
- ctor public SnoozeCriterion(String, CharSequence, CharSequence);
- ctor protected SnoozeCriterion(android.os.Parcel);
- method public int describeContents();
- method public CharSequence getConfirmation();
- method public CharSequence getExplanation();
- method public String getId();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.SnoozeCriterion> CREATOR;
- }
-
-}
-
-package android.service.oemlock {
-
- public class OemLockManager {
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) public String getLockName();
- method @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) public boolean isOemUnlockAllowedByCarrier();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE) public boolean isOemUnlockAllowedByUser();
- method @RequiresPermission(android.Manifest.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE) public void setOemUnlockAllowedByCarrier(boolean, @Nullable byte[]);
- method @RequiresPermission(android.Manifest.permission.MANAGE_USER_OEM_UNLOCK_STATE) public void setOemUnlockAllowedByUser(boolean);
- }
-
-}
-
-package android.service.persistentdata {
-
- public class PersistentDataBlockManager {
- method @RequiresPermission("android.permission.ACCESS_PDB_STATE") public int getDataBlockSize();
- method @android.service.persistentdata.PersistentDataBlockManager.FlashLockState @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) public int getFlashLockState();
- method public long getMaximumDataBlockSize();
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_OEM_UNLOCK_STATE, "android.permission.OEM_UNLOCK_STATE"}) public boolean getOemUnlockEnabled();
- method public byte[] read();
- method @Deprecated @RequiresPermission("android.permission.OEM_UNLOCK_STATE") public void setOemUnlockEnabled(boolean);
- method @RequiresPermission("android.permission.OEM_UNLOCK_STATE") public void wipe();
- method public int write(byte[]);
- field public static final int FLASH_LOCK_LOCKED = 1; // 0x1
- field public static final int FLASH_LOCK_UNKNOWN = -1; // 0xffffffff
- field public static final int FLASH_LOCK_UNLOCKED = 0; // 0x0
- }
-
- @IntDef(prefix={"FLASH_LOCK_"}, value={android.service.persistentdata.PersistentDataBlockManager.FLASH_LOCK_UNKNOWN, android.service.persistentdata.PersistentDataBlockManager.FLASH_LOCK_LOCKED, android.service.persistentdata.PersistentDataBlockManager.FLASH_LOCK_UNLOCKED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PersistentDataBlockManager.FlashLockState {
- }
-
-}
-
-package android.service.quicksettings {
-
- public class TileService extends android.app.Service {
- method public final void setStatusIcon(android.graphics.drawable.Icon, String);
- }
-
-}
-
-package android.service.resolver {
-
- public abstract class ResolverRankerService extends android.app.Service {
- ctor public ResolverRankerService();
- method public android.os.IBinder onBind(android.content.Intent);
- method public void onPredictSharingProbabilities(java.util.List<android.service.resolver.ResolverTarget>);
- method public void onTrainRankingModel(java.util.List<android.service.resolver.ResolverTarget>, int);
- field public static final String BIND_PERMISSION = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
- field public static final String HOLD_PERMISSION = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE";
- field public static final String SERVICE_INTERFACE = "android.service.resolver.ResolverRankerService";
- }
-
- public final class ResolverTarget implements android.os.Parcelable {
- ctor public ResolverTarget();
- method public int describeContents();
- method public float getChooserScore();
- method public float getLaunchScore();
- method public float getRecencyScore();
- method public float getSelectProbability();
- method public float getTimeSpentScore();
- method public void setChooserScore(float);
- method public void setLaunchScore(float);
- method public void setRecencyScore(float);
- method public void setSelectProbability(float);
- method public void setTimeSpentScore(float);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.resolver.ResolverTarget> CREATOR;
- }
-
-}
-
-package android.service.settings.suggestions {
-
- public final class Suggestion implements android.os.Parcelable {
- method public int describeContents();
- method public int getFlags();
- method public android.graphics.drawable.Icon getIcon();
- method public String getId();
- method public android.app.PendingIntent getPendingIntent();
- method public CharSequence getSummary();
- method public CharSequence getTitle();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.settings.suggestions.Suggestion> CREATOR;
- field public static final int FLAG_HAS_BUTTON = 1; // 0x1
- }
-
- public static class Suggestion.Builder {
- ctor public Suggestion.Builder(String);
- method public android.service.settings.suggestions.Suggestion build();
- method public android.service.settings.suggestions.Suggestion.Builder setFlags(int);
- method public android.service.settings.suggestions.Suggestion.Builder setIcon(android.graphics.drawable.Icon);
- method public android.service.settings.suggestions.Suggestion.Builder setPendingIntent(android.app.PendingIntent);
- method public android.service.settings.suggestions.Suggestion.Builder setSummary(CharSequence);
- method public android.service.settings.suggestions.Suggestion.Builder setTitle(CharSequence);
- }
-
- public abstract class SuggestionService extends android.app.Service {
- ctor public SuggestionService();
- method public android.os.IBinder onBind(android.content.Intent);
- method public abstract java.util.List<android.service.settings.suggestions.Suggestion> onGetSuggestions();
- method public abstract void onSuggestionDismissed(android.service.settings.suggestions.Suggestion);
- method public abstract void onSuggestionLaunched(android.service.settings.suggestions.Suggestion);
- }
-
-}
-
-package android.service.storage {
-
- public abstract class ExternalStorageService extends android.app.Service {
- ctor public ExternalStorageService();
- method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method public abstract void onEndSession(@NonNull String) throws java.io.IOException;
- method public abstract void onStartSession(@NonNull String, int, @NonNull android.os.ParcelFileDescriptor, @NonNull java.io.File, @NonNull java.io.File) throws java.io.IOException;
- method public abstract void onVolumeStateChanged(@NonNull android.os.storage.StorageVolume) throws java.io.IOException;
- field public static final int FLAG_SESSION_ATTRIBUTE_INDEXABLE = 2; // 0x2
- field public static final int FLAG_SESSION_TYPE_FUSE = 1; // 0x1
- field public static final String SERVICE_INTERFACE = "android.service.storage.ExternalStorageService";
- }
-
-}
-
-package android.service.textclassifier {
-
- public abstract class TextClassifierService extends android.app.Service {
- ctor public TextClassifierService();
- method @NonNull public static android.view.textclassifier.TextClassifier getDefaultTextClassifierImplementation(@NonNull android.content.Context);
- method @Deprecated public final android.view.textclassifier.TextClassifier getLocalTextClassifier();
- method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method @MainThread public abstract void onClassifyText(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextClassification.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextClassification>);
- method public void onConnected();
- method @MainThread public void onCreateTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationContext, @NonNull android.view.textclassifier.TextClassificationSessionId);
- method @MainThread public void onDestroyTextClassificationSession(@NonNull android.view.textclassifier.TextClassificationSessionId);
- method @MainThread public void onDetectLanguage(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextLanguage.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLanguage>);
- method public void onDisconnected();
- method @MainThread public abstract void onGenerateLinks(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextLinks.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLinks>);
- method @Deprecated @MainThread public void onSelectionEvent(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.SelectionEvent);
- method @MainThread public void onSuggestConversationActions(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.ConversationActions.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.ConversationActions>);
- method @MainThread public abstract void onSuggestSelection(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextSelection.Request, @NonNull android.os.CancellationSignal, @NonNull android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextSelection>);
- method @MainThread public void onTextClassifierEvent(@Nullable android.view.textclassifier.TextClassificationSessionId, @NonNull android.view.textclassifier.TextClassifierEvent);
- field public static final String SERVICE_INTERFACE = "android.service.textclassifier.TextClassifierService";
- }
-
- public static interface TextClassifierService.Callback<T> {
- method public void onFailure(@NonNull CharSequence);
- method public void onSuccess(T);
- }
-
-}
-
-package android.service.trust {
-
- public class TrustAgentService extends android.app.Service {
- ctor public TrustAgentService();
- method public final void addEscrowToken(byte[], android.os.UserHandle);
- method @Deprecated public final void grantTrust(CharSequence, long, boolean);
- method public final void grantTrust(CharSequence, long, int);
- method public final void isEscrowTokenActive(long, android.os.UserHandle);
- method public final android.os.IBinder onBind(android.content.Intent);
- method public boolean onConfigure(java.util.List<android.os.PersistableBundle>);
- method public void onDeviceLocked();
- method public void onDeviceUnlockLockout(long);
- method public void onDeviceUnlocked();
- method public void onEscrowTokenAdded(byte[], long, android.os.UserHandle);
- method public void onEscrowTokenRemoved(long, boolean);
- method public void onEscrowTokenStateReceived(long, int);
- method public void onTrustTimeout();
- method public void onUnlockAttempt(boolean);
- method public final void removeEscrowToken(long, android.os.UserHandle);
- method public final void revokeTrust();
- method public final void setManagingTrust(boolean);
- method public final void showKeyguardErrorMessage(@NonNull CharSequence);
- method public final void unlockUserWithToken(long, byte[], android.os.UserHandle);
- field public static final int FLAG_GRANT_TRUST_DISMISS_KEYGUARD = 2; // 0x2
- field public static final int FLAG_GRANT_TRUST_INITIATED_BY_USER = 1; // 0x1
- field public static final String SERVICE_INTERFACE = "android.service.trust.TrustAgentService";
- field public static final int TOKEN_STATE_ACTIVE = 1; // 0x1
- field public static final int TOKEN_STATE_INACTIVE = 0; // 0x0
- field public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
- }
-
-}
-
-package android.service.voice {
-
- public class AlwaysOnHotwordDetector {
- method @Nullable public android.content.Intent createEnrollIntent();
- method @Nullable public android.content.Intent createReEnrollIntent();
- method @Nullable public android.content.Intent createUnEnrollIntent();
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public int getParameter(int);
- method public int getSupportedAudioCapabilities();
- method public int getSupportedRecognitionModes();
- method @Nullable @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public android.service.voice.AlwaysOnHotwordDetector.ModelParamRange queryParameter(int);
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public int setParameter(int, int);
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition(int);
- method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean stopRecognition();
- field public static final int AUDIO_CAPABILITY_ECHO_CANCELLATION = 1; // 0x1
- field public static final int AUDIO_CAPABILITY_NOISE_SUPPRESSION = 2; // 0x2
- field public static final int MODEL_PARAM_THRESHOLD_FACTOR = 0; // 0x0
- field public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 2; // 0x2
- field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1
- field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION = 4; // 0x4
- field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION = 8; // 0x8
- field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2
- field public static final int RECOGNITION_MODE_VOICE_TRIGGER = 1; // 0x1
- field public static final int STATE_HARDWARE_UNAVAILABLE = -2; // 0xfffffffe
- field public static final int STATE_KEYPHRASE_ENROLLED = 2; // 0x2
- field public static final int STATE_KEYPHRASE_UNENROLLED = 1; // 0x1
- field @Deprecated public static final int STATE_KEYPHRASE_UNSUPPORTED = -1; // 0xffffffff
- }
-
- public abstract static class AlwaysOnHotwordDetector.Callback {
- ctor public AlwaysOnHotwordDetector.Callback();
- method public abstract void onAvailabilityChanged(int);
- method public abstract void onDetected(@NonNull android.service.voice.AlwaysOnHotwordDetector.EventPayload);
- method public abstract void onError();
- method public abstract void onRecognitionPaused();
- method public abstract void onRecognitionResumed();
- }
-
- public static class AlwaysOnHotwordDetector.EventPayload {
- method @Nullable public android.media.AudioFormat getCaptureAudioFormat();
- method @Nullable public byte[] getTriggerAudio();
- }
-
- public static final class AlwaysOnHotwordDetector.ModelParamRange {
- method public int getEnd();
- method public int getStart();
- }
-
- public class VoiceInteractionService extends android.app.Service {
- method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
- method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
- }
-
-}
-
-package android.service.wallpaper {
-
- public class WallpaperService.Engine {
- method public boolean isInAmbientMode();
- method public void onAmbientModeChanged(boolean, long);
- }
-
-}
-
-package android.service.watchdog {
-
- public abstract class ExplicitHealthCheckService extends android.app.Service {
- ctor public ExplicitHealthCheckService();
- method public final void notifyHealthCheckPassed(@NonNull String);
- method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method public abstract void onCancelHealthCheck(@NonNull String);
- method @NonNull public abstract java.util.List<java.lang.String> onGetRequestedPackages();
- method @NonNull public abstract java.util.List<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> onGetSupportedPackages();
- method public abstract void onRequestHealthCheck(@NonNull String);
- field public static final String BIND_PERMISSION = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE";
- field public static final String SERVICE_INTERFACE = "android.service.watchdog.ExplicitHealthCheckService";
- }
-
- public static final class ExplicitHealthCheckService.PackageConfig implements android.os.Parcelable {
- ctor public ExplicitHealthCheckService.PackageConfig(@NonNull String, long);
- method public int describeContents();
- method public long getHealthCheckTimeoutMillis();
- method @NonNull public String getPackageName();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> CREATOR;
- }
-
-}
-
-package android.telecom {
-
- @Deprecated public class AudioState implements android.os.Parcelable {
- ctor @Deprecated public AudioState(boolean, int, int);
- ctor @Deprecated public AudioState(android.telecom.AudioState);
- ctor @Deprecated public AudioState(android.telecom.CallAudioState);
- method @Deprecated public static String audioRouteToString(int);
- method @Deprecated public int describeContents();
- method @Deprecated public int getRoute();
- method @Deprecated public int getSupportedRouteMask();
- method @Deprecated public boolean isMuted();
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.telecom.AudioState> CREATOR;
- field @Deprecated public static final int ROUTE_BLUETOOTH = 2; // 0x2
- field @Deprecated public static final int ROUTE_EARPIECE = 1; // 0x1
- field @Deprecated public static final int ROUTE_SPEAKER = 8; // 0x8
- field @Deprecated public static final int ROUTE_WIRED_HEADSET = 4; // 0x4
- field @Deprecated public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
- }
-
- public final class Call {
- method @Deprecated public void addListener(android.telecom.Call.Listener);
- method public void enterBackgroundAudioProcessing();
- method public void exitBackgroundAudioProcessing(boolean);
- method @Deprecated public void removeListener(android.telecom.Call.Listener);
- field @Deprecated public static final int STATE_PRE_DIAL_WAIT = 8; // 0x8
- }
-
- @Deprecated public abstract static class Call.Listener extends android.telecom.Call.Callback {
- ctor @Deprecated public Call.Listener();
- }
-
- public static class CallScreeningService.CallResponse.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallViaAudioProcessing(boolean);
- }
-
- public abstract class Conference extends android.telecom.Conferenceable {
- method @Deprecated public final android.telecom.AudioState getAudioState();
- method @Deprecated public final long getConnectTimeMillis();
- method public android.telecom.Connection getPrimaryConnection();
- method @NonNull public final String getTelecomCallId();
- method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setAddress(@NonNull android.net.Uri, int);
- method public final void setCallerDisplayName(@NonNull String, int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setConferenceState(boolean);
- method @Deprecated public final void setConnectTimeMillis(long);
- }
-
- public abstract class Connection extends android.telecom.Conferenceable {
- method @Deprecated public final android.telecom.AudioState getAudioState();
- method @IntRange(from=0) public final long getConnectTimeMillis();
- method public final long getConnectionStartElapsedRealtimeMillis();
- method @Nullable public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
- method @Nullable public final String getTelecomCallId();
- method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
- method public final void resetConnectionTime();
- method public void setCallDirection(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setConnectTimeMillis(@IntRange(from=0) long);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public final void setConnectionStartElapsedRealtimeMillis(long);
- method public void setPhoneAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
- method public void setTelecomCallId(@NonNull String);
- field public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 2097152; // 0x200000
- field public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 262144; // 0x40000
- field public static final String EXTRA_DISABLE_ADD_CALL = "android.telecom.extra.DISABLE_ADD_CALL";
- field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1; // 0x1
- field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
- field public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 64; // 0x40
- field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
- }
-
- public final class ConnectionRequest implements android.os.Parcelable {
- method @Nullable public String getTelecomCallId();
- }
-
- public abstract class ConnectionService extends android.app.Service {
- method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
- }
-
- public abstract class InCallService extends android.app.Service {
- method @Deprecated public android.telecom.Phone getPhone();
- method @Deprecated public void onPhoneCreated(android.telecom.Phone);
- method @Deprecated public void onPhoneDestroyed(android.telecom.Phone);
- }
-
- public class ParcelableCallAnalytics implements android.os.Parcelable {
- ctor public ParcelableCallAnalytics(long, long, int, boolean, boolean, int, int, boolean, String, boolean, java.util.List<android.telecom.ParcelableCallAnalytics.AnalyticsEvent>, java.util.List<android.telecom.ParcelableCallAnalytics.EventTiming>);
- ctor public ParcelableCallAnalytics(android.os.Parcel);
- method public java.util.List<android.telecom.ParcelableCallAnalytics.AnalyticsEvent> analyticsEvents();
- method public int describeContents();
- method public long getCallDurationMillis();
- method public int getCallTechnologies();
- method public int getCallTerminationCode();
- method public int getCallType();
- method public String getConnectionService();
- method public java.util.List<android.telecom.ParcelableCallAnalytics.EventTiming> getEventTimings();
- method public long getStartTimeMillis();
- method public boolean isAdditionalCall();
- method public boolean isCreatedFromExistingConnection();
- method public boolean isEmergencyCall();
- method public boolean isInterrupted();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CALLTYPE_INCOMING = 1; // 0x1
- field public static final int CALLTYPE_OUTGOING = 2; // 0x2
- field public static final int CALLTYPE_UNKNOWN = 0; // 0x0
- field public static final int CDMA_PHONE = 1; // 0x1
- field @NonNull public static final android.os.Parcelable.Creator<android.telecom.ParcelableCallAnalytics> CREATOR;
- field public static final int GSM_PHONE = 2; // 0x2
- field public static final int IMS_PHONE = 4; // 0x4
- field public static final long MILLIS_IN_1_SECOND = 1000L; // 0x3e8L
- field public static final long MILLIS_IN_5_MINUTES = 300000L; // 0x493e0L
- field public static final int SIP_PHONE = 8; // 0x8
- field public static final int STILL_CONNECTED = -1; // 0xffffffff
- field public static final int THIRD_PARTY_PHONE = 16; // 0x10
- }
-
- public static final class ParcelableCallAnalytics.AnalyticsEvent implements android.os.Parcelable {
- ctor public ParcelableCallAnalytics.AnalyticsEvent(int, long);
- method public int describeContents();
- method public int getEventName();
- method public long getTimeSinceLastEvent();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int AUDIO_ROUTE_BT = 204; // 0xcc
- field public static final int AUDIO_ROUTE_EARPIECE = 205; // 0xcd
- field public static final int AUDIO_ROUTE_HEADSET = 206; // 0xce
- field public static final int AUDIO_ROUTE_SPEAKER = 207; // 0xcf
- field public static final int BIND_CS = 5; // 0x5
- field public static final int BLOCK_CHECK_FINISHED = 105; // 0x69
- field public static final int BLOCK_CHECK_INITIATED = 104; // 0x68
- field public static final int CONFERENCE_WITH = 300; // 0x12c
- field @NonNull public static final android.os.Parcelable.Creator<android.telecom.ParcelableCallAnalytics.AnalyticsEvent> CREATOR;
- field public static final int CS_BOUND = 6; // 0x6
- field public static final int DIRECT_TO_VM_FINISHED = 103; // 0x67
- field public static final int DIRECT_TO_VM_INITIATED = 102; // 0x66
- field public static final int FILTERING_COMPLETED = 107; // 0x6b
- field public static final int FILTERING_INITIATED = 106; // 0x6a
- field public static final int FILTERING_TIMED_OUT = 108; // 0x6c
- field public static final int MUTE = 202; // 0xca
- field public static final int REMOTELY_HELD = 402; // 0x192
- field public static final int REMOTELY_UNHELD = 403; // 0x193
- field public static final int REQUEST_ACCEPT = 7; // 0x7
- field public static final int REQUEST_HOLD = 400; // 0x190
- field public static final int REQUEST_PULL = 500; // 0x1f4
- field public static final int REQUEST_REJECT = 8; // 0x8
- field public static final int REQUEST_UNHOLD = 401; // 0x191
- field public static final int SCREENING_COMPLETED = 101; // 0x65
- field public static final int SCREENING_SENT = 100; // 0x64
- field public static final int SET_ACTIVE = 1; // 0x1
- field public static final int SET_DIALING = 4; // 0x4
- field public static final int SET_DISCONNECTED = 2; // 0x2
- field public static final int SET_HOLD = 404; // 0x194
- field public static final int SET_PARENT = 302; // 0x12e
- field public static final int SET_SELECT_PHONE_ACCOUNT = 0; // 0x0
- field public static final int SILENCE = 201; // 0xc9
- field public static final int SKIP_RINGING = 200; // 0xc8
- field public static final int SPLIT_CONFERENCE = 301; // 0x12d
- field public static final int START_CONNECTION = 3; // 0x3
- field public static final int SWAP = 405; // 0x195
- field public static final int UNMUTE = 203; // 0xcb
- }
-
- public static final class ParcelableCallAnalytics.EventTiming implements android.os.Parcelable {
- ctor public ParcelableCallAnalytics.EventTiming(int, long);
- method public int describeContents();
- method public int getName();
- method public long getTime();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int ACCEPT_TIMING = 0; // 0x0
- field public static final int BIND_CS_TIMING = 6; // 0x6
- field public static final int BLOCK_CHECK_FINISHED_TIMING = 9; // 0x9
- field @NonNull public static final android.os.Parcelable.Creator<android.telecom.ParcelableCallAnalytics.EventTiming> CREATOR;
- field public static final int DIRECT_TO_VM_FINISHED_TIMING = 8; // 0x8
- field public static final int DISCONNECT_TIMING = 2; // 0x2
- field public static final int FILTERING_COMPLETED_TIMING = 10; // 0xa
- field public static final int FILTERING_TIMED_OUT_TIMING = 11; // 0xb
- field public static final int HOLD_TIMING = 3; // 0x3
- field public static final int INVALID = 999999; // 0xf423f
- field public static final int OUTGOING_TIME_TO_DIALING_TIMING = 5; // 0x5
- field public static final int REJECT_TIMING = 1; // 0x1
- field public static final int SCREENING_COMPLETED_TIMING = 7; // 0x7
- field public static final int UNHOLD_TIMING = 4; // 0x4
- }
-
- @Deprecated public final class Phone {
- method @Deprecated public void addListener(android.telecom.Phone.Listener);
- method @Deprecated public boolean canAddCall();
- method @Deprecated public android.telecom.AudioState getAudioState();
- method @Deprecated public android.telecom.CallAudioState getCallAudioState();
- method @Deprecated public java.util.List<android.telecom.Call> getCalls();
- method @Deprecated public void removeListener(android.telecom.Phone.Listener);
- method @Deprecated public void requestBluetoothAudio(String);
- method @Deprecated public void setAudioRoute(int);
- method @Deprecated public void setMuted(boolean);
- }
-
- @Deprecated public abstract static class Phone.Listener {
- ctor @Deprecated public Phone.Listener();
- method @Deprecated public void onAudioStateChanged(android.telecom.Phone, android.telecom.AudioState);
- method @Deprecated public void onBringToForeground(android.telecom.Phone, boolean);
- method @Deprecated public void onCallAdded(android.telecom.Phone, android.telecom.Call);
- method @Deprecated public void onCallAudioStateChanged(android.telecom.Phone, android.telecom.CallAudioState);
- method @Deprecated public void onCallRemoved(android.telecom.Phone, android.telecom.Call);
- method @Deprecated public void onCanAddCallChanged(android.telecom.Phone, boolean);
- method @Deprecated public void onSilenceRinger(android.telecom.Phone);
- }
-
- public final class PhoneAccount implements android.os.Parcelable {
- field public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 128; // 0x80
- field public static final int CAPABILITY_EMERGENCY_PREFERRED = 8192; // 0x2000
- field public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 512; // 0x200
- field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
- field public static final String EXTRA_PLAY_CALL_RECORDING_TONE = "android.telecom.extra.PLAY_CALL_RECORDING_TONE";
- field public static final String EXTRA_SORT_ORDER = "android.telecom.extra.SORT_ORDER";
- }
-
- public static class PhoneAccount.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telecom.PhoneAccount.Builder setGroupId(@NonNull String);
- }
-
- public class PhoneAccountSuggestionService extends android.app.Service {
- ctor public PhoneAccountSuggestionService();
- method public void onAccountSuggestionRequest(@NonNull String);
- method public android.os.IBinder onBind(android.content.Intent);
- method public final void suggestPhoneAccounts(@NonNull String, @NonNull java.util.List<android.telecom.PhoneAccountSuggestion>);
- field public static final String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
- }
-
- public final class RemoteConference {
- method @Deprecated public void setAudioState(android.telecom.AudioState);
- }
-
- public final class RemoteConnection {
- method @Deprecated public void setAudioState(android.telecom.AudioState);
- }
-
- public final class StatusHints implements android.os.Parcelable {
- ctor @Deprecated public StatusHints(android.content.ComponentName, CharSequence, int, android.os.Bundle);
- method @Deprecated public android.graphics.drawable.Drawable getIcon(android.content.Context);
- method @Deprecated public int getIconResId();
- method @Deprecated public android.content.ComponentName getPackageName();
- }
-
- public final class TelecomAnalytics implements android.os.Parcelable {
- ctor public TelecomAnalytics(java.util.List<android.telecom.TelecomAnalytics.SessionTiming>, java.util.List<android.telecom.ParcelableCallAnalytics>);
- method public int describeContents();
- method public java.util.List<android.telecom.ParcelableCallAnalytics> getCallAnalytics();
- method public java.util.List<android.telecom.TelecomAnalytics.SessionTiming> getSessionTimings();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telecom.TelecomAnalytics> CREATOR;
- }
-
- public static final class TelecomAnalytics.SessionTiming implements android.os.Parcelable {
- ctor public TelecomAnalytics.SessionTiming(int, long);
- method public int describeContents();
- method public Integer getKey();
- method public long getTime();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telecom.TelecomAnalytics.SessionTiming> CREATOR;
- field public static final int CSW_ADD_CONFERENCE_CALL = 108; // 0x6c
- field public static final int CSW_HANDLE_CREATE_CONNECTION_COMPLETE = 100; // 0x64
- field public static final int CSW_REMOVE_CALL = 106; // 0x6a
- field public static final int CSW_SET_ACTIVE = 101; // 0x65
- field public static final int CSW_SET_DIALING = 103; // 0x67
- field public static final int CSW_SET_DISCONNECTED = 104; // 0x68
- field public static final int CSW_SET_IS_CONFERENCED = 107; // 0x6b
- field public static final int CSW_SET_ON_HOLD = 105; // 0x69
- field public static final int CSW_SET_RINGING = 102; // 0x66
- field public static final int ICA_ANSWER_CALL = 1; // 0x1
- field public static final int ICA_CONFERENCE = 8; // 0x8
- field public static final int ICA_DISCONNECT_CALL = 3; // 0x3
- field public static final int ICA_HOLD_CALL = 4; // 0x4
- field public static final int ICA_MUTE = 6; // 0x6
- field public static final int ICA_REJECT_CALL = 2; // 0x2
- field public static final int ICA_SET_AUDIO_ROUTE = 7; // 0x7
- field public static final int ICA_UNHOLD_CALL = 5; // 0x5
- }
-
- public class TelecomManager {
- method public void addNewUnknownCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
- method @Deprecated public void clearAccounts();
- method public void clearPhoneAccounts();
- method @NonNull public android.content.Intent createLaunchEmergencyDialerIntent(@Nullable String);
- method @RequiresPermission(android.Manifest.permission.DUMP) public android.telecom.TelecomAnalytics dumpAnalytics();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
- method public java.util.List<android.telecom.PhoneAccountHandle> getAllPhoneAccountHandles();
- method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts();
- method public int getAllPhoneAccountsCount();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
- method public int getCallState();
- method public android.telecom.PhoneAccountHandle getConnectionManager();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode();
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultDialerPackage(@NonNull android.os.UserHandle);
- method @Deprecated public android.content.ComponentName getDefaultPhoneApp();
- method @Deprecated public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
- method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
- method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle);
- field public static final String ACTION_CURRENT_TTY_MODE_CHANGED = "android.telecom.action.CURRENT_TTY_MODE_CHANGED";
- field public static final String ACTION_TTY_PREFERRED_MODE_CHANGED = "android.telecom.action.TTY_PREFERRED_MODE_CHANGED";
- field public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1; // 0x1
- field public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; // 0x2
- field public static final int CALL_SOURCE_UNSPECIFIED = 0; // 0x0
- field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
- field public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
- field public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE";
- field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
- field public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE";
- field public static final String EXTRA_CURRENT_TTY_MODE = "android.telecom.extra.CURRENT_TTY_MODE";
- field public static final String EXTRA_IS_USER_INTENT_EMERGENCY_CALL = "android.telecom.extra.IS_USER_INTENT_EMERGENCY_CALL";
- field public static final String EXTRA_TTY_PREFERRED_MODE = "android.telecom.extra.TTY_PREFERRED_MODE";
- field public static final String EXTRA_UNKNOWN_CALL_HANDLE = "android.telecom.extra.UNKNOWN_CALL_HANDLE";
- field public static final int TTY_MODE_FULL = 1; // 0x1
- field public static final int TTY_MODE_HCO = 2; // 0x2
- field public static final int TTY_MODE_OFF = 0; // 0x0
- field public static final int TTY_MODE_VCO = 3; // 0x3
- }
-
-}
-
-package android.telephony {
-
- public final class AccessNetworkConstants {
- field public static final int TRANSPORT_TYPE_INVALID = -1; // 0xffffffff
- }
-
- public static final class AccessNetworkConstants.NgranBands {
- method public static int getFrequencyRangeGroup(int);
- field public static final int FREQUENCY_RANGE_GROUP_1 = 1; // 0x1
- field public static final int FREQUENCY_RANGE_GROUP_2 = 2; // 0x2
- field public static final int FREQUENCY_RANGE_GROUP_UNKNOWN = 0; // 0x0
- }
-
- public final class BarringInfo implements android.os.Parcelable {
- ctor public BarringInfo();
- method @NonNull public android.telephony.BarringInfo createLocationInfoSanitizedCopy();
- }
-
- public final class CallAttributes implements android.os.Parcelable {
- ctor public CallAttributes(@NonNull android.telephony.PreciseCallState, int, @NonNull android.telephony.CallQuality);
- method public int describeContents();
- method @NonNull public android.telephony.CallQuality getCallQuality();
- method public int getNetworkType();
- method @NonNull public android.telephony.PreciseCallState getPreciseCallState();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR;
- }
-
- public final class CallForwardingInfo implements android.os.Parcelable {
- ctor public CallForwardingInfo(boolean, int, @Nullable String, int);
- method public int describeContents();
- method @Nullable public String getNumber();
- method public int getReason();
- method public int getTimeoutSeconds();
- method public boolean isEnabled();
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallForwardingInfo> CREATOR;
- field public static final int REASON_ALL = 4; // 0x4
- field public static final int REASON_ALL_CONDITIONAL = 5; // 0x5
- field public static final int REASON_BUSY = 1; // 0x1
- field public static final int REASON_NOT_REACHABLE = 3; // 0x3
- field public static final int REASON_NO_REPLY = 2; // 0x2
- field public static final int REASON_UNCONDITIONAL = 0; // 0x0
- }
-
- public final class CallQuality implements android.os.Parcelable {
- ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int);
- ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int, boolean, boolean, boolean);
- method public int describeContents();
- method public int getAverageRelativeJitter();
- method public int getAverageRoundTripTime();
- method public int getCallDuration();
- method public int getCodecType();
- method public int getDownlinkCallQualityLevel();
- method public int getMaxRelativeJitter();
- method public int getNumRtpPacketsNotReceived();
- method public int getNumRtpPacketsReceived();
- method public int getNumRtpPacketsTransmitted();
- method public int getNumRtpPacketsTransmittedLost();
- method public int getUplinkCallQualityLevel();
- method public boolean isIncomingSilenceDetectedAtCallSetup();
- method public boolean isOutgoingSilenceDetectedAtCallSetup();
- method public boolean isRtpInactivityDetected();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CALL_QUALITY_BAD = 4; // 0x4
- field public static final int CALL_QUALITY_EXCELLENT = 0; // 0x0
- field public static final int CALL_QUALITY_FAIR = 2; // 0x2
- field public static final int CALL_QUALITY_GOOD = 1; // 0x1
- field public static final int CALL_QUALITY_NOT_AVAILABLE = 5; // 0x5
- field public static final int CALL_QUALITY_POOR = 3; // 0x3
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallQuality> CREATOR;
- }
-
- public class CarrierConfigManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultCarrierServicePackageName();
- method @NonNull public static android.os.PersistableBundle getDefaultConfig();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void overrideConfig(int, @Nullable android.os.PersistableBundle);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void updateConfigForPhoneId(int, String);
- field public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
- field public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool";
- }
-
- public static final class CarrierConfigManager.Wifi {
- field public static final String KEY_HOTSPOT_MAX_CLIENT_COUNT = "wifi.hotspot_maximum_client_count";
- field public static final String KEY_PREFIX = "wifi.";
- }
-
- public final class CarrierRestrictionRules implements android.os.Parcelable {
- method @NonNull public java.util.List<java.lang.Boolean> areCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
- method public int describeContents();
- method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers();
- method public int getDefaultCarrierRestriction();
- method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers();
- method public int getMultiSimPolicy();
- method public boolean isAllCarriersAllowed();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1; // 0x1
- field public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0; // 0x0
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CarrierRestrictionRules> CREATOR;
- field public static final int MULTISIM_POLICY_NONE = 0; // 0x0
- field public static final int MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT = 1; // 0x1
- }
-
- public static final class CarrierRestrictionRules.Builder {
- ctor public CarrierRestrictionRules.Builder();
- method @NonNull public android.telephony.CarrierRestrictionRules build();
- method @NonNull public android.telephony.CarrierRestrictionRules.Builder setAllCarriersAllowed();
- method @NonNull public android.telephony.CarrierRestrictionRules.Builder setAllowedCarriers(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
- method @NonNull public android.telephony.CarrierRestrictionRules.Builder setDefaultCarrierRestriction(int);
- method @NonNull public android.telephony.CarrierRestrictionRules.Builder setExcludedCarriers(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
- method @NonNull public android.telephony.CarrierRestrictionRules.Builder setMultiSimPolicy(int);
- }
-
- public class CbGeoUtils {
- }
-
- public static class CbGeoUtils.Circle implements android.telephony.CbGeoUtils.Geometry {
- ctor public CbGeoUtils.Circle(@NonNull android.telephony.CbGeoUtils.LatLng, double);
- method public boolean contains(@NonNull android.telephony.CbGeoUtils.LatLng);
- method @NonNull public android.telephony.CbGeoUtils.LatLng getCenter();
- method public double getRadius();
- }
-
- public static interface CbGeoUtils.Geometry {
- method public boolean contains(@NonNull android.telephony.CbGeoUtils.LatLng);
- }
-
- public static class CbGeoUtils.LatLng {
- ctor public CbGeoUtils.LatLng(double, double);
- method public double distance(@NonNull android.telephony.CbGeoUtils.LatLng);
- method @NonNull public android.telephony.CbGeoUtils.LatLng subtract(@NonNull android.telephony.CbGeoUtils.LatLng);
- field public final double lat;
- field public final double lng;
- }
-
- public static class CbGeoUtils.Polygon implements android.telephony.CbGeoUtils.Geometry {
- ctor public CbGeoUtils.Polygon(@NonNull java.util.List<android.telephony.CbGeoUtils.LatLng>);
- method public boolean contains(@NonNull android.telephony.CbGeoUtils.LatLng);
- method @NonNull public java.util.List<android.telephony.CbGeoUtils.LatLng> getVertices();
- }
-
- 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";
- }
-
- public abstract class CellBroadcastService extends android.app.Service {
- ctor public CellBroadcastService();
- method @NonNull @WorkerThread public abstract CharSequence getCellBroadcastAreaInfo(int);
- method @CallSuper public android.os.IBinder onBind(@Nullable android.content.Intent);
- method public abstract void onCdmaCellBroadcastSms(int, @NonNull byte[], int);
- method public abstract void onCdmaScpMessage(int, @NonNull java.util.List<android.telephony.cdma.CdmaSmsCbProgramData>, @NonNull String, @NonNull java.util.function.Consumer<android.os.Bundle>);
- method public abstract void onGsmCellBroadcastSms(int, @NonNull byte[]);
- field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService";
- }
-
- public abstract class CellIdentity implements android.os.Parcelable {
- method @NonNull public abstract android.telephony.CellLocation asCellLocation();
- method @NonNull public abstract android.telephony.CellIdentity sanitizeLocationInfo();
- }
-
- public final class CellIdentityCdma extends android.telephony.CellIdentity {
- method @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation();
- method @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo();
- }
-
- public final class CellIdentityGsm extends android.telephony.CellIdentity {
- method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
- method @NonNull public android.telephony.CellIdentityGsm sanitizeLocationInfo();
- }
-
- public final class CellIdentityLte extends android.telephony.CellIdentity {
- method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
- method @NonNull public android.telephony.CellIdentityLte sanitizeLocationInfo();
- }
-
- public final class CellIdentityNr extends android.telephony.CellIdentity {
- method @NonNull public android.telephony.CellLocation asCellLocation();
- method @NonNull public android.telephony.CellIdentityNr sanitizeLocationInfo();
- }
-
- public final class CellIdentityTdscdma extends android.telephony.CellIdentity {
- method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
- method @NonNull public android.telephony.CellIdentityTdscdma sanitizeLocationInfo();
- }
-
- public final class CellIdentityWcdma extends android.telephony.CellIdentity {
- method @NonNull public android.telephony.gsm.GsmCellLocation asCellLocation();
- method @NonNull public android.telephony.CellIdentityWcdma sanitizeLocationInfo();
- }
-
- public final class DataFailCause {
- field @Deprecated public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be
- }
-
- public final class DataSpecificRegistrationInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationInfo> CREATOR;
- }
-
- public final class ImsiEncryptionInfo implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public String getKeyIdentifier();
- method @Nullable public java.security.PublicKey getPublicKey();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ImsiEncryptionInfo> CREATOR;
- }
-
- public final class LteVopsSupportInfo implements android.os.Parcelable {
- ctor public LteVopsSupportInfo(int, int);
- method public int describeContents();
- method public int getEmcBearerSupport();
- method public int getVopsSupport();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.LteVopsSupportInfo> CREATOR;
- field public static final int LTE_STATUS_NOT_AVAILABLE = 1; // 0x1
- field public static final int LTE_STATUS_NOT_SUPPORTED = 3; // 0x3
- field public static final int LTE_STATUS_SUPPORTED = 2; // 0x2
- }
-
- public class MbmsDownloadSession implements java.lang.AutoCloseable {
- field public static final String MBMS_DOWNLOAD_SERVICE_ACTION = "android.telephony.action.EmbmsDownload";
- }
-
- public class MbmsGroupCallSession implements java.lang.AutoCloseable {
- field public static final String MBMS_GROUP_CALL_SERVICE_ACTION = "android.telephony.action.EmbmsGroupCall";
- }
-
- public class MbmsStreamingSession implements java.lang.AutoCloseable {
- field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
- }
-
- public final class ModemActivityInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
- method public long getIdleTimeMillis();
- method public static int getNumTxPowerLevels();
- method public long getReceiveTimeMillis();
- method public long getSleepTimeMillis();
- method public long getTimestampMillis();
- method public long getTransmitDurationMillisAtPowerLevel(int);
- method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
- field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
- field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
- field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
- field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
- field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
- }
-
- public final class NetworkRegistrationInfo implements android.os.Parcelable {
- method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
- method public int getRegistrationState();
- method public int getRejectCause();
- method public int getRoamingType();
- method public boolean isEmergencyEnabled();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3
- field public static final int REGISTRATION_STATE_HOME = 1; // 0x1
- field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0
- field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2
- field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5
- field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4
- }
-
- public static final class NetworkRegistrationInfo.Builder {
- ctor public NetworkRegistrationInfo.Builder();
- method @NonNull public android.telephony.NetworkRegistrationInfo build();
- method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAccessNetworkTechnology(int);
- method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAvailableServices(@NonNull java.util.List<java.lang.Integer>);
- method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setCellIdentity(@Nullable android.telephony.CellIdentity);
- method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setDomain(int);
- method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setEmergencyOnly(boolean);
- method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegisteredPlmn(@Nullable String);
- method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegistrationState(int);
- method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRejectCause(int);
- method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setTransportType(int);
- }
-
- public abstract class NetworkService extends android.app.Service {
- ctor public NetworkService();
- method public android.os.IBinder onBind(android.content.Intent);
- method @Nullable public abstract android.telephony.NetworkService.NetworkServiceProvider onCreateNetworkServiceProvider(int);
- field public static final String SERVICE_INTERFACE = "android.telephony.NetworkService";
- }
-
- public abstract class NetworkService.NetworkServiceProvider implements java.lang.AutoCloseable {
- ctor public NetworkService.NetworkServiceProvider(int);
- method public abstract void close();
- method public final int getSlotIndex();
- method public final void notifyNetworkRegistrationInfoChanged();
- method public void requestNetworkRegistrationInfo(int, @NonNull android.telephony.NetworkServiceCallback);
- }
-
- public class NetworkServiceCallback {
- method public void onRequestNetworkRegistrationInfoComplete(int, @Nullable android.telephony.NetworkRegistrationInfo);
- field public static final int RESULT_ERROR_BUSY = 3; // 0x3
- field public static final int RESULT_ERROR_FAILED = 5; // 0x5
- field public static final int RESULT_ERROR_ILLEGAL_STATE = 4; // 0x4
- field public static final int RESULT_ERROR_INVALID_ARG = 2; // 0x2
- field public static final int RESULT_ERROR_UNSUPPORTED = 1; // 0x1
- field public static final int RESULT_SUCCESS = 0; // 0x0
- }
-
- public interface NumberVerificationCallback {
- method public default void onCallReceived(@NonNull String);
- method public default void onVerificationFailed(int);
- field public static final int REASON_CONCURRENT_REQUESTS = 4; // 0x4
- field public static final int REASON_IN_ECBM = 5; // 0x5
- field public static final int REASON_IN_EMERGENCY_CALL = 6; // 0x6
- field public static final int REASON_NETWORK_NOT_AVAILABLE = 2; // 0x2
- field public static final int REASON_TIMED_OUT = 1; // 0x1
- field public static final int REASON_TOO_MANY_CALLS = 3; // 0x3
- field public static final int REASON_UNSPECIFIED = 0; // 0x0
- }
-
- public final class PhoneNumberRange implements android.os.Parcelable {
- ctor public PhoneNumberRange(@NonNull String, @NonNull String, @NonNull String, @NonNull String);
- method public int describeContents();
- method public boolean matches(@NonNull String);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhoneNumberRange> CREATOR;
- }
-
- public class PhoneNumberUtils {
- method @NonNull public static String getUsernameFromUriNumber(@NonNull String);
- method public static boolean isUriNumber(@Nullable String);
- method public static boolean isVoiceMailNumber(@NonNull android.content.Context, int, @Nullable String);
- }
-
- public class PhoneStateListener {
- method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
- method @Deprecated public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
- method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
- method @Deprecated public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
- method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber, int);
- method public void onPhysicalChannelConfigurationChanged(@NonNull java.util.List<android.telephony.PhysicalChannelConfig>);
- method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
- method public void onRadioPowerStateChanged(int);
- method public void onSrvccStateChanged(int);
- method public void onVoiceActivationStateChanged(int);
- field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
- field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
- field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
- field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final long LISTEN_PHYSICAL_CHANNEL_CONFIGURATION = 4294967296L; // 0x100000000L
- field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
- field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
- field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
- field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
- }
-
- public final class PhysicalChannelConfig implements android.os.Parcelable {
- method public int describeContents();
- method public int getCellBandwidthDownlink();
- method public int getChannelNumber();
- method public int getConnectionStatus();
- method public int getNetworkType();
- method @IntRange(from=0, to=1007) public int getPhysicalCellId();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int CHANNEL_NUMBER_UNKNOWN = -1; // 0xffffffff
- field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1
- field public static final int CONNECTION_SECONDARY_SERVING = 2; // 0x2
- field public static final int CONNECTION_UNKNOWN = -1; // 0xffffffff
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhysicalChannelConfig> CREATOR;
- field public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; // 0xffffffff
- }
-
- public final class PreciseCallState implements android.os.Parcelable {
- ctor public PreciseCallState(int, int, int, int, int);
- method public int describeContents();
- method public int getBackgroundCallState();
- method public int getForegroundCallState();
- method public int getRingingCallState();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PreciseCallState> CREATOR;
- field public static final int PRECISE_CALL_STATE_ACTIVE = 1; // 0x1
- field public static final int PRECISE_CALL_STATE_ALERTING = 4; // 0x4
- field public static final int PRECISE_CALL_STATE_DIALING = 3; // 0x3
- field public static final int PRECISE_CALL_STATE_DISCONNECTED = 7; // 0x7
- field public static final int PRECISE_CALL_STATE_DISCONNECTING = 8; // 0x8
- field public static final int PRECISE_CALL_STATE_HOLDING = 2; // 0x2
- field public static final int PRECISE_CALL_STATE_IDLE = 0; // 0x0
- field public static final int PRECISE_CALL_STATE_INCOMING = 5; // 0x5
- field public static final int PRECISE_CALL_STATE_NOT_VALID = -1; // 0xffffffff
- field public static final int PRECISE_CALL_STATE_WAITING = 6; // 0x6
- }
-
- public final class PreciseDataConnectionState implements android.os.Parcelable {
- method @Deprecated @NonNull public String getDataConnectionApn();
- method @Deprecated public int getDataConnectionApnTypeBitMask();
- method @Deprecated public int getDataConnectionFailCause();
- method @Deprecated public int getDataConnectionState();
- method public int getId();
- }
-
- public final class PreciseDisconnectCause {
- field public static final int ACCESS_CLASS_BLOCKED = 260; // 0x104
- field public static final int ACCESS_INFORMATION_DISCARDED = 43; // 0x2b
- field public static final int ACM_LIMIT_EXCEEDED = 68; // 0x44
- field public static final int BEARER_CAPABILITY_NOT_AUTHORIZED = 57; // 0x39
- field public static final int BEARER_NOT_AVAIL = 58; // 0x3a
- field public static final int BEARER_SERVICE_NOT_IMPLEMENTED = 65; // 0x41
- field public static final int BUSY = 17; // 0x11
- field public static final int CALL_BARRED = 240; // 0xf0
- field public static final int CALL_REJECTED = 21; // 0x15
- field public static final int CDMA_ACCESS_BLOCKED = 1009; // 0x3f1
- field public static final int CDMA_ACCESS_FAILURE = 1006; // 0x3ee
- field public static final int CDMA_DROP = 1001; // 0x3e9
- field public static final int CDMA_INTERCEPT = 1002; // 0x3ea
- field public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; // 0x3e8
- field public static final int CDMA_NOT_EMERGENCY = 1008; // 0x3f0
- field public static final int CDMA_PREEMPTED = 1007; // 0x3ef
- field public static final int CDMA_REORDER = 1003; // 0x3eb
- field public static final int CDMA_RETRY_ORDER = 1005; // 0x3ed
- field public static final int CDMA_SO_REJECT = 1004; // 0x3ec
- field public static final int CHANNEL_NOT_AVAIL = 44; // 0x2c
- field public static final int CHANNEL_UNACCEPTABLE = 6; // 0x6
- field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64
- field public static final int DESTINATION_OUT_OF_ORDER = 27; // 0x1b
- field public static final int ERROR_UNSPECIFIED = 65535; // 0xffff
- field public static final int FACILITY_REJECTED = 29; // 0x1d
- field public static final int FDN_BLOCKED = 241; // 0xf1
- field public static final int IMEI_NOT_ACCEPTED = 243; // 0xf3
- field public static final int IMSI_UNKNOWN_IN_VLR = 242; // 0xf2
- field public static final int INCOMING_CALLS_BARRED_WITHIN_CUG = 55; // 0x37
- field public static final int INCOMPATIBLE_DESTINATION = 88; // 0x58
- field public static final int INFORMATION_ELEMENT_NON_EXISTENT = 99; // 0x63
- field public static final int INTERWORKING_UNSPECIFIED = 127; // 0x7f
- field public static final int INVALID_MANDATORY_INFORMATION = 96; // 0x60
- field public static final int INVALID_NUMBER_FORMAT = 28; // 0x1c
- field public static final int INVALID_TRANSACTION_IDENTIFIER = 81; // 0x51
- field public static final int MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101; // 0x65
- field public static final int MESSAGE_TYPE_NON_IMPLEMENTED = 97; // 0x61
- field public static final int MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98; // 0x62
- field public static final int NETWORK_DETACH = 261; // 0x105
- field public static final int NETWORK_OUT_OF_ORDER = 38; // 0x26
- field public static final int NETWORK_REJECT = 252; // 0xfc
- field public static final int NETWORK_RESP_TIMEOUT = 251; // 0xfb
- field public static final int NORMAL = 16; // 0x10
- field public static final int NORMAL_UNSPECIFIED = 31; // 0x1f
- field public static final int NOT_VALID = -1; // 0xffffffff
- field public static final int NO_ANSWER_FROM_USER = 19; // 0x13
- field public static final int NO_CIRCUIT_AVAIL = 34; // 0x22
- field public static final int NO_DISCONNECT_CAUSE_AVAILABLE = 0; // 0x0
- field public static final int NO_ROUTE_TO_DESTINATION = 3; // 0x3
- field public static final int NO_USER_RESPONDING = 18; // 0x12
- field public static final int NO_VALID_SIM = 249; // 0xf9
- field public static final int NUMBER_CHANGED = 22; // 0x16
- field public static final int OEM_CAUSE_1 = 61441; // 0xf001
- field public static final int OEM_CAUSE_10 = 61450; // 0xf00a
- field public static final int OEM_CAUSE_11 = 61451; // 0xf00b
- field public static final int OEM_CAUSE_12 = 61452; // 0xf00c
- field public static final int OEM_CAUSE_13 = 61453; // 0xf00d
- field public static final int OEM_CAUSE_14 = 61454; // 0xf00e
- field public static final int OEM_CAUSE_15 = 61455; // 0xf00f
- field public static final int OEM_CAUSE_2 = 61442; // 0xf002
- field public static final int OEM_CAUSE_3 = 61443; // 0xf003
- field public static final int OEM_CAUSE_4 = 61444; // 0xf004
- field public static final int OEM_CAUSE_5 = 61445; // 0xf005
- field public static final int OEM_CAUSE_6 = 61446; // 0xf006
- field public static final int OEM_CAUSE_7 = 61447; // 0xf007
- field public static final int OEM_CAUSE_8 = 61448; // 0xf008
- field public static final int OEM_CAUSE_9 = 61449; // 0xf009
- field public static final int ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70; // 0x46
- field public static final int OPERATOR_DETERMINED_BARRING = 8; // 0x8
- field public static final int OUT_OF_SRV = 248; // 0xf8
- field public static final int PREEMPTION = 25; // 0x19
- field public static final int PROTOCOL_ERROR_UNSPECIFIED = 111; // 0x6f
- field public static final int QOS_NOT_AVAIL = 49; // 0x31
- field public static final int RADIO_ACCESS_FAILURE = 253; // 0xfd
- field public static final int RADIO_INTERNAL_ERROR = 250; // 0xfa
- field public static final int RADIO_LINK_FAILURE = 254; // 0xfe
- field public static final int RADIO_LINK_LOST = 255; // 0xff
- field public static final int RADIO_OFF = 247; // 0xf7
- field public static final int RADIO_RELEASE_ABNORMAL = 259; // 0x103
- field public static final int RADIO_RELEASE_NORMAL = 258; // 0x102
- field public static final int RADIO_SETUP_FAILURE = 257; // 0x101
- field public static final int RADIO_UPLINK_FAILURE = 256; // 0x100
- field public static final int RECOVERY_ON_TIMER_EXPIRED = 102; // 0x66
- field public static final int REQUESTED_FACILITY_NOT_IMPLEMENTED = 69; // 0x45
- field public static final int REQUESTED_FACILITY_NOT_SUBSCRIBED = 50; // 0x32
- field public static final int RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 47; // 0x2f
- field public static final int SEMANTICALLY_INCORRECT_MESSAGE = 95; // 0x5f
- field public static final int SERVICE_OPTION_NOT_AVAILABLE = 63; // 0x3f
- field public static final int SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79; // 0x4f
- field public static final int STATUS_ENQUIRY = 30; // 0x1e
- field public static final int SWITCHING_CONGESTION = 42; // 0x2a
- field public static final int TEMPORARY_FAILURE = 41; // 0x29
- field public static final int UNOBTAINABLE_NUMBER = 1; // 0x1
- field public static final int USER_NOT_MEMBER_OF_CUG = 87; // 0x57
- }
-
- public class ServiceState implements android.os.Parcelable {
- method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int);
- method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int);
- method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForTransportType(int);
- field public static final int ROAMING_TYPE_DOMESTIC = 2; // 0x2
- field public static final int ROAMING_TYPE_INTERNATIONAL = 3; // 0x3
- field public static final int ROAMING_TYPE_NOT_ROAMING = 0; // 0x0
- field public static final int ROAMING_TYPE_UNKNOWN = 1; // 0x1
- }
-
- public final class SmsCbCmasInfo implements android.os.Parcelable {
- ctor public SmsCbCmasInfo(int, int, int, int, int, int);
- method public int describeContents();
- method public int getCategory();
- method public int getCertainty();
- method public int getMessageClass();
- method public int getResponseType();
- method public int getSeverity();
- method public int getUrgency();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CMAS_CATEGORY_CBRNE = 10; // 0xa
- field public static final int CMAS_CATEGORY_ENV = 7; // 0x7
- field public static final int CMAS_CATEGORY_FIRE = 5; // 0x5
- field public static final int CMAS_CATEGORY_GEO = 0; // 0x0
- field public static final int CMAS_CATEGORY_HEALTH = 6; // 0x6
- field public static final int CMAS_CATEGORY_INFRA = 9; // 0x9
- field public static final int CMAS_CATEGORY_MET = 1; // 0x1
- field public static final int CMAS_CATEGORY_OTHER = 11; // 0xb
- field public static final int CMAS_CATEGORY_RESCUE = 4; // 0x4
- field public static final int CMAS_CATEGORY_SAFETY = 2; // 0x2
- field public static final int CMAS_CATEGORY_SECURITY = 3; // 0x3
- field public static final int CMAS_CATEGORY_TRANSPORT = 8; // 0x8
- field public static final int CMAS_CATEGORY_UNKNOWN = -1; // 0xffffffff
- field public static final int CMAS_CERTAINTY_LIKELY = 1; // 0x1
- field public static final int CMAS_CERTAINTY_OBSERVED = 0; // 0x0
- field public static final int CMAS_CERTAINTY_UNKNOWN = -1; // 0xffffffff
- field public static final int CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY = 3; // 0x3
- field public static final int CMAS_CLASS_CMAS_EXERCISE = 5; // 0x5
- field public static final int CMAS_CLASS_EXTREME_THREAT = 1; // 0x1
- field public static final int CMAS_CLASS_OPERATOR_DEFINED_USE = 6; // 0x6
- field public static final int CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT = 0; // 0x0
- field public static final int CMAS_CLASS_REQUIRED_MONTHLY_TEST = 4; // 0x4
- field public static final int CMAS_CLASS_SEVERE_THREAT = 2; // 0x2
- field public static final int CMAS_CLASS_UNKNOWN = -1; // 0xffffffff
- field public static final int CMAS_RESPONSE_TYPE_ASSESS = 6; // 0x6
- field public static final int CMAS_RESPONSE_TYPE_AVOID = 5; // 0x5
- field public static final int CMAS_RESPONSE_TYPE_EVACUATE = 1; // 0x1
- field public static final int CMAS_RESPONSE_TYPE_EXECUTE = 3; // 0x3
- field public static final int CMAS_RESPONSE_TYPE_MONITOR = 4; // 0x4
- field public static final int CMAS_RESPONSE_TYPE_NONE = 7; // 0x7
- field public static final int CMAS_RESPONSE_TYPE_PREPARE = 2; // 0x2
- field public static final int CMAS_RESPONSE_TYPE_SHELTER = 0; // 0x0
- field public static final int CMAS_RESPONSE_TYPE_UNKNOWN = -1; // 0xffffffff
- field public static final int CMAS_SEVERITY_EXTREME = 0; // 0x0
- field public static final int CMAS_SEVERITY_SEVERE = 1; // 0x1
- field public static final int CMAS_SEVERITY_UNKNOWN = -1; // 0xffffffff
- field public static final int CMAS_URGENCY_EXPECTED = 1; // 0x1
- field public static final int CMAS_URGENCY_IMMEDIATE = 0; // 0x0
- field public static final int CMAS_URGENCY_UNKNOWN = -1; // 0xffffffff
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SmsCbCmasInfo> CREATOR;
- }
-
- public final class SmsCbEtwsInfo implements android.os.Parcelable {
- ctor public SmsCbEtwsInfo(int, boolean, boolean, boolean, @Nullable byte[]);
- method public int describeContents();
- method @Nullable public byte[] getPrimaryNotificationSignature();
- method public long getPrimaryNotificationTimestamp();
- method public int getWarningType();
- method public boolean isEmergencyUserAlert();
- method public boolean isPopupAlert();
- method public boolean isPrimary();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SmsCbEtwsInfo> CREATOR;
- field public static final int ETWS_WARNING_TYPE_EARTHQUAKE = 0; // 0x0
- field public static final int ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI = 2; // 0x2
- field public static final int ETWS_WARNING_TYPE_OTHER_EMERGENCY = 4; // 0x4
- field public static final int ETWS_WARNING_TYPE_TEST_MESSAGE = 3; // 0x3
- field public static final int ETWS_WARNING_TYPE_TSUNAMI = 1; // 0x1
- field public static final int ETWS_WARNING_TYPE_UNKNOWN = -1; // 0xffffffff
- }
-
- public final class SmsCbLocation implements android.os.Parcelable {
- ctor public SmsCbLocation(@NonNull String, int, int);
- method public int describeContents();
- method public int getCid();
- method public int getLac();
- method @NonNull public String getPlmn();
- method public boolean isInLocationArea(@NonNull android.telephony.SmsCbLocation);
- method public boolean isInLocationArea(@Nullable String, int, int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SmsCbLocation> CREATOR;
- }
-
- public final class SmsCbMessage implements android.os.Parcelable {
- ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, int, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo, int, @Nullable java.util.List<android.telephony.CbGeoUtils.Geometry>, long, int, int);
- method @NonNull public static android.telephony.SmsCbMessage createFromCursor(@NonNull android.database.Cursor);
- method public int describeContents();
- method @Nullable public android.telephony.SmsCbCmasInfo getCmasWarningInfo();
- method @NonNull public android.content.ContentValues getContentValues();
- method public int getDataCodingScheme();
- method @Nullable public android.telephony.SmsCbEtwsInfo getEtwsWarningInfo();
- method public int getGeographicalScope();
- method @NonNull public java.util.List<android.telephony.CbGeoUtils.Geometry> getGeometries();
- method @Nullable public String getLanguageCode();
- method @NonNull public android.telephony.SmsCbLocation getLocation();
- method public int getMaximumWaitingDuration();
- method @Nullable public String getMessageBody();
- method public int getMessageFormat();
- method public int getMessagePriority();
- method public long getReceivedTime();
- method public int getSerialNumber();
- method public int getServiceCategory();
- method public int getSlotIndex();
- method public int getSubscriptionId();
- method public boolean isCmasMessage();
- method public boolean isEmergencyMessage();
- method public boolean isEtwsMessage();
- method public boolean needGeoFencingCheck();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SmsCbMessage> CREATOR;
- field public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE = 3; // 0x3
- field public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0; // 0x0
- field public static final int GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE = 2; // 0x2
- field public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1; // 0x1
- field public static final int MAXIMUM_WAIT_TIME_NOT_SET = 255; // 0xff
- field public static final int MESSAGE_FORMAT_3GPP = 1; // 0x1
- field public static final int MESSAGE_FORMAT_3GPP2 = 2; // 0x2
- field public static final int MESSAGE_PRIORITY_EMERGENCY = 3; // 0x3
- field public static final int MESSAGE_PRIORITY_INTERACTIVE = 1; // 0x1
- field public static final int MESSAGE_PRIORITY_NORMAL = 0; // 0x0
- field public static final int MESSAGE_PRIORITY_URGENT = 2; // 0x2
- }
-
- public final class SmsManager {
- method public boolean disableCellBroadcastRange(int, int, int);
- method public boolean enableCellBroadcastRange(int, int, int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getPremiumSmsConsent(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPremiumSmsConsent(@NonNull String, int);
- field public static final int PREMIUM_SMS_CONSENT_ALWAYS_ALLOW = 3; // 0x3
- field public static final int PREMIUM_SMS_CONSENT_ASK_USER = 1; // 0x1
- field public static final int PREMIUM_SMS_CONSENT_NEVER_ALLOW = 2; // 0x2
- field public static final int PREMIUM_SMS_CONSENT_UNKNOWN = 0; // 0x0
- }
-
- 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, @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 {
- method public boolean areUiccApplicationsEnabled();
- method @Nullable public java.util.List<android.telephony.UiccAccessRule> getAccessRules();
- method public int getProfileClass();
- method public boolean isGroupDisabled();
- }
-
- public class SubscriptionManager {
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean canDisablePhysicalSubscription();
- method public boolean canManageSubscription(@NonNull android.telephony.SubscriptionInfo, @NonNull String);
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getActiveSubscriptionIdList();
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForIcc(@NonNull String);
- method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getCompleteActiveSubscriptionIdList();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int);
- method @NonNull public static android.content.res.Resources getResourcesForSubId(@NonNull android.content.Context, int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSubscriptionEnabled(int);
- method public void requestEmbeddedSubscriptionInfoListRefresh();
- method public void requestEmbeddedSubscriptionInfoListRefresh(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultDataSubId(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultSmsSubId(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultVoiceSubscriptionId(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUiccApplicationsEnabled(int, boolean);
- field @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS) public static final String ACTION_SUBSCRIPTION_PLANS_CHANGED = "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED";
- field @NonNull public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI;
- field @Deprecated public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
- field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
- field public static final int PROFILE_CLASS_PROVISIONING = 1; // 0x1
- field public static final int PROFILE_CLASS_TESTING = 0; // 0x0
- field public static final int PROFILE_CLASS_UNSET = -1; // 0xffffffff
- field @NonNull public static final android.net.Uri VT_ENABLED_CONTENT_URI;
- field @NonNull public static final android.net.Uri WFC_ENABLED_CONTENT_URI;
- field @NonNull public static final android.net.Uri WFC_MODE_CONTENT_URI;
- field @NonNull public static final android.net.Uri WFC_ROAMING_ENABLED_CONTENT_URI;
- field @NonNull public static final android.net.Uri WFC_ROAMING_MODE_CONTENT_URI;
- }
-
- public static class SubscriptionPlan.Builder {
- method @Deprecated public static android.telephony.SubscriptionPlan.Builder createRecurringDaily(java.time.ZonedDateTime);
- method @Deprecated public static android.telephony.SubscriptionPlan.Builder createRecurringMonthly(java.time.ZonedDateTime);
- method @Deprecated public static android.telephony.SubscriptionPlan.Builder createRecurringWeekly(java.time.ZonedDateTime);
- }
-
- public final class TelephonyHistogram implements android.os.Parcelable {
- ctor public TelephonyHistogram(int, int, int);
- ctor public TelephonyHistogram(android.telephony.TelephonyHistogram);
- ctor public TelephonyHistogram(android.os.Parcel);
- method public void addTimeTaken(int);
- method public int describeContents();
- method public int getAverageTime();
- method public int getBucketCount();
- method public int[] getBucketCounters();
- method public int[] getBucketEndPoints();
- method public int getCategory();
- method public int getId();
- method public int getMaxTime();
- method public int getMinTime();
- method public int getSampleCount();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.TelephonyHistogram> CREATOR;
- field public static final int TELEPHONY_CATEGORY_RIL = 1; // 0x1
- }
-
- public class TelephonyManager {
- method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
- method public int checkCarrierPrivilegesForPackage(String);
- method public int checkCarrierPrivilegesForPackageAnyPhone(String);
- method public void dial(String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean disableDataConnectivity();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableDataConnectivity();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean enableModemForSlot(int, boolean);
- method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean);
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int);
- method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes();
- method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
- method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
- method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
- 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 @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaEnhancedRoamingIndicatorDisplayNumber();
- 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();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int);
- method public String getCdmaPrlVersion();
- method public int getCurrentPhoneType();
- method public int getCurrentPhoneType(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getDataActivationState();
- method @Deprecated public boolean getDataEnabled();
- method @Deprecated public boolean getDataEnabled(int);
- method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getDefaultRespondViaMessageApplication();
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
- method public int getMaxNumberOfSimultaneouslyActiveSims();
- method public static long getMaxNumberVerificationTimeoutMillis();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getMergedImsisFromGroup();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask();
- method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState();
- method public int getSimApplicationState();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSimApplicationState(int);
- method public int getSimCardState();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSimCardState(int);
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Locale getSimLocale();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getSupportedRadioAccessFamily();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.UiccSlotInfo[] getUiccSlotsInfo();
- method @Nullable public android.os.Bundle getVisualVoicemailSettings();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String);
- method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int);
- method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int);
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
- 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 isDataConnectivityPossible();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean isIccLockEnabled();
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isLteCdmaEvdoGsmWcdmaEnabled();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMobileDataPolicyEnabled(int);
- method public boolean isNrDualConnectivityEnabled();
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isOpportunisticNetworkEnabled();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn();
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
- 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 needsOtaServiceProvisioning();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
- method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestModemActivityInfo(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.ModemActivityInfo,android.telephony.TelephonyManager.ModemActivityInfoException>);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
- 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>);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallForwarding(@NonNull android.telephony.CallForwardingInfo, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
- method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
- method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMobileDataPolicyEnabledStatus(int, boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
- method public int setNrDualConnectivityState(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRadioEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerState(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerStateForSlot(int, int);
- 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 @Deprecated public void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoiceActivationState(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void shutdownAllRadios();
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPin(String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPinReportResult(String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPuk(String, String);
- method @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();
- 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_DEFAULT_DATA_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED";
- field public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED";
- field public static final String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE";
- field public static final String ACTION_EMERGENCY_CALLBACK_MODE_CHANGED = "android.intent.action.EMERGENCY_CALLBACK_MODE_CHANGED";
- field public static final String ACTION_EMERGENCY_CALL_STATE_CHANGED = "android.intent.action.EMERGENCY_CALL_STATE_CHANGED";
- field public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE = "com.android.omadm.service.CONFIGURATION_UPDATE";
- field public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS = "android.telephony.action.SHOW_NOTICE_ECM_BLOCK_OTHERS";
- field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
- field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
- field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
- field public static final int CALL_WAITING_STATUS_DISABLED = 2; // 0x2
- field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1
- field public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; // 0x4
- field public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3; // 0x3
- 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
- field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
- field public static final int ENABLE_NR_DUAL_CONNECTIVITY_INVALID_STATE = 4; // 0x4
- field public static final int ENABLE_NR_DUAL_CONNECTIVITY_NOT_SUPPORTED = 1; // 0x1
- field public static final int ENABLE_NR_DUAL_CONNECTIVITY_RADIO_ERROR = 3; // 0x3
- field public static final int ENABLE_NR_DUAL_CONNECTIVITY_RADIO_NOT_AVAILABLE = 2; // 0x2
- field public static final int ENABLE_NR_DUAL_CONNECTIVITY_SUCCESS = 0; // 0x0
- field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
- field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
- field public static final String EXTRA_PHONE_IN_ECM_STATE = "android.telephony.extra.PHONE_IN_ECM_STATE";
- field public static final String EXTRA_PHONE_IN_EMERGENCY_CALL = "android.telephony.extra.PHONE_IN_EMERGENCY_CALL";
- field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
- field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
- field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
- field public static final int INVALID_EMERGENCY_NUMBER_DB_VERSION = -1; // 0xffffffff
- field public static final int KEY_TYPE_EPDG = 1; // 0x1
- field public static final int KEY_TYPE_WLAN = 2; // 0x2
- field public static final int MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL = 1; // 0x1
- field public static final int MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED = 2; // 0x2
- field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L
- field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L
- field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L
- field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L
- field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L
- field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L
- field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L
- field public static final long NETWORK_TYPE_BITMASK_GPRS = 1L; // 0x1L
- field public static final long NETWORK_TYPE_BITMASK_GSM = 32768L; // 0x8000L
- field public static final long NETWORK_TYPE_BITMASK_HSDPA = 128L; // 0x80L
- field public static final long NETWORK_TYPE_BITMASK_HSPA = 512L; // 0x200L
- field public static final long NETWORK_TYPE_BITMASK_HSPAP = 16384L; // 0x4000L
- field public static final long NETWORK_TYPE_BITMASK_HSUPA = 256L; // 0x100L
- field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L
- field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L
- field public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L
- field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L
- field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L
- field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L
- field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L
- field public static final int NR_DUAL_CONNECTIVITY_DISABLE = 2; // 0x2
- field public static final int NR_DUAL_CONNECTIVITY_DISABLE_IMMEDIATE = 3; // 0x3
- field public static final int NR_DUAL_CONNECTIVITY_ENABLE = 1; // 0x1
- field public static final int RADIO_POWER_OFF = 0; // 0x0
- field public static final int RADIO_POWER_ON = 1; // 0x1
- field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
- field public static final int SET_CARRIER_RESTRICTION_ERROR = 2; // 0x2
- field public static final int SET_CARRIER_RESTRICTION_NOT_SUPPORTED = 1; // 0x1
- field public static final int SET_CARRIER_RESTRICTION_SUCCESS = 0; // 0x0
- field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2
- field public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1; // 0x1
- field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3
- field public static final int SIM_ACTIVATION_STATE_RESTRICTED = 4; // 0x4
- field public static final int SIM_ACTIVATION_STATE_UNKNOWN = 0; // 0x0
- field public static final int SIM_STATE_LOADED = 10; // 0xa
- field public static final int SIM_STATE_PRESENT = 11; // 0xb
- field public static final int SRVCC_STATE_HANDOVER_CANCELED = 3; // 0x3
- field public static final int SRVCC_STATE_HANDOVER_COMPLETED = 1; // 0x1
- field public static final int SRVCC_STATE_HANDOVER_FAILED = 2; // 0x2
- field public static final int SRVCC_STATE_HANDOVER_NONE = -1; // 0xffffffff
- field public static final int SRVCC_STATE_HANDOVER_STARTED = 0; // 0x0
- }
-
- public static interface TelephonyManager.CallForwardingInfoCallback {
- method public void onCallForwardingInfoAvailable(@NonNull android.telephony.CallForwardingInfo);
- method public void onError(int);
- field public static final int RESULT_ERROR_FDN_CHECK_FAILURE = 2; // 0x2
- field public static final int RESULT_ERROR_NOT_SUPPORTED = 3; // 0x3
- field public static final int RESULT_ERROR_UNKNOWN = 1; // 0x1
- field public static final int RESULT_SUCCESS = 0; // 0x0
- }
-
- public static class TelephonyManager.ModemActivityInfoException extends java.lang.Exception {
- method public int getErrorCode();
- field public static final int ERROR_INVALID_INFO_RECEIVED = 2; // 0x2
- field public static final int ERROR_MODEM_RESPONSE_ERROR = 3; // 0x3
- field public static final int ERROR_PHONE_NOT_AVAILABLE = 1; // 0x1
- field public static final int ERROR_UNKNOWN = 0; // 0x0
- }
-
- public final class UiccAccessRule implements android.os.Parcelable {
- ctor public UiccAccessRule(byte[], @Nullable String, long);
- method public int describeContents();
- method public int getCarrierPrivilegeStatus(android.content.pm.PackageInfo);
- method public int getCarrierPrivilegeStatus(android.content.pm.Signature, String);
- method public String getCertificateHexString();
- method @Nullable public String getPackageName();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.UiccAccessRule> CREATOR;
- }
-
- public class UiccSlotInfo implements android.os.Parcelable {
- ctor @Deprecated public UiccSlotInfo(boolean, boolean, String, int, int, boolean);
- method public int describeContents();
- method public String getCardId();
- method public int getCardStateInfo();
- method public boolean getIsActive();
- method public boolean getIsEuicc();
- method public boolean getIsExtendedApduSupported();
- method public int getLogicalSlotIdx();
- method public boolean isRemovable();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CARD_STATE_INFO_ABSENT = 1; // 0x1
- field public static final int CARD_STATE_INFO_ERROR = 3; // 0x3
- field public static final int CARD_STATE_INFO_PRESENT = 2; // 0x2
- field public static final int CARD_STATE_INFO_RESTRICTED = 4; // 0x4
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.UiccSlotInfo> CREATOR;
- }
-
- public abstract class VisualVoicemailService extends android.app.Service {
- method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, String, short, String, android.app.PendingIntent);
- method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
- }
-
-}
-
-package android.telephony.cdma {
-
- public final class CdmaSmsCbProgramData implements android.os.Parcelable {
- method public int describeContents();
- method public int getCategory();
- method public int getOperation();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 4099; // 0x1003
- field public static final int CATEGORY_CMAS_EXTREME_THREAT = 4097; // 0x1001
- field public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE = 4351; // 0x10ff
- field public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 4096; // 0x1000
- field public static final int CATEGORY_CMAS_SEVERE_THREAT = 4098; // 0x1002
- field public static final int CATEGORY_CMAS_TEST_MESSAGE = 4100; // 0x1004
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.cdma.CdmaSmsCbProgramData> CREATOR;
- field public static final int OPERATION_ADD_CATEGORY = 1; // 0x1
- field public static final int OPERATION_CLEAR_CATEGORIES = 2; // 0x2
- field public static final int OPERATION_DELETE_CATEGORY = 0; // 0x0
- }
-
-}
-
-package android.telephony.data {
-
- public final class DataCallResponse implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public java.util.List<android.net.LinkAddress> getAddresses();
- method public int getCause();
- method @NonNull public java.util.List<java.net.InetAddress> getDnsAddresses();
- method @NonNull public java.util.List<java.net.InetAddress> getGatewayAddresses();
- method public int getHandoverFailureMode();
- method public int getId();
- method @NonNull public String getInterfaceName();
- method public int getLinkStatus();
- method @Deprecated public int getMtu();
- method public int getMtuV4();
- method public int getMtuV6();
- method @NonNull public java.util.List<java.net.InetAddress> getPcscfAddresses();
- method public int getProtocolType();
- method public long getRetryIntervalMillis();
- method @Deprecated public int getSuggestedRetryTime();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
- field public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 1; // 0x1
- field public static final int HANDOVER_FAILURE_MODE_LEGACY = 0; // 0x0
- field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER = 2; // 0x2
- field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 3; // 0x3
- field public static final int HANDOVER_FAILURE_MODE_UNKNOWN = -1; // 0xffffffff
- field public static final int LINK_STATUS_ACTIVE = 2; // 0x2
- field public static final int LINK_STATUS_DORMANT = 1; // 0x1
- field public static final int LINK_STATUS_INACTIVE = 0; // 0x0
- field public static final int LINK_STATUS_UNKNOWN = -1; // 0xffffffff
- field public static final int RETRY_INTERVAL_UNDEFINED = -1; // 0xffffffff
- }
-
- public static final class DataCallResponse.Builder {
- ctor public DataCallResponse.Builder();
- method @NonNull public android.telephony.data.DataCallResponse build();
- method @NonNull public android.telephony.data.DataCallResponse.Builder setAddresses(@NonNull java.util.List<android.net.LinkAddress>);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setCause(int);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setDnsAddresses(@NonNull java.util.List<java.net.InetAddress>);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setGatewayAddresses(@NonNull java.util.List<java.net.InetAddress>);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setHandoverFailureMode(int);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setId(int);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setInterfaceName(@NonNull String);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setLinkStatus(int);
- method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setMtu(int);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV4(int);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV6(int);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryIntervalMillis(long);
- method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
- }
-
- public final class DataProfile implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public String getApn();
- method public int getAuthType();
- method public int getBearerBitmask();
- method @Deprecated public int getMtu();
- method public int getMtuV4();
- method public int getMtuV6();
- method @Nullable public String getPassword();
- method public int getProfileId();
- method public int getProtocolType();
- method public int getRoamingProtocolType();
- method public int getSupportedApnTypesBitmask();
- method public int getType();
- method @Nullable public String getUserName();
- method public boolean isEnabled();
- method public boolean isPersistent();
- method public boolean isPreferred();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR;
- field public static final int TYPE_3GPP = 1; // 0x1
- field public static final int TYPE_3GPP2 = 2; // 0x2
- field public static final int TYPE_COMMON = 0; // 0x0
- }
-
- public static final class DataProfile.Builder {
- ctor public DataProfile.Builder();
- method @NonNull public android.telephony.data.DataProfile build();
- method @NonNull public android.telephony.data.DataProfile.Builder enable(boolean);
- method @NonNull public android.telephony.data.DataProfile.Builder setApn(@NonNull String);
- method @NonNull public android.telephony.data.DataProfile.Builder setAuthType(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setBearerBitmask(int);
- method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setMtu(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setMtuV4(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setMtuV6(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setPassword(@NonNull String);
- method @NonNull public android.telephony.data.DataProfile.Builder setPersistent(boolean);
- method @NonNull public android.telephony.data.DataProfile.Builder setPreferred(boolean);
- method @NonNull public android.telephony.data.DataProfile.Builder setProfileId(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setProtocolType(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setRoamingProtocolType(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setSupportedApnTypesBitmask(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setType(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setUserName(@NonNull String);
- }
-
- public abstract class DataService extends android.app.Service {
- ctor public DataService();
- method public android.os.IBinder onBind(android.content.Intent);
- method @Nullable public abstract android.telephony.data.DataService.DataServiceProvider onCreateDataServiceProvider(int);
- field public static final int REQUEST_REASON_HANDOVER = 3; // 0x3
- field public static final int REQUEST_REASON_NORMAL = 1; // 0x1
- field public static final int REQUEST_REASON_SHUTDOWN = 2; // 0x2
- field public static final int REQUEST_REASON_UNKNOWN = 0; // 0x0
- field public static final String SERVICE_INTERFACE = "android.telephony.data.DataService";
- }
-
- public abstract class DataService.DataServiceProvider implements java.lang.AutoCloseable {
- ctor public DataService.DataServiceProvider(int);
- method public abstract void close();
- method public void deactivateDataCall(int, int, @Nullable android.telephony.data.DataServiceCallback);
- method public final int getSlotIndex();
- method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>);
- method public void requestDataCallList(@NonNull android.telephony.data.DataServiceCallback);
- method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback);
- method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback);
- method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback);
- }
-
- public class DataServiceCallback {
- method public void onDataCallListChanged(@NonNull java.util.List<android.telephony.data.DataCallResponse>);
- method public void onDeactivateDataCallComplete(int);
- method public void onRequestDataCallListComplete(int, @NonNull java.util.List<android.telephony.data.DataCallResponse>);
- method public void onSetDataProfileComplete(int);
- method public void onSetInitialAttachApnComplete(int);
- method public void onSetupDataCallComplete(int, @Nullable android.telephony.data.DataCallResponse);
- field public static final int RESULT_ERROR_BUSY = 3; // 0x3
- field public static final int RESULT_ERROR_ILLEGAL_STATE = 4; // 0x4
- field public static final int RESULT_ERROR_INVALID_ARG = 2; // 0x2
- field public static final int RESULT_ERROR_UNSUPPORTED = 1; // 0x1
- field public static final int RESULT_SUCCESS = 0; // 0x0
- }
-
- public abstract class QualifiedNetworksService extends android.app.Service {
- ctor public QualifiedNetworksService();
- method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int);
- field public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE = "android.telephony.data.QualifiedNetworksService";
- }
-
- public abstract class QualifiedNetworksService.NetworkAvailabilityProvider implements java.lang.AutoCloseable {
- ctor public QualifiedNetworksService.NetworkAvailabilityProvider(int);
- method public abstract void close();
- method public final int getSlotIndex();
- method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
- }
-
-}
-
-package android.telephony.euicc {
-
- public final class DownloadableSubscription implements android.os.Parcelable {
- method public java.util.List<android.telephony.UiccAccessRule> getAccessRules();
- method @Nullable public String getCarrierName();
- }
-
- public static final class DownloadableSubscription.Builder {
- ctor public DownloadableSubscription.Builder();
- ctor public DownloadableSubscription.Builder(android.telephony.euicc.DownloadableSubscription);
- method public android.telephony.euicc.DownloadableSubscription build();
- method public android.telephony.euicc.DownloadableSubscription.Builder setAccessRules(java.util.List<android.telephony.UiccAccessRule>);
- method public android.telephony.euicc.DownloadableSubscription.Builder setCarrierName(String);
- method public android.telephony.euicc.DownloadableSubscription.Builder setConfirmationCode(String);
- method public android.telephony.euicc.DownloadableSubscription.Builder setEncodedActivationCode(String);
- }
-
- public class EuiccCardManager {
- method public void authenticateServer(String, String, byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
- method public void cancelSession(String, byte[], @android.telephony.euicc.EuiccCardManager.CancelReason int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
- method public void deleteProfile(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
- method public void disableProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
- method public void listNotifications(String, @android.telephony.euicc.EuiccNotification.Event int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
- method public void loadBoundProfilePackage(String, byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
- method public void prepareDownload(String, @Nullable byte[], byte[], byte[], byte[], java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
- method public void removeNotificationFromList(String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
- method public void requestAllProfiles(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo[]>);
- method public void requestDefaultSmdpAddress(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>);
- method public void requestEuiccChallenge(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
- method public void requestEuiccInfo1(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
- method public void requestEuiccInfo2(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<byte[]>);
- method public void requestProfile(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
- method public void requestRulesAuthTable(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccRulesAuthTable>);
- method public void requestSmdsAddress(String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.String>);
- method public void resetMemory(String, @android.telephony.euicc.EuiccCardManager.ResetOption int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
- method public void retrieveNotification(String, int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification>);
- method public void retrieveNotificationList(String, @android.telephony.euicc.EuiccNotification.Event int, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.telephony.euicc.EuiccNotification[]>);
- method public void setDefaultSmdpAddress(String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
- method public void setNickname(String, String, String, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<java.lang.Void>);
- method public void switchToProfile(String, String, boolean, java.util.concurrent.Executor, android.telephony.euicc.EuiccCardManager.ResultCallback<android.service.euicc.EuiccProfileInfo>);
- field public static final int CANCEL_REASON_END_USER_REJECTED = 0; // 0x0
- field public static final int CANCEL_REASON_POSTPONED = 1; // 0x1
- field public static final int CANCEL_REASON_PPR_NOT_ALLOWED = 3; // 0x3
- field public static final int CANCEL_REASON_TIMEOUT = 2; // 0x2
- field public static final int RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 2; // 0x2
- field public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1; // 0x1
- field public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 4; // 0x4
- field public static final int RESULT_CALLER_NOT_ALLOWED = -3; // 0xfffffffd
- field public static final int RESULT_EUICC_NOT_FOUND = -2; // 0xfffffffe
- field public static final int RESULT_OK = 0; // 0x0
- field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff
- }
-
- @IntDef(prefix={"CANCEL_REASON_"}, value={android.telephony.euicc.EuiccCardManager.CANCEL_REASON_END_USER_REJECTED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_POSTPONED, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_TIMEOUT, android.telephony.euicc.EuiccCardManager.CANCEL_REASON_PPR_NOT_ALLOWED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccCardManager.CancelReason {
- }
-
- @IntDef(flag=true, prefix={"RESET_OPTION_"}, value={android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES, android.telephony.euicc.EuiccCardManager.RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccCardManager.ResetOption {
- }
-
- public static interface EuiccCardManager.ResultCallback<T> {
- method public void onComplete(int, T);
- }
-
- public class EuiccManager {
- method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void continueOperation(android.content.Intent, android.os.Bundle);
- method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(@NonNull android.app.PendingIntent);
- method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(@android.telephony.euicc.EuiccCardManager.ResetOption int, @NonNull android.app.PendingIntent);
- method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
- method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
- method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public int getOtaStatus();
- method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public java.util.List<java.lang.String> getSupportedCountries();
- method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public java.util.List<java.lang.String> getUnsupportedCountries();
- method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public boolean isSupportedCountry(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void setSupportedCountries(@NonNull java.util.List<java.lang.String>);
- method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void setUnsupportedCountries(@NonNull java.util.List<java.lang.String>);
- field public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED";
- field @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public static final String ACTION_OTA_STATUS_CHANGED = "android.telephony.euicc.action.OTA_STATUS_CHANGED";
- field public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION = "android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
- field public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
- field public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = "android.telephony.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED";
- field public static final int EUICC_ACTIVATION_TYPE_ACCOUNT_REQUIRED = 4; // 0x4
- field public static final int EUICC_ACTIVATION_TYPE_BACKUP = 2; // 0x2
- field public static final int EUICC_ACTIVATION_TYPE_DEFAULT = 1; // 0x1
- field public static final int EUICC_ACTIVATION_TYPE_TRANSFER = 3; // 0x3
- field public static final int EUICC_OTA_FAILED = 2; // 0x2
- field public static final int EUICC_OTA_IN_PROGRESS = 1; // 0x1
- field public static final int EUICC_OTA_NOT_NEEDED = 4; // 0x4
- field public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; // 0x5
- field public static final int EUICC_OTA_SUCCEEDED = 3; // 0x3
- field public static final String EXTRA_ACTIVATION_TYPE = "android.telephony.euicc.extra.ACTIVATION_TYPE";
- field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS";
- field public static final String EXTRA_ENABLE_SUBSCRIPTION = "android.telephony.euicc.extra.ENABLE_SUBSCRIPTION";
- field public static final String EXTRA_FORCE_PROVISION = "android.telephony.euicc.extra.FORCE_PROVISION";
- field public static final String EXTRA_FROM_SUBSCRIPTION_ID = "android.telephony.euicc.extra.FROM_SUBSCRIPTION_ID";
- field public static final String EXTRA_PHYSICAL_SLOT_ID = "android.telephony.euicc.extra.PHYSICAL_SLOT_ID";
- field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.euicc.extra.SUBSCRIPTION_ID";
- field public static final String EXTRA_SUBSCRIPTION_NICKNAME = "android.telephony.euicc.extra.SUBSCRIPTION_NICKNAME";
- }
-
- @IntDef(prefix={"EUICC_OTA_"}, value={android.telephony.euicc.EuiccManager.EUICC_OTA_IN_PROGRESS, android.telephony.euicc.EuiccManager.EUICC_OTA_FAILED, android.telephony.euicc.EuiccManager.EUICC_OTA_SUCCEEDED, android.telephony.euicc.EuiccManager.EUICC_OTA_NOT_NEEDED, android.telephony.euicc.EuiccManager.EUICC_OTA_STATUS_UNAVAILABLE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccManager.OtaStatus {
- }
-
- public final class EuiccNotification implements android.os.Parcelable {
- ctor public EuiccNotification(int, String, @android.telephony.euicc.EuiccNotification.Event int, @Nullable byte[]);
- method public int describeContents();
- method @Nullable public byte[] getData();
- method @android.telephony.euicc.EuiccNotification.Event public int getEvent();
- method public int getSeq();
- method public String getTargetAddr();
- method public void writeToParcel(android.os.Parcel, int);
- field @android.telephony.euicc.EuiccNotification.Event public static final int ALL_EVENTS = 15; // 0xf
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccNotification> CREATOR;
- field public static final int EVENT_DELETE = 8; // 0x8
- field public static final int EVENT_DISABLE = 4; // 0x4
- field public static final int EVENT_ENABLE = 2; // 0x2
- field public static final int EVENT_INSTALL = 1; // 0x1
- }
-
- @IntDef(flag=true, prefix={"EVENT_"}, value={android.telephony.euicc.EuiccNotification.EVENT_INSTALL, android.telephony.euicc.EuiccNotification.EVENT_ENABLE, android.telephony.euicc.EuiccNotification.EVENT_DISABLE, android.telephony.euicc.EuiccNotification.EVENT_DELETE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccNotification.Event {
- }
-
- public final class EuiccRulesAuthTable implements android.os.Parcelable {
- method public int describeContents();
- method public int findIndex(@android.service.euicc.EuiccProfileInfo.PolicyRule int, android.service.carrier.CarrierIdentifier);
- method public boolean hasPolicyRuleFlag(int, @android.telephony.euicc.EuiccRulesAuthTable.PolicyRuleFlag int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.euicc.EuiccRulesAuthTable> CREATOR;
- field public static final int POLICY_RULE_FLAG_CONSENT_REQUIRED = 1; // 0x1
- }
-
- public static final class EuiccRulesAuthTable.Builder {
- ctor public EuiccRulesAuthTable.Builder(int);
- method public android.telephony.euicc.EuiccRulesAuthTable.Builder add(int, java.util.List<android.service.carrier.CarrierIdentifier>, int);
- method public android.telephony.euicc.EuiccRulesAuthTable build();
- }
-
- @IntDef(flag=true, prefix={"POLICY_RULE_FLAG_"}, value={android.telephony.euicc.EuiccRulesAuthTable.POLICY_RULE_FLAG_CONSENT_REQUIRED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface EuiccRulesAuthTable.PolicyRuleFlag {
- }
-
-}
-
-package android.telephony.ims {
-
- public final class ImsCallForwardInfo implements android.os.Parcelable {
- ctor public ImsCallForwardInfo(int, int, int, int, @NonNull String, int);
- method public int describeContents();
- method public int getCondition();
- method public String getNumber();
- method public int getServiceClass();
- method public int getStatus();
- method public int getTimeSeconds();
- method public int getToA();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CDIV_CF_REASON_ALL = 4; // 0x4
- field public static final int CDIV_CF_REASON_ALL_CONDITIONAL = 5; // 0x5
- field public static final int CDIV_CF_REASON_BUSY = 1; // 0x1
- field public static final int CDIV_CF_REASON_NOT_LOGGED_IN = 6; // 0x6
- field public static final int CDIV_CF_REASON_NOT_REACHABLE = 3; // 0x3
- field public static final int CDIV_CF_REASON_NO_REPLY = 2; // 0x2
- field public static final int CDIV_CF_REASON_UNCONDITIONAL = 0; // 0x0
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsCallForwardInfo> CREATOR;
- field public static final int STATUS_ACTIVE = 1; // 0x1
- field public static final int STATUS_NOT_ACTIVE = 0; // 0x0
- field public static final int TYPE_OF_ADDRESS_INTERNATIONAL = 145; // 0x91
- field public static final int TYPE_OF_ADDRESS_UNKNOWN = 129; // 0x81
- }
-
- public final class ImsCallProfile implements android.os.Parcelable {
- ctor public ImsCallProfile();
- ctor public ImsCallProfile(int, int);
- ctor public ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile);
- method public int describeContents();
- method public String getCallExtra(String);
- method public String getCallExtra(String, String);
- method public boolean getCallExtraBoolean(String);
- method public boolean getCallExtraBoolean(String, boolean);
- method public int getCallExtraInt(String);
- method public int getCallExtraInt(String, int);
- method public android.os.Bundle getCallExtras();
- method public int getCallType();
- method public static int getCallTypeFromVideoState(int);
- method public int getCallerNumberVerificationStatus();
- method public int getEmergencyCallRouting();
- method public int getEmergencyServiceCategories();
- method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
- method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
- method @NonNull public android.os.Bundle getProprietaryCallExtras();
- method public int getRestrictCause();
- method public int getServiceType();
- method public static int getVideoStateFromCallType(int);
- method public static int getVideoStateFromImsCallProfile(android.telephony.ims.ImsCallProfile);
- method public boolean hasKnownUserIntentEmergency();
- method public boolean isEmergencyCallTesting();
- method public boolean isVideoCall();
- method public boolean isVideoPaused();
- method public static int presentationToOir(int);
- method public void setCallExtra(String, String);
- method public void setCallExtraBoolean(String, boolean);
- method public void setCallExtraInt(String, int);
- method public void setCallRestrictCause(int);
- method public void setCallerNumberVerificationStatus(int);
- method public void setEmergencyCallRouting(int);
- method public void setEmergencyCallTesting(boolean);
- method public void setEmergencyServiceCategories(int);
- method public void setEmergencyUrns(@NonNull java.util.List<java.lang.String>);
- method public void setHasKnownUserIntentEmergency(boolean);
- method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
- method public void updateCallType(android.telephony.ims.ImsCallProfile);
- method public void updateMediaProfile(android.telephony.ims.ImsCallProfile);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CALL_RESTRICT_CAUSE_DISABLED = 2; // 0x2
- field public static final int CALL_RESTRICT_CAUSE_HD = 3; // 0x3
- field public static final int CALL_RESTRICT_CAUSE_NONE = 0; // 0x0
- field public static final int CALL_RESTRICT_CAUSE_RAT = 1; // 0x1
- field public static final int CALL_TYPE_VIDEO_N_VOICE = 3; // 0x3
- field public static final int CALL_TYPE_VOICE = 2; // 0x2
- field public static final int CALL_TYPE_VOICE_N_VIDEO = 1; // 0x1
- field public static final int CALL_TYPE_VS = 8; // 0x8
- field public static final int CALL_TYPE_VS_RX = 10; // 0xa
- field public static final int CALL_TYPE_VS_TX = 9; // 0x9
- field public static final int CALL_TYPE_VT = 4; // 0x4
- field public static final int CALL_TYPE_VT_NODIR = 7; // 0x7
- field public static final int CALL_TYPE_VT_RX = 6; // 0x6
- field public static final int CALL_TYPE_VT_TX = 5; // 0x5
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsCallProfile> CREATOR;
- field public static final int DIALSTRING_NORMAL = 0; // 0x0
- field public static final int DIALSTRING_SS_CONF = 1; // 0x1
- field public static final int DIALSTRING_USSD = 2; // 0x2
- field public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
- field public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS";
- field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telephony.ims.extra.CALL_DISCONNECT_CAUSE";
- field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE";
- field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
- field public static final String EXTRA_CHILD_NUMBER = "ChildNum";
- field public static final String EXTRA_CNA = "cna";
- field public static final String EXTRA_CNAP = "cnap";
- field public static final String EXTRA_CODEC = "Codec";
- field public static final String EXTRA_DIALSTRING = "dialstring";
- field public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
- field public static final String EXTRA_EMERGENCY_CALL = "e_call";
- field public static final String EXTRA_FORWARDED_NUMBER = "android.telephony.ims.extra.FORWARDED_NUMBER";
- field public static final String EXTRA_IS_CALL_PULL = "CallPull";
- field public static final String EXTRA_OI = "oi";
- field public static final String EXTRA_OIR = "oir";
- field public static final String EXTRA_REMOTE_URI = "remote_uri";
- field public static final String EXTRA_USSD = "ussd";
- field public static final int OIR_DEFAULT = 0; // 0x0
- field public static final int OIR_PRESENTATION_NOT_RESTRICTED = 2; // 0x2
- field public static final int OIR_PRESENTATION_PAYPHONE = 4; // 0x4
- field public static final int OIR_PRESENTATION_RESTRICTED = 1; // 0x1
- field public static final int OIR_PRESENTATION_UNKNOWN = 3; // 0x3
- field public static final int SERVICE_TYPE_EMERGENCY = 2; // 0x2
- field public static final int SERVICE_TYPE_NONE = 0; // 0x0
- field public static final int SERVICE_TYPE_NORMAL = 1; // 0x1
- field public static final int VERIFICATION_STATUS_FAILED = 2; // 0x2
- field public static final int VERIFICATION_STATUS_NOT_VERIFIED = 0; // 0x0
- field public static final int VERIFICATION_STATUS_PASSED = 1; // 0x1
- }
-
- public class ImsCallSessionListener {
- method public void callQualityChanged(@NonNull android.telephony.CallQuality);
- method public void callSessionConferenceExtendFailed(android.telephony.ims.ImsReasonInfo);
- method public void callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
- method public void callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
- method public void callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState);
- method @Deprecated public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo);
- method @Deprecated public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo);
- method public void callSessionHeld(android.telephony.ims.ImsCallProfile);
- method public void callSessionHoldFailed(android.telephony.ims.ImsReasonInfo);
- method public void callSessionHoldReceived(android.telephony.ims.ImsCallProfile);
- method public void callSessionInitiated(android.telephony.ims.ImsCallProfile);
- method public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo);
- method public void callSessionInviteParticipantsRequestDelivered();
- method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
- method @Deprecated public void callSessionMayHandover(int, int);
- method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase);
- method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo);
- method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
- method public void callSessionMultipartyStateChanged(boolean);
- method public void callSessionProgressing(android.telephony.ims.ImsStreamMediaProfile);
- method public void callSessionRemoveParticipantsRequestDelivered();
- method public void callSessionRemoveParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
- method public void callSessionResumeFailed(android.telephony.ims.ImsReasonInfo);
- method public void callSessionResumeReceived(android.telephony.ims.ImsCallProfile);
- method public void callSessionResumed(android.telephony.ims.ImsCallProfile);
- method public void callSessionRttAudioIndicatorChanged(@NonNull android.telephony.ims.ImsStreamMediaProfile);
- method public void callSessionRttMessageReceived(String);
- method public void callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile);
- method public void callSessionRttModifyResponseReceived(int);
- method public void callSessionSuppServiceReceived(android.telephony.ims.ImsSuppServiceNotification);
- method public void callSessionTerminated(android.telephony.ims.ImsReasonInfo);
- method public void callSessionTtyModeReceived(int);
- method public void callSessionUpdateFailed(android.telephony.ims.ImsReasonInfo);
- method public void callSessionUpdateReceived(android.telephony.ims.ImsCallProfile);
- method public void callSessionUpdated(android.telephony.ims.ImsCallProfile);
- method public void callSessionUssdMessageReceived(int, String);
- method public void onHandover(int, int, @Nullable android.telephony.ims.ImsReasonInfo);
- method public void onHandoverFailed(int, int, @NonNull android.telephony.ims.ImsReasonInfo);
- method public void onMayHandover(int, int);
- }
-
- public final class ImsConferenceState implements android.os.Parcelable {
- method public int describeContents();
- method public static int getConnectionStateForStatus(String);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsConferenceState> CREATOR;
- field public static final String DISPLAY_TEXT = "display-text";
- field public static final String ENDPOINT = "endpoint";
- field public static final String SIP_STATUS_CODE = "sipstatuscode";
- field public static final String STATUS = "status";
- field public static final String STATUS_ALERTING = "alerting";
- field public static final String STATUS_CONNECTED = "connected";
- field public static final String STATUS_CONNECT_FAIL = "connect-fail";
- field public static final String STATUS_DIALING_IN = "dialing-in";
- field public static final String STATUS_DIALING_OUT = "dialing-out";
- field public static final String STATUS_DISCONNECTED = "disconnected";
- field public static final String STATUS_DISCONNECTING = "disconnecting";
- field public static final String STATUS_MUTED_VIA_FOCUS = "muted-via-focus";
- field public static final String STATUS_ON_HOLD = "on-hold";
- field public static final String STATUS_PENDING = "pending";
- field public static final String STATUS_SEND_ONLY = "sendonly";
- field public static final String STATUS_SEND_RECV = "sendrecv";
- field public static final String USER = "user";
- field public final java.util.HashMap<java.lang.String,android.os.Bundle> mParticipants;
- }
-
- public final class ImsException extends java.lang.Exception {
- ctor public ImsException(@Nullable String);
- ctor public ImsException(@Nullable String, int);
- ctor public ImsException(@Nullable String, int, @Nullable Throwable);
- }
-
- public final class ImsExternalCallState implements android.os.Parcelable {
- ctor public ImsExternalCallState(@NonNull String, @NonNull android.net.Uri, @Nullable android.net.Uri, boolean, int, int, boolean);
- method public int describeContents();
- method @NonNull public android.net.Uri getAddress();
- method public int getCallId();
- method public int getCallState();
- method public int getCallType();
- method @Nullable public android.net.Uri getLocalAddress();
- method public boolean isCallHeld();
- method public boolean isCallPullable();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CALL_STATE_CONFIRMED = 1; // 0x1
- field public static final int CALL_STATE_TERMINATED = 2; // 0x2
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsExternalCallState> CREATOR;
- }
-
- public class ImsManager {
- method @NonNull public android.telephony.ims.SipDelegateManager getSipDelegateManager(int);
- }
-
- public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
- method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(int, int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(int, int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException;
- method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiNonPersistent(boolean, int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingModeSetting(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingSettingEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean);
- method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback);
- }
-
- @Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback {
- ctor @Deprecated public ImsMmTelManager.RegistrationCallback();
- }
-
- public final class ImsReasonInfo implements android.os.Parcelable {
- field public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED = "Forbidden. Not Authorized for Service";
- }
-
- public class ImsService extends android.app.Service {
- ctor public ImsService();
- method public android.telephony.ims.feature.MmTelFeature createMmTelFeature(int);
- method public android.telephony.ims.feature.RcsFeature createRcsFeature(int);
- method public void disableIms(int);
- method public void enableIms(int);
- method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int);
- method public long getImsServiceCapabilities();
- method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int);
- method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int);
- method public final void onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) throws android.os.RemoteException;
- method public android.telephony.ims.stub.ImsFeatureConfiguration querySupportedImsFeatures();
- method public void readyForFeatureCreation();
- field public static final long CAPABILITY_SIP_DELEGATE_CREATION = 2L; // 0x2L
- }
-
- public final class ImsSsData implements android.os.Parcelable {
- ctor public ImsSsData(int, int, int, int, int);
- method public int describeContents();
- method @Nullable public java.util.List<android.telephony.ims.ImsCallForwardInfo> getCallForwardInfo();
- method public int getRequestType();
- method public int getResult();
- method public int getServiceClass();
- method public int getServiceType();
- method @NonNull public java.util.List<android.telephony.ims.ImsSsInfo> getSuppServiceInfo();
- method public int getTeleserviceType();
- method public boolean isTypeBarring();
- method public boolean isTypeCf();
- method public boolean isTypeClip();
- method public boolean isTypeClir();
- method public boolean isTypeColp();
- method public boolean isTypeColr();
- method public boolean isTypeCw();
- method public boolean isTypeIcb();
- method public boolean isTypeInterrogation();
- method public boolean isTypeUnConditional();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsSsData> CREATOR;
- field public static final int RESULT_SUCCESS = 0; // 0x0
- field public static final int SERVICE_CLASS_DATA = 2; // 0x2
- field public static final int SERVICE_CLASS_DATA_CIRCUIT_ASYNC = 32; // 0x20
- field public static final int SERVICE_CLASS_DATA_CIRCUIT_SYNC = 16; // 0x10
- field public static final int SERVICE_CLASS_DATA_PACKET_ACCESS = 64; // 0x40
- field public static final int SERVICE_CLASS_DATA_PAD = 128; // 0x80
- field public static final int SERVICE_CLASS_FAX = 4; // 0x4
- field public static final int SERVICE_CLASS_NONE = 0; // 0x0
- field public static final int SERVICE_CLASS_SMS = 8; // 0x8
- field public static final int SERVICE_CLASS_VOICE = 1; // 0x1
- field public static final int SS_ACTIVATION = 0; // 0x0
- field public static final int SS_ALL_BARRING = 18; // 0x12
- field public static final int SS_ALL_DATA_TELESERVICES = 3; // 0x3
- field public static final int SS_ALL_TELESERVICES_EXCEPT_SMS = 5; // 0x5
- field public static final int SS_ALL_TELESEVICES = 1; // 0x1
- field public static final int SS_ALL_TELE_AND_BEARER_SERVICES = 0; // 0x0
- field public static final int SS_BAIC = 16; // 0x10
- field public static final int SS_BAIC_ROAMING = 17; // 0x11
- field public static final int SS_BAOC = 13; // 0xd
- field public static final int SS_BAOIC = 14; // 0xe
- field public static final int SS_BAOIC_EXC_HOME = 15; // 0xf
- field public static final int SS_CFU = 0; // 0x0
- field public static final int SS_CFUT = 6; // 0x6
- field public static final int SS_CF_ALL = 4; // 0x4
- field public static final int SS_CF_ALL_CONDITIONAL = 5; // 0x5
- field public static final int SS_CF_BUSY = 1; // 0x1
- field public static final int SS_CF_NOT_REACHABLE = 3; // 0x3
- field public static final int SS_CF_NO_REPLY = 2; // 0x2
- field public static final int SS_CLIP = 7; // 0x7
- field public static final int SS_CLIR = 8; // 0x8
- field public static final int SS_CNAP = 11; // 0xb
- field public static final int SS_COLP = 9; // 0x9
- field public static final int SS_COLR = 10; // 0xa
- field public static final int SS_DEACTIVATION = 1; // 0x1
- field public static final int SS_ERASURE = 4; // 0x4
- field public static final int SS_INCOMING_BARRING = 20; // 0x14
- field public static final int SS_INCOMING_BARRING_ANONYMOUS = 22; // 0x16
- field public static final int SS_INCOMING_BARRING_DN = 21; // 0x15
- field public static final int SS_INTERROGATION = 2; // 0x2
- field public static final int SS_OUTGOING_BARRING = 19; // 0x13
- field public static final int SS_REGISTRATION = 3; // 0x3
- field public static final int SS_SMS_SERVICES = 4; // 0x4
- field public static final int SS_TELEPHONY = 2; // 0x2
- field public static final int SS_WAIT = 12; // 0xc
- }
-
- public static final class ImsSsData.Builder {
- ctor public ImsSsData.Builder(int, int, int, int, int);
- method @NonNull public android.telephony.ims.ImsSsData build();
- method @NonNull public android.telephony.ims.ImsSsData.Builder setCallForwardingInfo(@NonNull java.util.List<android.telephony.ims.ImsCallForwardInfo>);
- method @NonNull public android.telephony.ims.ImsSsData.Builder setSuppServiceInfo(@NonNull java.util.List<android.telephony.ims.ImsSsInfo>);
- }
-
- public final class ImsSsInfo implements android.os.Parcelable {
- ctor @Deprecated public ImsSsInfo(int, @Nullable String);
- method public int describeContents();
- method public int getClirInterrogationStatus();
- method public int getClirOutgoingState();
- method @Deprecated public String getIcbNum();
- method @Nullable public String getIncomingCommunicationBarringNumber();
- method public int getProvisionStatus();
- method public int getStatus();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CLIR_OUTGOING_DEFAULT = 0; // 0x0
- field public static final int CLIR_OUTGOING_INVOCATION = 1; // 0x1
- field public static final int CLIR_OUTGOING_SUPPRESSION = 2; // 0x2
- field public static final int CLIR_STATUS_NOT_PROVISIONED = 0; // 0x0
- field public static final int CLIR_STATUS_PROVISIONED_PERMANENT = 1; // 0x1
- field public static final int CLIR_STATUS_TEMPORARILY_ALLOWED = 4; // 0x4
- field public static final int CLIR_STATUS_TEMPORARILY_RESTRICTED = 3; // 0x3
- field public static final int CLIR_STATUS_UNKNOWN = 2; // 0x2
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsSsInfo> CREATOR;
- field public static final int DISABLED = 0; // 0x0
- field public static final int ENABLED = 1; // 0x1
- field public static final int NOT_REGISTERED = -1; // 0xffffffff
- field public static final int SERVICE_NOT_PROVISIONED = 0; // 0x0
- field public static final int SERVICE_PROVISIONED = 1; // 0x1
- field public static final int SERVICE_PROVISIONING_UNKNOWN = -1; // 0xffffffff
- }
-
- public static final class ImsSsInfo.Builder {
- ctor public ImsSsInfo.Builder(int);
- method @NonNull public android.telephony.ims.ImsSsInfo build();
- method @NonNull public android.telephony.ims.ImsSsInfo.Builder setClirInterrogationStatus(int);
- method @NonNull public android.telephony.ims.ImsSsInfo.Builder setClirOutgoingState(int);
- method @NonNull public android.telephony.ims.ImsSsInfo.Builder setIncomingCommunicationBarringNumber(@NonNull String);
- method @NonNull public android.telephony.ims.ImsSsInfo.Builder setProvisionStatus(int);
- }
-
- public final class ImsStreamMediaProfile implements android.os.Parcelable {
- ctor public ImsStreamMediaProfile(int, int, int, int, int);
- method public void copyFrom(android.telephony.ims.ImsStreamMediaProfile);
- method public int describeContents();
- method public int getAudioDirection();
- method public int getAudioQuality();
- method public int getRttMode();
- method public int getVideoDirection();
- method public int getVideoQuality();
- method public boolean isReceivingRttAudio();
- method public boolean isRttCall();
- method public void setReceivingRttAudio(boolean);
- method public void setRttMode(int);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int AUDIO_QUALITY_AMR = 1; // 0x1
- field public static final int AUDIO_QUALITY_AMR_WB = 2; // 0x2
- field public static final int AUDIO_QUALITY_EVRC = 4; // 0x4
- field public static final int AUDIO_QUALITY_EVRC_B = 5; // 0x5
- field public static final int AUDIO_QUALITY_EVRC_NW = 7; // 0x7
- field public static final int AUDIO_QUALITY_EVRC_WB = 6; // 0x6
- field public static final int AUDIO_QUALITY_EVS_FB = 20; // 0x14
- field public static final int AUDIO_QUALITY_EVS_NB = 17; // 0x11
- field public static final int AUDIO_QUALITY_EVS_SWB = 19; // 0x13
- field public static final int AUDIO_QUALITY_EVS_WB = 18; // 0x12
- field public static final int AUDIO_QUALITY_G711A = 13; // 0xd
- field public static final int AUDIO_QUALITY_G711AB = 15; // 0xf
- field public static final int AUDIO_QUALITY_G711U = 11; // 0xb
- field public static final int AUDIO_QUALITY_G722 = 14; // 0xe
- field public static final int AUDIO_QUALITY_G723 = 12; // 0xc
- field public static final int AUDIO_QUALITY_G729 = 16; // 0x10
- field public static final int AUDIO_QUALITY_GSM_EFR = 8; // 0x8
- field public static final int AUDIO_QUALITY_GSM_FR = 9; // 0x9
- field public static final int AUDIO_QUALITY_GSM_HR = 10; // 0xa
- field public static final int AUDIO_QUALITY_NONE = 0; // 0x0
- field public static final int AUDIO_QUALITY_QCELP13K = 3; // 0x3
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsStreamMediaProfile> CREATOR;
- field public static final int DIRECTION_INACTIVE = 0; // 0x0
- field public static final int DIRECTION_INVALID = -1; // 0xffffffff
- field public static final int DIRECTION_RECEIVE = 1; // 0x1
- field public static final int DIRECTION_SEND = 2; // 0x2
- field public static final int DIRECTION_SEND_RECEIVE = 3; // 0x3
- field public static final int RTT_MODE_DISABLED = 0; // 0x0
- field public static final int RTT_MODE_FULL = 1; // 0x1
- field public static final int VIDEO_QUALITY_NONE = 0; // 0x0
- field public static final int VIDEO_QUALITY_QCIF = 1; // 0x1
- field public static final int VIDEO_QUALITY_QVGA_LANDSCAPE = 2; // 0x2
- field public static final int VIDEO_QUALITY_QVGA_PORTRAIT = 4; // 0x4
- field public static final int VIDEO_QUALITY_VGA_LANDSCAPE = 8; // 0x8
- field public static final int VIDEO_QUALITY_VGA_PORTRAIT = 16; // 0x10
- }
-
- public final class ImsSuppServiceNotification implements android.os.Parcelable {
- ctor public ImsSuppServiceNotification(int, int, int, int, String, String[]);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsSuppServiceNotification> CREATOR;
- field public final int code;
- field public final String[] history;
- field public final int index;
- field public final int notificationType;
- field public final String number;
- field public final int type;
- }
-
- public class ImsUtListener {
- method public void onLineIdentificationSupplementaryServiceResponse(int, @NonNull android.telephony.ims.ImsSsInfo);
- method public void onSupplementaryServiceIndication(android.telephony.ims.ImsSsData);
- method public void onUtConfigurationCallBarringQueried(int, android.telephony.ims.ImsSsInfo[]);
- method public void onUtConfigurationCallForwardQueried(int, android.telephony.ims.ImsCallForwardInfo[]);
- method public void onUtConfigurationCallWaitingQueried(int, android.telephony.ims.ImsSsInfo[]);
- method @Deprecated public void onUtConfigurationQueried(int, android.os.Bundle);
- method public void onUtConfigurationQueryFailed(int, android.telephony.ims.ImsReasonInfo);
- method public void onUtConfigurationUpdateFailed(int, android.telephony.ims.ImsReasonInfo);
- method public void onUtConfigurationUpdated(int);
- field @Deprecated public static final String BUNDLE_KEY_CLIR = "queryClir";
- field @Deprecated public static final String BUNDLE_KEY_SSINFO = "imsSsInfo";
- }
-
- public abstract class ImsVideoCallProvider {
- ctor public ImsVideoCallProvider();
- method public void changeCallDataUsage(long);
- method public void changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities);
- method public void changePeerDimensions(int, int);
- method public void changeVideoQuality(int);
- method public void handleCallSessionEvent(int);
- method public abstract void onRequestCallDataUsage();
- method public abstract void onRequestCameraCapabilities();
- method public abstract void onSendSessionModifyRequest(android.telecom.VideoProfile, android.telecom.VideoProfile);
- method public abstract void onSendSessionModifyResponse(android.telecom.VideoProfile);
- method public abstract void onSetCamera(String);
- method public void onSetCamera(String, int);
- method public abstract void onSetDeviceOrientation(int);
- method public abstract void onSetDisplaySurface(android.view.Surface);
- method public abstract void onSetPauseImage(android.net.Uri);
- method public abstract void onSetPreviewSurface(android.view.Surface);
- method public abstract void onSetZoom(float);
- method public void receiveSessionModifyRequest(android.telecom.VideoProfile);
- method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
- }
-
- public class ProvisioningManager {
- method @NonNull public static android.telephony.ims.ProvisioningManager createForSubscriptionId(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getProvisioningIntValue(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(int, int);
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException;
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(int, int, boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
- field public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67; // 0x43
- field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
- field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
- field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
- field public static final int PROVISIONING_VALUE_ENABLED = 1; // 0x1
- field public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC";
- field public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY";
- }
-
- public static class ProvisioningManager.Callback {
- ctor public ProvisioningManager.Callback();
- method public void onProvisioningIntChanged(int, int);
- method public void onProvisioningStringChanged(int, @NonNull String);
- }
-
- public class RcsUceAdapter {
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
- }
-
- public class SipDelegateManager {
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSupported() throws android.telephony.ims.ImsException;
- }
-
-}
-
-package android.telephony.ims.feature {
-
- public final class CapabilityChangeRequest implements android.os.Parcelable {
- method public void addCapabilitiesToDisableForTech(int, int);
- method public void addCapabilitiesToEnableForTech(int, int);
- method public int describeContents();
- method public java.util.List<android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair> getCapabilitiesToDisable();
- method public java.util.List<android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair> getCapabilitiesToEnable();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.feature.CapabilityChangeRequest> CREATOR;
- }
-
- public static class CapabilityChangeRequest.CapabilityPair {
- ctor public CapabilityChangeRequest.CapabilityPair(int, int);
- method public int getCapability();
- method public int getRadioTech();
- }
-
- public abstract class ImsFeature {
- ctor public ImsFeature();
- method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
- method public int getFeatureState();
- method public final int getSlotIndex();
- method public abstract void onFeatureReady();
- method public abstract void onFeatureRemoved();
- method public final void setFeatureState(int);
- field public static final int CAPABILITY_ERROR_GENERIC = -1; // 0xffffffff
- field public static final int CAPABILITY_SUCCESS = 0; // 0x0
- field public static final int FEATURE_EMERGENCY_MMTEL = 0; // 0x0
- field public static final int FEATURE_MMTEL = 1; // 0x1
- field public static final int FEATURE_RCS = 2; // 0x2
- field public static final int STATE_INITIALIZING = 1; // 0x1
- field public static final int STATE_READY = 2; // 0x2
- field public static final int STATE_UNAVAILABLE = 0; // 0x0
- }
-
- @Deprecated public static class ImsFeature.Capabilities {
- field @Deprecated protected int mCapabilities;
- }
-
- protected static class ImsFeature.CapabilityCallbackProxy {
- method public void onChangeCapabilityConfigurationError(int, int, int);
- }
-
- public class MmTelFeature extends android.telephony.ims.feature.ImsFeature {
- ctor public MmTelFeature();
- method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
- method @Nullable public android.telephony.ims.ImsCallProfile createCallProfile(int, int);
- method @Nullable public android.telephony.ims.stub.ImsCallSessionImplBase createCallSession(@NonNull android.telephony.ims.ImsCallProfile);
- method @NonNull public android.telephony.ims.stub.ImsEcbmImplBase getEcbm();
- method @NonNull public android.telephony.ims.stub.ImsMultiEndpointImplBase getMultiEndpoint();
- method @NonNull public android.telephony.ims.stub.ImsSmsImplBase getSmsImplementation();
- method @NonNull public android.telephony.ims.stub.ImsUtImplBase getUt();
- method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
- method public final void notifyIncomingCall(@NonNull android.telephony.ims.stub.ImsCallSessionImplBase, @NonNull android.os.Bundle);
- method public final void notifyRejectedCall(@NonNull android.telephony.ims.ImsCallProfile, @NonNull android.telephony.ims.ImsReasonInfo);
- method public final void notifyVoiceMessageCountUpdate(int);
- method public void onFeatureReady();
- method public void onFeatureRemoved();
- method public boolean queryCapabilityConfiguration(int, int);
- method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
- method public void setUiTtyMode(int, @Nullable android.os.Message);
- method public int shouldProcessCall(@NonNull String[]);
- field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL";
- field public static final String EXTRA_IS_USSD = "android.telephony.ims.feature.extra.IS_USSD";
- field public static final int PROCESS_CALL_CSFB = 1; // 0x1
- field public static final int PROCESS_CALL_IMS = 0; // 0x0
- }
-
- public static class MmTelFeature.MmTelCapabilities extends android.telephony.ims.feature.ImsFeature.Capabilities {
- ctor public MmTelFeature.MmTelCapabilities();
- ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
- ctor public MmTelFeature.MmTelCapabilities(int);
- method public final void addCapabilities(int);
- method public final void removeCapabilities(int);
- }
-
- public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
- ctor public RcsFeature();
- method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
- method public void onFeatureReady();
- method public void onFeatureRemoved();
- }
-
-}
-
-package android.telephony.ims.stub {
-
- public class ImsCallSessionImplBase implements java.lang.AutoCloseable {
- ctor public ImsCallSessionImplBase();
- method public void accept(int, android.telephony.ims.ImsStreamMediaProfile);
- method public void close();
- method public void deflect(String);
- method public void extendToConference(String[]);
- method public String getCallId();
- method public android.telephony.ims.ImsCallProfile getCallProfile();
- method public android.telephony.ims.ImsVideoCallProvider getImsVideoCallProvider();
- method public android.telephony.ims.ImsCallProfile getLocalCallProfile();
- method public String getProperty(String);
- method public android.telephony.ims.ImsCallProfile getRemoteCallProfile();
- method public int getState();
- method public void hold(android.telephony.ims.ImsStreamMediaProfile);
- method public void inviteParticipants(String[]);
- method public boolean isInCall();
- method public boolean isMultiparty();
- method public void merge();
- method public void reject(int);
- method public void removeParticipants(String[]);
- method public void resume(android.telephony.ims.ImsStreamMediaProfile);
- method public void sendDtmf(char, android.os.Message);
- method public void sendRttMessage(String);
- method public void sendRttModifyRequest(android.telephony.ims.ImsCallProfile);
- method public void sendRttModifyResponse(boolean);
- method public void sendUssd(String);
- method public void setListener(android.telephony.ims.ImsCallSessionListener);
- method public void setMute(boolean);
- method public void start(String, android.telephony.ims.ImsCallProfile);
- method public void startConference(String[], android.telephony.ims.ImsCallProfile);
- method public void startDtmf(char);
- method public void stopDtmf();
- method public void terminate(int);
- method public void update(int, android.telephony.ims.ImsStreamMediaProfile);
- field public static final int USSD_MODE_NOTIFY = 0; // 0x0
- field public static final int USSD_MODE_REQUEST = 1; // 0x1
- }
-
- public static class ImsCallSessionImplBase.State {
- method public static String toString(int);
- field public static final int ESTABLISHED = 4; // 0x4
- field public static final int ESTABLISHING = 3; // 0x3
- field public static final int IDLE = 0; // 0x0
- field public static final int INITIATED = 1; // 0x1
- field public static final int INVALID = -1; // 0xffffffff
- field public static final int NEGOTIATING = 2; // 0x2
- field public static final int REESTABLISHING = 6; // 0x6
- field public static final int RENEGOTIATING = 5; // 0x5
- field public static final int TERMINATED = 8; // 0x8
- field public static final int TERMINATING = 7; // 0x7
- }
-
- public class ImsConfigImplBase {
- ctor public ImsConfigImplBase();
- method public int getConfigInt(int);
- method public String getConfigString(int);
- method public final void notifyProvisionedValueChanged(int, int);
- method public final void notifyProvisionedValueChanged(int, String);
- method public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean);
- method public int setConfig(int, int);
- method public int setConfig(int, String);
- field public static final int CONFIG_RESULT_FAILED = 1; // 0x1
- field public static final int CONFIG_RESULT_SUCCESS = 0; // 0x0
- field public static final int CONFIG_RESULT_UNKNOWN = -1; // 0xffffffff
- }
-
- public class ImsEcbmImplBase {
- ctor public ImsEcbmImplBase();
- method public final void enteredEcbm();
- method public void exitEmergencyCallbackMode();
- method public final void exitedEcbm();
- }
-
- public final class ImsFeatureConfiguration implements android.os.Parcelable {
- method public int describeContents();
- method public java.util.Set<android.telephony.ims.stub.ImsFeatureConfiguration.FeatureSlotPair> getServiceFeatures();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.stub.ImsFeatureConfiguration> CREATOR;
- }
-
- public static class ImsFeatureConfiguration.Builder {
- ctor public ImsFeatureConfiguration.Builder();
- method public android.telephony.ims.stub.ImsFeatureConfiguration.Builder addFeature(int, int);
- method public android.telephony.ims.stub.ImsFeatureConfiguration build();
- }
-
- public static final class ImsFeatureConfiguration.FeatureSlotPair {
- ctor public ImsFeatureConfiguration.FeatureSlotPair(int, int);
- field public final int featureType;
- field public final int slotId;
- }
-
- public class ImsMultiEndpointImplBase {
- ctor public ImsMultiEndpointImplBase();
- method public final void onImsExternalCallStateUpdate(java.util.List<android.telephony.ims.ImsExternalCallState>);
- method public void requestImsExternalCallStateInfo();
- }
-
- public class ImsRegistrationImplBase {
- ctor public ImsRegistrationImplBase();
- method public final void onDeregistered(android.telephony.ims.ImsReasonInfo);
- method public final void onRegistered(int);
- method public final void onRegistering(int);
- method public final void onSubscriberAssociatedUriChanged(android.net.Uri[]);
- method public final void onTechnologyChangeFailed(int, android.telephony.ims.ImsReasonInfo);
- field public static final int REGISTRATION_TECH_IWLAN = 1; // 0x1
- field public static final int REGISTRATION_TECH_LTE = 0; // 0x0
- field public static final int REGISTRATION_TECH_NONE = -1; // 0xffffffff
- }
-
- public class ImsSmsImplBase {
- ctor public ImsSmsImplBase();
- method public void acknowledgeSms(int, @IntRange(from=0, to=65535) int, int);
- method public void acknowledgeSmsReport(int, @IntRange(from=0, to=65535) int, int);
- method public String getSmsFormat();
- method public void onReady();
- method @Deprecated public final void onSendSmsResult(int, @IntRange(from=0, to=65535) int, int, int) throws java.lang.RuntimeException;
- method public final void onSendSmsResultError(int, @IntRange(from=0, to=65535) int, int, int, int) throws java.lang.RuntimeException;
- method public final void onSendSmsResultSuccess(int, @IntRange(from=0, to=65535) int) throws java.lang.RuntimeException;
- method public final void onSmsReceived(int, String, byte[]) throws java.lang.RuntimeException;
- method @Deprecated public final void onSmsStatusReportReceived(int, @IntRange(from=0, to=65535) int, String, byte[]) throws java.lang.RuntimeException;
- method public final void onSmsStatusReportReceived(int, String, byte[]) throws java.lang.RuntimeException;
- method public void sendSms(int, @IntRange(from=0, to=65535) int, String, String, boolean, byte[]);
- field public static final int DELIVER_STATUS_ERROR_GENERIC = 2; // 0x2
- field public static final int DELIVER_STATUS_ERROR_NO_MEMORY = 3; // 0x3
- field public static final int DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED = 4; // 0x4
- field public static final int DELIVER_STATUS_OK = 1; // 0x1
- field public static final int RESULT_NO_NETWORK_ERROR = -1; // 0xffffffff
- field public static final int SEND_STATUS_ERROR = 2; // 0x2
- field public static final int SEND_STATUS_ERROR_FALLBACK = 4; // 0x4
- field public static final int SEND_STATUS_ERROR_RETRY = 3; // 0x3
- field public static final int SEND_STATUS_OK = 1; // 0x1
- field public static final int STATUS_REPORT_STATUS_ERROR = 2; // 0x2
- field public static final int STATUS_REPORT_STATUS_OK = 1; // 0x1
- }
-
- public class ImsUtImplBase {
- ctor public ImsUtImplBase();
- method public void close();
- method public int queryCallBarring(int);
- method public int queryCallBarringForServiceClass(int, int);
- method public int queryCallForward(int, String);
- method public int queryCallWaiting();
- method public int queryClip();
- method public int queryClir();
- method public int queryColp();
- method public int queryColr();
- method public void setListener(android.telephony.ims.ImsUtListener);
- method public int transact(android.os.Bundle);
- method public int updateCallBarring(int, int, String[]);
- method public int updateCallBarringForServiceClass(int, int, String[], int);
- method public int updateCallForward(int, int, String, int, int);
- method public int updateCallWaiting(boolean, int);
- method public int updateClip(boolean);
- method public int updateClir(int);
- method public int updateColp(boolean);
- method public int updateColr(int);
- }
-
- public class SipTransportImplBase {
- ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor);
- }
-
-}
-
-package android.telephony.mbms {
-
- public static class DownloadRequest.Builder {
- method public android.telephony.mbms.DownloadRequest.Builder setServiceId(String);
- }
-
- public final class FileInfo implements android.os.Parcelable {
- ctor public FileInfo(android.net.Uri, String);
- }
-
- public final class FileServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
- ctor public FileServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>);
- }
-
- public class MbmsDownloadReceiver extends android.content.BroadcastReceiver {
- field public static final int RESULT_APP_NOTIFICATION_ERROR = 6; // 0x6
- field public static final int RESULT_BAD_TEMP_FILE_ROOT = 3; // 0x3
- field public static final int RESULT_DOWNLOAD_FINALIZATION_ERROR = 4; // 0x4
- field public static final int RESULT_INVALID_ACTION = 1; // 0x1
- field public static final int RESULT_MALFORMED_INTENT = 2; // 0x2
- field public static final int RESULT_OK = 0; // 0x0
- field public static final int RESULT_TEMP_FILE_GENERATION_ERROR = 5; // 0x5
- }
-
- public final class StreamingServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
- ctor public StreamingServiceInfo(java.util.Map<java.util.Locale,java.lang.String>, String, java.util.List<java.util.Locale>, String, java.util.Date, java.util.Date);
- }
-
- public final class UriPathPair implements android.os.Parcelable {
- method public int describeContents();
- method public android.net.Uri getContentUri();
- method public android.net.Uri getFilePathUri();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.mbms.UriPathPair> CREATOR;
- }
-
-}
-
-package android.telephony.mbms.vendor {
-
- public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface {
- ctor public MbmsDownloadServiceBase();
- method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
- method public int addServiceAnnouncement(int, @NonNull byte[]);
- method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
- method public android.os.IBinder asBinder();
- method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
- method public void dispose(int) throws android.os.RemoteException;
- method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
- method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException;
- method @NonNull public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException;
- method public void onAppCallbackDied(int, int);
- method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
- method public int removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
- method public int removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
- method public int requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) throws android.os.RemoteException;
- method public int requestUpdateFileServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
- method public int resetDownloadKnowledge(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
- method public int setTempFileRootDirectory(int, String) throws android.os.RemoteException;
- }
-
- public class MbmsGroupCallServiceBase extends android.app.Service {
- ctor public MbmsGroupCallServiceBase();
- method public void dispose(int) throws android.os.RemoteException;
- method public int initialize(@NonNull android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException;
- method public void onAppCallbackDied(int, int);
- method public android.os.IBinder onBind(android.content.Intent);
- method public int startGroupCall(int, long, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>, @NonNull android.telephony.mbms.GroupCallCallback);
- method public void stopGroupCall(int, long);
- method public void updateGroupCall(int, long, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>);
- }
-
- public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface {
- ctor public MbmsStreamingServiceBase();
- method public android.os.IBinder asBinder();
- method public void dispose(int) throws android.os.RemoteException;
- method @Nullable public android.net.Uri getPlaybackUri(int, String) throws android.os.RemoteException;
- method public int initialize(android.telephony.mbms.MbmsStreamingSessionCallback, int) throws android.os.RemoteException;
- method public void onAppCallbackDied(int, int);
- method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
- method public int requestUpdateStreamingServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
- method public int startStreaming(int, String, android.telephony.mbms.StreamingServiceCallback) throws android.os.RemoteException;
- method public void stopStreaming(int, String) throws android.os.RemoteException;
- }
-
- public class VendorUtils {
- ctor public VendorUtils();
- method public static android.content.ComponentName getAppReceiverFromPackageName(android.content.Context, String);
- field public static final String ACTION_CLEANUP = "android.telephony.mbms.action.CLEANUP";
- field public static final String ACTION_DOWNLOAD_RESULT_INTERNAL = "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL";
- field public static final String ACTION_FILE_DESCRIPTOR_REQUEST = "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST";
- field public static final String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT";
- field public static final String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI";
- field public static final String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST";
- field public static final String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST";
- field public static final String EXTRA_PAUSED_URI_LIST = "android.telephony.mbms.extra.PAUSED_URI_LIST";
- field public static final String EXTRA_SERVICE_ID = "android.telephony.mbms.extra.SERVICE_ID";
- field public static final String EXTRA_TEMP_FILES_IN_USE = "android.telephony.mbms.extra.TEMP_FILES_IN_USE";
- field public static final String EXTRA_TEMP_FILE_ROOT = "android.telephony.mbms.extra.TEMP_FILE_ROOT";
- field public static final String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST";
- }
-
-}
-
-package android.util {
-
- public class EventLog {
- method public static void readEventsOnWrapping(int[], long, java.util.Collection<android.util.EventLog.Event>) throws java.io.IOException;
- }
-
- public static final class EventLog.Event {
- method public int getUid();
- }
-
- public final class StatsEvent {
- method @NonNull public static android.util.StatsEvent.Builder newBuilder();
- }
-
- public static final class StatsEvent.Builder {
- method @NonNull public android.util.StatsEvent.Builder addBooleanAnnotation(byte, boolean);
- method @NonNull public android.util.StatsEvent.Builder addIntAnnotation(byte, int);
- method @NonNull public android.util.StatsEvent build();
- method @NonNull public android.util.StatsEvent.Builder setAtomId(int);
- method @NonNull public android.util.StatsEvent.Builder usePooledBuffer();
- method @NonNull public android.util.StatsEvent.Builder writeAttributionChain(@NonNull int[], @NonNull String[]);
- method @NonNull public android.util.StatsEvent.Builder writeBoolean(boolean);
- method @NonNull public android.util.StatsEvent.Builder writeByteArray(@NonNull byte[]);
- method @NonNull public android.util.StatsEvent.Builder writeFloat(float);
- method @NonNull public android.util.StatsEvent.Builder writeInt(int);
- method @NonNull public android.util.StatsEvent.Builder writeKeyValuePairs(@Nullable android.util.SparseIntArray, @Nullable android.util.SparseLongArray, @Nullable android.util.SparseArray<java.lang.String>, @Nullable android.util.SparseArray<java.lang.Float>);
- method @NonNull public android.util.StatsEvent.Builder writeLong(long);
- method @NonNull public android.util.StatsEvent.Builder writeString(@NonNull String);
- }
-
- public final class StatsLog {
- method public static void write(@NonNull android.util.StatsEvent);
- method public static void writeRaw(@NonNull byte[], int);
- }
-
-}
-
-package android.view {
-
- public abstract class Window {
- method public void addSystemFlags(@android.view.WindowManager.LayoutParams.SystemFlags int);
- }
-
- public interface WindowManager extends android.view.ViewManager {
- method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public android.graphics.Region getCurrentImeTouchRegion();
- }
-
- public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
- method public final long getUserActivityTimeout();
- method public final void setUserActivityTimeout(long);
- field @RequiresPermission(android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS) public static final int SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 524288; // 0x80000
- field @RequiresPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW) public static final int SYSTEM_FLAG_SHOW_FOR_ALL_USERS = 16; // 0x10
- }
-
- @IntDef(flag=true, prefix={"SYSTEM_FLAG_"}, value={android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface WindowManager.LayoutParams.SystemFlags {
- }
-
-}
-
-package android.view.accessibility {
-
- public final class AccessibilityManager {
- method public int getAccessibilityWindowId(@Nullable android.os.IBinder);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut();
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void registerSystemAction(@NonNull android.app.RemoteAction, int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void unregisterSystemAction(int);
- }
-
-}
-
-package android.view.autofill {
-
- public final class AutofillManager {
- method public void setAugmentedAutofillWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>);
- }
-
-}
-
-package android.view.contentcapture {
-
- public final class ContentCaptureContext implements android.os.Parcelable {
- method @Nullable public android.content.ComponentName getActivityComponent();
- method public int getDisplayId();
- method public int getFlags();
- method @Nullable public android.view.contentcapture.ContentCaptureSessionId getParentSessionId();
- method public int getTaskId();
- field public static final int FLAG_DISABLED_BY_APP = 1; // 0x1
- field public static final int FLAG_DISABLED_BY_FLAG_SECURE = 2; // 0x2
- field public static final int FLAG_RECONNECTED = 4; // 0x4
- }
-
- public final class ContentCaptureEvent implements android.os.Parcelable {
- method public int describeContents();
- method @Nullable public android.view.contentcapture.ContentCaptureContext getContentCaptureContext();
- method public long getEventTime();
- method @Nullable public android.view.autofill.AutofillId getId();
- method @Nullable public java.util.List<android.view.autofill.AutofillId> getIds();
- method @Nullable public android.graphics.Insets getInsets();
- method @Nullable public CharSequence getText();
- method public int getType();
- method @Nullable public android.view.contentcapture.ViewNode getViewNode();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureEvent> CREATOR;
- field public static final int TYPE_CONTEXT_UPDATED = 6; // 0x6
- field public static final int TYPE_SESSION_PAUSED = 8; // 0x8
- field public static final int TYPE_SESSION_RESUMED = 7; // 0x7
- field public static final int TYPE_VIEW_APPEARED = 1; // 0x1
- field public static final int TYPE_VIEW_DISAPPEARED = 2; // 0x2
- field public static final int TYPE_VIEW_INSETS_CHANGED = 9; // 0x9
- field public static final int TYPE_VIEW_TEXT_CHANGED = 3; // 0x3
- field public static final int TYPE_VIEW_TREE_APPEARED = 5; // 0x5
- field public static final int TYPE_VIEW_TREE_APPEARING = 4; // 0x4
- }
-
- public final class ContentCaptureManager {
- method public boolean isContentCaptureFeatureEnabled();
- field public static final int NO_SESSION_ID = 0; // 0x0
- }
-
- public final class ViewNode extends android.app.assist.AssistStructure.ViewNode {
- method @Nullable public android.view.autofill.AutofillId getParentAutofillId();
- }
-
-}
-
-package android.webkit {
-
- public abstract class CookieManager {
- method protected abstract boolean allowFileSchemeCookiesImpl();
- method public abstract String getCookie(String, boolean);
- method public String getCookie(android.net.WebAddress);
- method public abstract boolean hasCookies(boolean);
- method protected abstract void setAcceptFileSchemeCookiesImpl(boolean);
- }
-
- public class FindActionModeCallback implements android.view.ActionMode.Callback android.text.TextWatcher android.view.View.OnClickListener android.webkit.WebView.FindListener {
- ctor public FindActionModeCallback(android.content.Context);
- method public void afterTextChanged(android.text.Editable);
- method public void beforeTextChanged(CharSequence, int, int, int);
- method public void findAll();
- method public void finish();
- method public int getActionModeGlobalBottom();
- method public boolean onActionItemClicked(android.view.ActionMode, android.view.MenuItem);
- method public void onClick(android.view.View);
- method public boolean onCreateActionMode(android.view.ActionMode, android.view.Menu);
- method public void onDestroyActionMode(android.view.ActionMode);
- method public void onFindResultReceived(int, int, boolean);
- method public boolean onPrepareActionMode(android.view.ActionMode, android.view.Menu);
- method public void onTextChanged(CharSequence, int, int, int);
- method public void setText(String);
- method public void setWebView(@NonNull android.webkit.WebView);
- method public void showSoftInput();
- method public void updateMatchCount(int, int, boolean);
- }
-
- public static class FindActionModeCallback.NoAction implements android.view.ActionMode.Callback {
- ctor public FindActionModeCallback.NoAction();
- method public boolean onActionItemClicked(android.view.ActionMode, android.view.MenuItem);
- method public boolean onCreateActionMode(android.view.ActionMode, android.view.Menu);
- method public void onDestroyActionMode(android.view.ActionMode);
- method public boolean onPrepareActionMode(android.view.ActionMode, android.view.Menu);
- }
-
- public class GeolocationPermissions {
- ctor public GeolocationPermissions();
- }
-
- public class HttpAuthHandler extends android.os.Handler {
- ctor public HttpAuthHandler();
- }
-
- public class JsDialogHelper {
- ctor public JsDialogHelper(android.webkit.JsPromptResult, int, String, String, String);
- ctor public JsDialogHelper(android.webkit.JsPromptResult, android.os.Message);
- method public boolean invokeCallback(android.webkit.WebChromeClient, android.webkit.WebView);
- method public void showDialog(android.content.Context);
- field public static final int ALERT = 1; // 0x1
- field public static final int CONFIRM = 2; // 0x2
- field public static final int PROMPT = 3; // 0x3
- field public static final int UNLOAD = 4; // 0x4
- }
-
- public class JsPromptResult extends android.webkit.JsResult {
- ctor public JsPromptResult(android.webkit.JsResult.ResultReceiver);
- method public String getStringResult();
- }
-
- public class JsResult {
- ctor public JsResult(android.webkit.JsResult.ResultReceiver);
- method public final boolean getResult();
- }
-
- public static interface JsResult.ResultReceiver {
- method public void onJsResultComplete(android.webkit.JsResult);
- }
-
- public interface PacProcessor {
- method @NonNull public static android.webkit.PacProcessor createInstance();
- method @Nullable public String findProxyForUrl(@NonNull String);
- method @NonNull public static android.webkit.PacProcessor getInstance();
- method @Nullable public default android.net.Network getNetwork();
- method public default void release();
- method public default void setNetwork(@Nullable android.net.Network);
- method public boolean setProxyScript(@NonNull String);
- }
-
- public class SslErrorHandler extends android.os.Handler {
- ctor public SslErrorHandler();
- }
-
- @Deprecated public abstract class TokenBindingService {
- ctor @Deprecated public TokenBindingService();
- }
-
- public class WebChromeClient {
- method @Deprecated public void openFileChooser(android.webkit.ValueCallback<android.net.Uri>, String, String);
- }
-
- public abstract class WebHistoryItem implements java.lang.Cloneable {
- method @Deprecated public abstract int getId();
- }
-
- @Deprecated public abstract class WebIconDatabase {
- method @Deprecated public abstract void bulkRequestIconForPageUrl(android.content.ContentResolver, String, android.webkit.WebIconDatabase.IconListener);
- }
-
- public abstract class WebMessagePort {
- ctor public WebMessagePort();
- }
-
- public abstract class WebResourceError {
- ctor public WebResourceError();
- }
-
- public class WebResourceResponse {
- ctor public WebResourceResponse(boolean, String, String, int, String, java.util.Map<java.lang.String,java.lang.String>, java.io.InputStream);
- }
-
- public abstract class WebSettings {
- method public abstract boolean getAcceptThirdPartyCookies();
- method @Deprecated public abstract boolean getNavDump();
- method @Deprecated public abstract boolean getPluginsEnabled();
- method @Deprecated public abstract boolean getUseWebViewBackgroundForOverscrollBackground();
- method @Deprecated public abstract int getUserAgent();
- method public abstract boolean getVideoOverlayForEmbeddedEncryptedVideoEnabled();
- method public abstract void setAcceptThirdPartyCookies(boolean);
- method @Deprecated public abstract void setNavDump(boolean);
- method @Deprecated public abstract void setPluginsEnabled(boolean);
- method @Deprecated public abstract void setUseWebViewBackgroundForOverscrollBackground(boolean);
- method @Deprecated public abstract void setUserAgent(int);
- method public abstract void setVideoOverlayForEmbeddedEncryptedVideoEnabled(boolean);
- }
-
- public class WebStorage {
- ctor public WebStorage();
- }
-
- public static class WebStorage.Origin {
- ctor protected WebStorage.Origin(String, long, long);
- }
-
- public class WebView extends android.widget.AbsoluteLayout implements android.view.ViewGroup.OnHierarchyChangeListener android.view.ViewTreeObserver.OnGlobalFocusChangeListener {
- method public android.webkit.WebViewProvider getWebViewProvider();
- }
-
- public static class WebView.HitTestResult {
- ctor public WebView.HitTestResult();
- method public void setExtra(String);
- method public void setType(int);
- }
-
- public class WebView.PrivateAccess {
- ctor public WebView.PrivateAccess();
- method public void awakenScrollBars(int);
- method public void awakenScrollBars(int, boolean);
- method public float getHorizontalScrollFactor();
- method public int getHorizontalScrollbarHeight();
- method public float getVerticalScrollFactor();
- method public void onScrollChanged(int, int, int, int);
- method public void overScrollBy(int, int, int, int, int, int, int, int, boolean);
- method public void setMeasuredDimension(int, int);
- method public void setScrollXRaw(int);
- method public void setScrollYRaw(int);
- method public void super_computeScroll();
- method public boolean super_dispatchKeyEvent(android.view.KeyEvent);
- method public int super_getScrollBarStyle();
- method @Nullable public android.view.WindowInsets super_onApplyWindowInsets(@Nullable android.view.WindowInsets);
- method public void super_onDrawVerticalScrollBar(android.graphics.Canvas, android.graphics.drawable.Drawable, int, int, int, int);
- method public boolean super_onGenericMotionEvent(android.view.MotionEvent);
- method public boolean super_onHoverEvent(android.view.MotionEvent);
- method public boolean super_performAccessibilityAction(int, android.os.Bundle);
- method public boolean super_performLongClick();
- method public boolean super_requestFocus(int, android.graphics.Rect);
- method public void super_scrollTo(int, int);
- method public boolean super_setFrame(int, int, int, int);
- method public void super_setLayoutParams(android.view.ViewGroup.LayoutParams);
- method public void super_startActivityForResult(android.content.Intent, int);
- }
-
- public final class WebViewDelegate {
- method public void addWebViewAssetPath(android.content.Context);
- method @Deprecated public void callDrawGlFunction(android.graphics.Canvas, long);
- method @Deprecated public void callDrawGlFunction(@NonNull android.graphics.Canvas, long, @Nullable Runnable);
- method @Deprecated public boolean canInvokeDrawGlFunctor(android.view.View);
- method @Deprecated public void detachDrawGlFunctor(android.view.View, long);
- method public void drawWebViewFunctor(@NonNull android.graphics.Canvas, int);
- method public android.app.Application getApplication();
- method public String getDataDirectorySuffix();
- method public String getErrorString(android.content.Context, int);
- method public int getPackageId(android.content.res.Resources, String);
- method @Deprecated public void invokeDrawGlFunctor(android.view.View, long, boolean);
- method public boolean isMultiProcessEnabled();
- method public boolean isTraceTagEnabled();
- method public void setOnTraceEnabledChangeListener(android.webkit.WebViewDelegate.OnTraceEnabledChangeListener);
- }
-
- public static interface WebViewDelegate.OnTraceEnabledChangeListener {
- method public void onTraceEnabledChange(boolean);
- }
-
- public final class WebViewFactory {
- ctor public WebViewFactory();
- method public static android.content.pm.PackageInfo getLoadedPackageInfo();
- method public static int loadWebViewNativeLibraryFromPackage(String, ClassLoader);
- method public static void prepareWebViewInZygote();
- field public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2; // 0x2
- field public static final int LIBLOAD_FAILED_JNI_CALL = 7; // 0x7
- field public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4; // 0x4
- field public static final int LIBLOAD_FAILED_TO_FIND_NAMESPACE = 10; // 0xa
- field public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6; // 0x6
- field public static final int LIBLOAD_FAILED_TO_OPEN_RELRO_FILE = 5; // 0x5
- field public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3; // 0x3
- field public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 8; // 0x8
- field public static final int LIBLOAD_SUCCESS = 0; // 0x0
- field public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1; // 0x1
- }
-
- public interface WebViewFactoryProvider {
- method @NonNull public default android.webkit.PacProcessor createPacProcessor();
- method public android.webkit.WebViewProvider createWebView(android.webkit.WebView, android.webkit.WebView.PrivateAccess);
- method public android.webkit.CookieManager getCookieManager();
- method public android.webkit.GeolocationPermissions getGeolocationPermissions();
- method @NonNull public default android.webkit.PacProcessor getPacProcessor();
- method public android.webkit.ServiceWorkerController getServiceWorkerController();
- method public android.webkit.WebViewFactoryProvider.Statics getStatics();
- method @Deprecated public android.webkit.TokenBindingService getTokenBindingService();
- method public android.webkit.TracingController getTracingController();
- method public android.webkit.WebIconDatabase getWebIconDatabase();
- method public android.webkit.WebStorage getWebStorage();
- method public ClassLoader getWebViewClassLoader();
- method public android.webkit.WebViewDatabase getWebViewDatabase(android.content.Context);
- }
-
- public static interface WebViewFactoryProvider.Statics {
- method public void clearClientCertPreferences(Runnable);
- method public void enableSlowWholeDocumentDraw();
- method public String findAddress(String);
- method public void freeMemoryForTests();
- method public String getDefaultUserAgent(android.content.Context);
- method @NonNull public android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
- method public void initSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
- method public android.net.Uri[] parseFileChooserResult(int, android.content.Intent);
- method public void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
- method public void setWebContentsDebuggingEnabled(boolean);
- }
-
- public interface WebViewProvider {
- method public void addJavascriptInterface(Object, String);
- method public boolean canGoBack();
- method public boolean canGoBackOrForward(int);
- method public boolean canGoForward();
- method public boolean canZoomIn();
- method public boolean canZoomOut();
- method public android.graphics.Picture capturePicture();
- method public void clearCache(boolean);
- method public void clearFormData();
- method public void clearHistory();
- method public void clearMatches();
- method public void clearSslPreferences();
- method public void clearView();
- method public android.webkit.WebBackForwardList copyBackForwardList();
- method public android.print.PrintDocumentAdapter createPrintDocumentAdapter(String);
- method public android.webkit.WebMessagePort[] createWebMessageChannel();
- method public void destroy();
- method public void documentHasImages(android.os.Message);
- method public void dumpViewHierarchyWithProperties(java.io.BufferedWriter, int);
- method public void evaluateJavaScript(String, android.webkit.ValueCallback<java.lang.String>);
- method public int findAll(String);
- method public void findAllAsync(String);
- method public android.view.View findHierarchyView(String, int);
- method public void findNext(boolean);
- method public void flingScroll(int, int);
- method public void freeMemory();
- method public android.net.http.SslCertificate getCertificate();
- method public int getContentHeight();
- method public int getContentWidth();
- method public android.graphics.Bitmap getFavicon();
- method public android.webkit.WebView.HitTestResult getHitTestResult();
- method public String[] getHttpAuthUsernamePassword(String, String);
- method public String getOriginalUrl();
- method public int getProgress();
- method public boolean getRendererPriorityWaivedWhenNotVisible();
- method public int getRendererRequestedPriority();
- method public float getScale();
- method public android.webkit.WebViewProvider.ScrollDelegate getScrollDelegate();
- method public android.webkit.WebSettings getSettings();
- method @NonNull public default android.view.textclassifier.TextClassifier getTextClassifier();
- method public String getTitle();
- method public String getTouchIconUrl();
- method public String getUrl();
- method public android.webkit.WebViewProvider.ViewDelegate getViewDelegate();
- method public int getVisibleTitleHeight();
- method public android.webkit.WebChromeClient getWebChromeClient();
- method public android.webkit.WebViewClient getWebViewClient();
- method @Nullable public android.webkit.WebViewRenderProcess getWebViewRenderProcess();
- method @Nullable public android.webkit.WebViewRenderProcessClient getWebViewRenderProcessClient();
- method public android.view.View getZoomControls();
- method public void goBack();
- method public void goBackOrForward(int);
- method public void goForward();
- method public void init(java.util.Map<java.lang.String,java.lang.Object>, boolean);
- method public void insertVisualStateCallback(long, android.webkit.WebView.VisualStateCallback);
- method public void invokeZoomPicker();
- method public boolean isPaused();
- method public boolean isPrivateBrowsingEnabled();
- method public void loadData(String, String, String);
- method public void loadDataWithBaseURL(String, String, String, String, String);
- method public void loadUrl(String, java.util.Map<java.lang.String,java.lang.String>);
- method public void loadUrl(String);
- method public void notifyFindDialogDismissed();
- method public void onPause();
- method public void onResume();
- method public boolean overlayHorizontalScrollbar();
- method public boolean overlayVerticalScrollbar();
- method public boolean pageDown(boolean);
- method public boolean pageUp(boolean);
- method public void pauseTimers();
- method public void postMessageToMainFrame(android.webkit.WebMessage, android.net.Uri);
- method public void postUrl(String, byte[]);
- method public void reload();
- method public void removeJavascriptInterface(String);
- method public void requestFocusNodeHref(android.os.Message);
- method public void requestImageRef(android.os.Message);
- method public boolean restorePicture(android.os.Bundle, java.io.File);
- method public android.webkit.WebBackForwardList restoreState(android.os.Bundle);
- method public void resumeTimers();
- method public void savePassword(String, String, String);
- method public boolean savePicture(android.os.Bundle, java.io.File);
- method public android.webkit.WebBackForwardList saveState(android.os.Bundle);
- method public void saveWebArchive(String);
- method public void saveWebArchive(String, boolean, android.webkit.ValueCallback<java.lang.String>);
- method public void setCertificate(android.net.http.SslCertificate);
- method public void setDownloadListener(android.webkit.DownloadListener);
- method public void setFindListener(android.webkit.WebView.FindListener);
- method public void setHorizontalScrollbarOverlay(boolean);
- method public void setHttpAuthUsernamePassword(String, String, String, String);
- method public void setInitialScale(int);
- method public void setMapTrackballToArrowKeys(boolean);
- method public void setNetworkAvailable(boolean);
- method public void setPictureListener(android.webkit.WebView.PictureListener);
- method public void setRendererPriorityPolicy(int, boolean);
- method public default void setTextClassifier(@Nullable android.view.textclassifier.TextClassifier);
- method public void setVerticalScrollbarOverlay(boolean);
- method public void setWebChromeClient(android.webkit.WebChromeClient);
- method public void setWebViewClient(android.webkit.WebViewClient);
- method public void setWebViewRenderProcessClient(@Nullable java.util.concurrent.Executor, @Nullable android.webkit.WebViewRenderProcessClient);
- method public boolean showFindDialog(String, boolean);
- method public void stopLoading();
- method public boolean zoomBy(float);
- method public boolean zoomIn();
- method public boolean zoomOut();
- }
-
- public static interface WebViewProvider.ScrollDelegate {
- method public int computeHorizontalScrollOffset();
- method public int computeHorizontalScrollRange();
- method public void computeScroll();
- method public int computeVerticalScrollExtent();
- method public int computeVerticalScrollOffset();
- method public int computeVerticalScrollRange();
- }
-
- public static interface WebViewProvider.ViewDelegate {
- method public default void autofill(android.util.SparseArray<android.view.autofill.AutofillValue>);
- method public boolean dispatchKeyEvent(android.view.KeyEvent);
- method public android.view.View findFocus(android.view.View);
- method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
- method public android.os.Handler getHandler(android.os.Handler);
- method public default boolean isVisibleToUserForAutofill(int);
- method public void onActivityResult(int, int, android.content.Intent);
- method @Nullable public default android.view.WindowInsets onApplyWindowInsets(@Nullable android.view.WindowInsets);
- method public void onAttachedToWindow();
- method public default boolean onCheckIsTextEditor();
- method public void onConfigurationChanged(android.content.res.Configuration);
- method public android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.EditorInfo);
- method public void onDetachedFromWindow();
- method public boolean onDragEvent(android.view.DragEvent);
- method public void onDraw(android.graphics.Canvas);
- method public void onDrawVerticalScrollBar(android.graphics.Canvas, android.graphics.drawable.Drawable, int, int, int, int);
- method public void onFinishTemporaryDetach();
- method public void onFocusChanged(boolean, int, android.graphics.Rect);
- method public boolean onGenericMotionEvent(android.view.MotionEvent);
- method public boolean onHoverEvent(android.view.MotionEvent);
- method public void onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
- method public void onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo);
- method public boolean onKeyDown(int, android.view.KeyEvent);
- method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
- method public boolean onKeyUp(int, android.view.KeyEvent);
- method public void onMeasure(int, int);
- method public default void onMovedToDisplay(int, android.content.res.Configuration);
- method public void onOverScrolled(int, int, boolean, boolean);
- method public default void onProvideAutofillVirtualStructure(android.view.ViewStructure, int);
- method public default void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int);
- method public void onProvideVirtualStructure(android.view.ViewStructure);
- method public void onScrollChanged(int, int, int, int);
- method public void onSizeChanged(int, int, int, int);
- method public void onStartTemporaryDetach();
- method public boolean onTouchEvent(android.view.MotionEvent);
- method public boolean onTrackballEvent(android.view.MotionEvent);
- method public void onVisibilityChanged(android.view.View, int);
- method public void onWindowFocusChanged(boolean);
- method public void onWindowVisibilityChanged(int);
- method public boolean performAccessibilityAction(int, android.os.Bundle);
- method public boolean performLongClick();
- method public void preDispatchDraw(android.graphics.Canvas);
- method public boolean requestChildRectangleOnScreen(android.view.View, android.graphics.Rect, boolean);
- method public boolean requestFocus(int, android.graphics.Rect);
- method public void setBackgroundColor(int);
- method public boolean setFrame(int, int, int, int);
- method public void setLayerType(int, android.graphics.Paint);
- method public void setLayoutParams(android.view.ViewGroup.LayoutParams);
- method public void setOverScrollMode(int);
- method public void setScrollBarStyle(int);
- method public boolean shouldDelayChildPressedState();
- }
-
- public final class WebViewProviderInfo implements android.os.Parcelable {
- ctor public WebViewProviderInfo(String, String, boolean, boolean, String[]);
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.webkit.WebViewProviderInfo> CREATOR;
- field public final boolean availableByDefault;
- field public final String description;
- field public final boolean isFallback;
- field public final String packageName;
- field public final android.content.pm.Signature[] signatures;
- }
-
- public final class WebViewUpdateService {
- method public static android.webkit.WebViewProviderInfo[] getAllWebViewPackages();
- method public static String getCurrentWebViewPackageName();
- method public static android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
- }
-
-}
-
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
deleted file mode 100644
index 773ecd034a8e..000000000000
--- a/api/system-lint-baseline.txt
+++ /dev/null
@@ -1,537 +0,0 @@
-// Baseline format: 1.0
-AcronymName: android.net.NetworkCapabilities#setSSID(String):
-
-
-
-ActionValue: android.location.Location#EXTRA_NO_GPS_LOCATION:
-
-ActionValue: android.net.TetheringManager#ACTION_TETHER_STATE_CHANGED:
-
-ActionValue: android.net.TetheringManager#EXTRA_ACTIVE_TETHER:
-
-ActionValue: android.net.TetheringManager#EXTRA_AVAILABLE_TETHER:
-
-ActionValue: android.net.TetheringManager#EXTRA_ERRORED_TETHER:
-
-ActionValue: android.net.wifi.WifiManager#ACTION_LINK_CONFIGURATION_CHANGED:
-
-
-
-ArrayReturn: android.bluetooth.BluetoothCodecStatus#BluetoothCodecStatus(android.bluetooth.BluetoothCodecConfig, android.bluetooth.BluetoothCodecConfig[], android.bluetooth.BluetoothCodecConfig[]) parameter #1:
-
-ArrayReturn: android.bluetooth.BluetoothCodecStatus#BluetoothCodecStatus(android.bluetooth.BluetoothCodecConfig, android.bluetooth.BluetoothCodecConfig[], android.bluetooth.BluetoothCodecConfig[]) parameter #2:
-
-ArrayReturn: android.bluetooth.BluetoothCodecStatus#getCodecsLocalCapabilities():
-
-ArrayReturn: android.bluetooth.BluetoothCodecStatus#getCodecsSelectableCapabilities():
-
-ArrayReturn: android.bluetooth.BluetoothUuid#containsAnyUuid(android.os.ParcelUuid[], android.os.ParcelUuid[]) parameter #0:
-
-ArrayReturn: android.bluetooth.BluetoothUuid#containsAnyUuid(android.os.ParcelUuid[], android.os.ParcelUuid[]) parameter #1:
-
-ArrayReturn: android.media.tv.tuner.Tuner.FilterCallback#onFilterEvent(android.media.tv.tuner.Tuner.Filter, android.media.tv.tuner.filter.FilterEvent[]) parameter #1:
-
-ArrayReturn: android.net.NetworkScoreManager#requestScores(android.net.NetworkKey[]) parameter #0:
-
-ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
-
-
-
-BuilderSetStyle: android.net.IpSecTransform.Builder#buildTunnelModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex):
- Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.net.IpSecTransform.Builder.buildTunnelModeTransform(java.net.InetAddress,android.net.IpSecManager.SecurityParameterIndex)
-
-
-ExecutorRegistration: android.media.MediaPlayer#setOnImsRxNoticeListener(android.media.MediaPlayer.OnImsRxNoticeListener, android.os.Handler):
- Registration methods should have overload that accepts delivery Executor: `setOnImsRxNoticeListener`
-ExecutorRegistration: android.net.wifi.p2p.WifiP2pManager#deletePersistentGroup(android.net.wifi.p2p.WifiP2pManager.Channel, int, android.net.wifi.p2p.WifiP2pManager.ActionListener):
-
-ExecutorRegistration: android.net.wifi.p2p.WifiP2pManager#factoryReset(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener):
-
-ExecutorRegistration: android.net.wifi.p2p.WifiP2pManager#listen(android.net.wifi.p2p.WifiP2pManager.Channel, boolean, android.net.wifi.p2p.WifiP2pManager.ActionListener):
-
-ExecutorRegistration: android.net.wifi.p2p.WifiP2pManager#requestPersistentGroupInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.PersistentGroupInfoListener):
-
-ExecutorRegistration: android.net.wifi.p2p.WifiP2pManager#setDeviceName(android.net.wifi.p2p.WifiP2pManager.Channel, String, android.net.wifi.p2p.WifiP2pManager.ActionListener):
-
-ExecutorRegistration: android.net.wifi.p2p.WifiP2pManager#setWfdInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pWfdInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener):
-
-ExecutorRegistration: android.net.wifi.p2p.WifiP2pManager#setWifiP2pChannels(android.net.wifi.p2p.WifiP2pManager.Channel, int, int, android.net.wifi.p2p.WifiP2pManager.ActionListener):
-
-
-
-GenericException: android.app.prediction.AppPredictor#finalize():
-
-GenericException: android.hardware.location.ContextHubClient#finalize():
-
-GenericException: android.net.IpSecManager.IpSecTunnelInterface#finalize():
-
-GenericException: android.service.autofill.augmented.FillWindow#finalize():
-
-
-
-IntentBuilderName: android.content.Context#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler):
-
-
-
-KotlinKeyword: android.app.Notification#when:
-
-
-
-KotlinOperator: android.telephony.CbGeoUtils.Geometry#contains(android.telephony.CbGeoUtils.LatLng):
-
-
-
-MissingGetterMatchingBuilder: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
- android.net.wifi.rtt.RangingRequest does not declare a `getResponders()` method matching method android.net.wifi.rtt.RangingRequest.Builder.addResponder(android.net.wifi.rtt.ResponderConfig)
-MissingGetterMatchingBuilder: android.security.keystore.KeyGenParameterSpec.Builder#setUid(int):
- android.security.keystore.KeyGenParameterSpec does not declare a `getUid()` method matching method android.security.keystore.KeyGenParameterSpec.Builder.setUid(int)
-MissingGetterMatchingBuilder: android.service.autofill.Dataset.Builder#setFieldInlinePresentation(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.service.autofill.InlinePresentation):
- android.service.autofill.Dataset does not declare a `getFieldInlinePresentation()` method matching method android.service.autofill.Dataset.Builder.setFieldInlinePresentation(android.view.autofill.AutofillId,android.view.autofill.AutofillValue,java.util.regex.Pattern,android.service.autofill.InlinePresentation)
-MissingGetterMatchingBuilder: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallViaAudioProcessing(boolean):
- android.telecom.CallScreeningService.CallResponse does not declare a `shouldScreenCallViaAudioProcessing()` method matching method android.telecom.CallScreeningService.CallResponse.Builder.setShouldScreenCallViaAudioProcessing(boolean)
-MissingGetterMatchingBuilder: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
- android.telephony.mbms.DownloadRequest does not declare a `getServiceId()` method matching method android.telephony.mbms.DownloadRequest.Builder.setServiceId(String)
-
-
-MissingNullability: android.hardware.soundtrigger.SoundTrigger.ModuleProperties#toString():
-
-MissingNullability: android.hardware.soundtrigger.SoundTrigger.ModuleProperties#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.media.session.MediaSessionManager.Callback#onAddressedPlayerChanged(android.content.ComponentName) parameter #0:
-
-MissingNullability: android.media.session.MediaSessionManager.Callback#onAddressedPlayerChanged(android.media.session.MediaSession.Token) parameter #0:
-
-MissingNullability: android.media.session.MediaSessionManager.Callback#onMediaKeyEventDispatched(android.view.KeyEvent, android.content.ComponentName) parameter #0:
-
-MissingNullability: android.media.session.MediaSessionManager.Callback#onMediaKeyEventDispatched(android.view.KeyEvent, android.content.ComponentName) parameter #1:
-
-MissingNullability: android.media.session.MediaSessionManager.Callback#onMediaKeyEventDispatched(android.view.KeyEvent, android.media.session.MediaSession.Token) parameter #0:
-
-MissingNullability: android.media.session.MediaSessionManager.Callback#onMediaKeyEventDispatched(android.view.KeyEvent, android.media.session.MediaSession.Token) parameter #1:
-
-MissingNullability: android.media.soundtrigger.SoundTriggerDetectionService#onUnbind(android.content.Intent) parameter #0:
-
-MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #0:
-
-MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #1:
-
-MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #2:
-
-MissingNullability: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
-
-MissingNullability: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context) parameter #0:
-
-MissingNullability: android.provider.ContactsContract.MetadataSync#CONTENT_URI:
-
-MissingNullability: android.provider.ContactsContract.MetadataSync#METADATA_AUTHORITY_URI:
-
-MissingNullability: android.provider.ContactsContract.MetadataSyncState#CONTENT_URI:
-
-MissingNullability: android.provider.SearchIndexablesProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #0:
-
-MissingNullability: android.provider.SearchIndexablesProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #1:
-
-MissingNullability: android.service.autofill.augmented.AugmentedAutofillService#onUnbind(android.content.Intent) parameter #0:
-
-MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
-
-MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #1:
-
-MissingNullability: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #2:
-
-MissingNullability: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context) parameter #0:
-
-MissingNullability: android.telecom.CallScreeningService.CallResponse.Builder#setShouldScreenCallFurther(boolean):
-
-MissingNullability: android.telephony.CallerInfo#toString():
-
-MissingNullability: android.telephony.CellBroadcastService#onBind(android.content.Intent):
-
-MissingNullability: android.telephony.CellBroadcastService#onBind(android.content.Intent) parameter #0:
-
-MissingNullability: android.telephony.CellBroadcastService#onCdmaCellBroadcastSms(int, byte[]) parameter #1:
-
-MissingNullability: android.telephony.CellBroadcastService#onCdmaCellBroadcastSms(int, byte[], int) parameter #1:
-
-MissingNullability: android.telephony.CellBroadcastService#onGsmCellBroadcastSms(int, byte[]) parameter #1:
-
-MissingNullability: android.telephony.ModemActivityInfo#toString():
-
-MissingNullability: android.telephony.ModemActivityInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.NetworkService#onUnbind(android.content.Intent) parameter #0:
-
-MissingNullability: android.telephony.SmsCbCmasInfo#toString():
-
-MissingNullability: android.telephony.SmsCbCmasInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.SmsCbEtwsInfo#toString():
-
-MissingNullability: android.telephony.SmsCbEtwsInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.SmsCbLocation#equals(Object) parameter #0:
-
-MissingNullability: android.telephony.SmsCbLocation#toString():
-
-MissingNullability: android.telephony.SmsCbLocation#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.SmsCbMessage#toString():
-
-MissingNullability: android.telephony.SmsCbMessage#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.SubscriptionPlan.Builder#createRecurringDaily(java.time.ZonedDateTime) parameter #0:
-
-MissingNullability: android.telephony.SubscriptionPlan.Builder#createRecurringMonthly(java.time.ZonedDateTime) parameter #0:
-
-MissingNullability: android.telephony.SubscriptionPlan.Builder#createRecurringWeekly(java.time.ZonedDateTime) parameter #0:
-
-MissingNullability: android.telephony.cdma.CdmaSmsCbProgramData#toString():
-
-MissingNullability: android.telephony.cdma.CdmaSmsCbProgramData#writeToParcel(android.os.Parcel, int) parameter #0:
-
-MissingNullability: android.telephony.data.DataService#onUnbind(android.content.Intent) parameter #0:
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, String, byte[]) parameter #1:
-
-MissingNullability: android.telephony.ims.stub.ImsSmsImplBase#onSmsStatusReportReceived(int, String, byte[]) parameter #2:
-
-MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String):
-
-MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId(String) parameter #0:
-
-
-
-MutableBareField: android.net.IpConfiguration#httpProxy:
-
-MutableBareField: android.net.IpConfiguration#ipAssignment:
-
-MutableBareField: android.net.IpConfiguration#proxySettings:
-
-MutableBareField: android.net.IpConfiguration#staticIpConfiguration:
-
-MutableBareField: android.net.wifi.WifiConfiguration#allowAutojoin:
-
-MutableBareField: android.net.wifi.WifiConfiguration#carrierId:
-
-MutableBareField: android.net.wifi.WifiConfiguration#fromWifiNetworkSpecifier:
-
-MutableBareField: android.net.wifi.WifiConfiguration#fromWifiNetworkSuggestion:
-
-MutableBareField: android.net.wifi.WifiConfiguration#macRandomizationSetting:
-
-MutableBareField: android.net.wifi.WifiConfiguration#meteredOverride:
-
-MutableBareField: android.net.wifi.WifiConfiguration#requirePmf:
-
-MutableBareField: android.net.wifi.WifiConfiguration#saePasswordId:
-
-MutableBareField: android.net.wifi.WifiConfiguration#shared:
-
-MutableBareField: android.net.wifi.WifiConfiguration#subscriptionId:
- Bare field subscriptionId must be marked final, or moved behind accessors if mutable
-MutableBareField: android.net.wifi.WifiScanner.ScanSettings#type:
-
-
-
-NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
-
-
-
-NoSettingsProvider: android.provider.Settings.Global#TETHER_OFFLOAD_DISABLED:
-
-NoSettingsProvider: android.provider.Settings.Global#TETHER_SUPPORTED:
-
-
-
-NotCloseable: android.bluetooth.BluetoothA2dpSink:
-
-NotCloseable: android.bluetooth.BluetoothMap:
-
-NotCloseable: android.bluetooth.BluetoothPan:
-
-NotCloseable: android.bluetooth.BluetoothPbap:
-
-
-
-OnNameExpected: android.content.ContentProvider#checkUriPermission(android.net.Uri, int, int):
-
-
-
-PairedRegistration: android.net.wifi.nl80211.WifiNl80211Manager#registerApCallback(String, java.util.concurrent.Executor, android.net.wifi.nl80211.WifiNl80211Manager.SoftApCallback):
-
-
-
-ProtectedMember: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context):
-
-ProtectedMember: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]):
-
-ProtectedMember: android.service.notification.NotificationAssistantService#attachBaseContext(android.content.Context):
-
-
-
-SamShouldBeLast: android.accounts.AccountManager#addAccount(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean):
-
-SamShouldBeLast: android.accounts.AccountManager#addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean, String[]):
-
-SamShouldBeLast: android.accounts.AccountManager#confirmCredentials(android.accounts.Account, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#editProperties(String, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#finishSession(android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#getAuthToken(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#getAuthToken(android.accounts.Account, String, android.os.Bundle, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#getAuthToken(android.accounts.Account, String, boolean, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#getAuthTokenByFeatures(String, String, String[], android.app.Activity, android.os.Bundle, android.os.Bundle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#hasFeatures(android.accounts.Account, String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#isCredentialsUpdateSuggested(android.accounts.Account, String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#renameAccount(android.accounts.Account, String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#startAddAccountSession(String, String, String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#startUpdateCredentialsSession(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.accounts.AccountManager#updateCredentials(android.accounts.Account, String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler):
-
-SamShouldBeLast: android.app.AlarmManager#set(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler):
-
-SamShouldBeLast: android.app.AlarmManager#setExact(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler):
-
-SamShouldBeLast: android.app.AlarmManager#setWindow(int, long, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler):
-
-SamShouldBeLast: android.app.WallpaperInfo#dump(android.util.Printer, String):
-
-SamShouldBeLast: android.app.WallpaperManager#addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler):
-
-SamShouldBeLast: android.app.admin.DevicePolicyManager#installSystemUpdate(android.content.ComponentName, android.net.Uri, java.util.concurrent.Executor, android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback):
-
-SamShouldBeLast: android.content.Context#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection):
-
-SamShouldBeLast: android.content.Context#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection):
-
-SamShouldBeLast: android.content.ContextWrapper#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection):
-
-SamShouldBeLast: android.content.ContextWrapper#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection):
-
-SamShouldBeLast: android.content.IntentFilter#dump(android.util.Printer, String):
-
-SamShouldBeLast: android.content.pm.ApplicationInfo#dump(android.util.Printer, String):
-
-SamShouldBeLast: android.content.pm.LauncherApps#registerPackageInstallerSessionCallback(java.util.concurrent.Executor, android.content.pm.PackageInstaller.SessionCallback):
-
-SamShouldBeLast: android.content.pm.PackageItemInfo#dumpBack(android.util.Printer, String):
-
-SamShouldBeLast: android.content.pm.PackageItemInfo#dumpFront(android.util.Printer, String):
-
-SamShouldBeLast: android.content.pm.ResolveInfo#dump(android.util.Printer, String):
-
-SamShouldBeLast: android.location.Location#dump(android.util.Printer, String):
-
-SamShouldBeLast: android.location.LocationManager#addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler):
-
-SamShouldBeLast: android.location.LocationManager#registerGnssMeasurementsCallback(java.util.concurrent.Executor, android.location.GnssMeasurementsEvent.Callback):
-
-SamShouldBeLast: android.location.LocationManager#registerGnssNavigationMessageCallback(java.util.concurrent.Executor, android.location.GnssNavigationMessage.Callback):
-
-SamShouldBeLast: android.location.LocationManager#registerGnssStatusCallback(java.util.concurrent.Executor, android.location.GnssStatus.Callback):
-
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, android.location.LocationListener, android.os.Looper):
-
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, java.util.concurrent.Executor, android.location.LocationListener):
-
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(android.location.LocationRequest, java.util.concurrent.Executor, android.location.LocationListener):
-
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper):
-
-SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, java.util.concurrent.Executor, android.location.LocationListener):
-
-SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(String, android.location.LocationListener, android.os.Looper):
-
-SamShouldBeLast: android.location.LocationManager#requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper):
-
-SamShouldBeLast: android.media.AudioFocusRequest.Builder#setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler):
-
-SamShouldBeLast: android.media.AudioManager#requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int):
-
-SamShouldBeLast: android.media.AudioRecord#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-
-SamShouldBeLast: android.media.AudioRecord#registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback):
-
-SamShouldBeLast: android.media.AudioRecordingMonitor#registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback):
-
-SamShouldBeLast: android.media.AudioRouting#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-
-SamShouldBeLast: android.media.AudioTrack#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
- SAM-compatible parameters (such as parameter 1, "listener", in android.media.AudioTrack.addOnRoutingChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.media.MediaPlayer#setOnImsRxNoticeListener(android.media.MediaPlayer.OnImsRxNoticeListener, android.os.Handler):
- SAM-compatible parameters (such as parameter 1, "listener", in android.media.MediaPlayer.setOnImsRxNoticeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.media.MediaRecorder#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-
-SamShouldBeLast: android.media.MediaRecorder#registerAudioRecordingCallback(java.util.concurrent.Executor, android.media.AudioManager.AudioRecordingCallback):
-
-SamShouldBeLast: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName):
-
-SamShouldBeLast: android.media.session.MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler):
-
-SamShouldBeLast: android.media.session.MediaSessionManager#addOnSession2TokensChangedListener(android.media.session.MediaSessionManager.OnSession2TokensChangedListener, android.os.Handler):
-
-SamShouldBeLast: android.media.session.MediaSessionManager#registerCallback(java.util.concurrent.Executor, android.media.session.MediaSessionManager.Callback):
-
-SamShouldBeLast: android.net.ConnectivityManager#createSocketKeepalive(android.net.Network, android.net.IpSecManager.UdpEncapsulationSocket, java.net.InetAddress, java.net.InetAddress, java.util.concurrent.Executor, android.net.SocketKeepalive.Callback):
-
-SamShouldBeLast: android.net.wifi.WifiManager#startLocalOnlyHotspot(android.net.wifi.SoftApConfiguration, java.util.concurrent.Executor, android.net.wifi.WifiManager.LocalOnlyHotspotCallback):
-
-SamShouldBeLast: android.net.wifi.rtt.WifiRttManager#startRanging(android.net.wifi.rtt.RangingRequest, java.util.concurrent.Executor, android.net.wifi.rtt.RangingResultCallback):
-
-SamShouldBeLast: android.nfc.NfcAdapter#enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle):
-
-SamShouldBeLast: android.nfc.NfcAdapter#ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler):
-
-SamShouldBeLast: android.nfc.NfcAdapter#setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity):
-
-SamShouldBeLast: android.nfc.NfcAdapter#setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...):
-
-SamShouldBeLast: android.nfc.NfcAdapter#setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...):
-
-SamShouldBeLast: android.os.Binder#attachInterface(android.os.IInterface, String):
-
-SamShouldBeLast: android.os.Binder#linkToDeath(android.os.IBinder.DeathRecipient, int):
-
-SamShouldBeLast: android.os.Binder#unlinkToDeath(android.os.IBinder.DeathRecipient, int):
-
-SamShouldBeLast: android.os.Handler#dump(android.util.Printer, String):
-
-SamShouldBeLast: android.os.Handler#postAtTime(Runnable, Object, long):
-
-SamShouldBeLast: android.os.Handler#postAtTime(Runnable, long):
-
-SamShouldBeLast: android.os.Handler#postDelayed(Runnable, Object, long):
-
-SamShouldBeLast: android.os.Handler#postDelayed(Runnable, long):
-
-SamShouldBeLast: android.os.Handler#removeCallbacks(Runnable, Object):
-
-SamShouldBeLast: android.os.IBinder#linkToDeath(android.os.IBinder.DeathRecipient, int):
-
-SamShouldBeLast: android.os.IBinder#unlinkToDeath(android.os.IBinder.DeathRecipient, int):
-
-SamShouldBeLast: android.os.RecoverySystem#verifyPackage(java.io.File, android.os.RecoverySystem.ProgressListener, java.io.File):
-
-SamShouldBeLast: android.telephony.MbmsDownloadSession#addProgressListener(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadProgressListener):
-
-SamShouldBeLast: android.telephony.MbmsDownloadSession#addStatusListener(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadStatusListener):
-
-SamShouldBeLast: android.telephony.MbmsDownloadSession#create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsDownloadSessionCallback):
-
-SamShouldBeLast: android.telephony.MbmsDownloadSession#create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsDownloadSessionCallback):
-
-SamShouldBeLast: android.telephony.MbmsGroupCallSession#create(android.content.Context, int, java.util.concurrent.Executor, android.telephony.mbms.MbmsGroupCallSessionCallback):
-
-SamShouldBeLast: android.telephony.MbmsGroupCallSession#create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsGroupCallSessionCallback):
-
-SamShouldBeLast: android.telephony.MbmsGroupCallSession#startGroupCall(long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, java.util.concurrent.Executor, android.telephony.mbms.GroupCallCallback):
-
-SamShouldBeLast: android.telephony.MbmsStreamingSession#create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsStreamingSessionCallback):
-
-SamShouldBeLast: android.telephony.MbmsStreamingSession#create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsStreamingSessionCallback):
-
-SamShouldBeLast: android.telephony.MbmsStreamingSession#startStreaming(android.telephony.mbms.StreamingServiceInfo, java.util.concurrent.Executor, android.telephony.mbms.StreamingServiceCallback):
-
-SamShouldBeLast: android.telephony.SmsManager#getSmsMessagesForFinancialApp(android.os.Bundle, java.util.concurrent.Executor, android.telephony.SmsManager.FinancialSmsCallback):
-
-SamShouldBeLast: android.telephony.SubscriptionManager#addOnOpportunisticSubscriptionsChangedListener(java.util.concurrent.Executor, android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener):
-
-SamShouldBeLast: android.telephony.TelephonyManager#requestCellInfoUpdate(java.util.concurrent.Executor, android.telephony.TelephonyManager.CellInfoCallback):
-
-SamShouldBeLast: android.telephony.TelephonyManager#requestNetworkScan(android.telephony.NetworkScanRequest, java.util.concurrent.Executor, android.telephony.TelephonyScanManager.NetworkScanCallback):
-
-SamShouldBeLast: android.telephony.TelephonyManager#setPreferredOpportunisticDataSubscription(int, boolean, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>):
-
-SamShouldBeLast: android.telephony.TelephonyManager#updateAvailableNetworks(java.util.List<android.telephony.AvailableNetworkInfo>, java.util.concurrent.Executor, java.util.function.Consumer<java.lang.Integer>):
-
-SamShouldBeLast: android.view.View#postDelayed(Runnable, long):
-
-SamShouldBeLast: android.view.View#postOnAnimationDelayed(Runnable, long):
-
-SamShouldBeLast: android.view.View#scheduleDrawable(android.graphics.drawable.Drawable, Runnable, long):
-
-SamShouldBeLast: android.view.Window#addOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler):
-
-SamShouldBeLast: android.view.accessibility.AccessibilityManager#addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, android.os.Handler):
-
-SamShouldBeLast: android.view.accessibility.AccessibilityManager#addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler):
-
-SamShouldBeLast: android.webkit.WebChromeClient#onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams):
-
-SamShouldBeLast: android.webkit.WebView#setWebViewRenderProcessClient(java.util.concurrent.Executor, android.webkit.WebViewRenderProcessClient):
-
-
-
-ServiceName: android.Manifest.permission#BIND_ATTENTION_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_AUGMENTED_AUTOFILL_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_CELL_BROADCAST_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_CONTENT_CAPTURE_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_CONTENT_SUGGESTIONS_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_EUICC_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_EXTERNAL_STORAGE_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_IMS_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_NETWORK_RECOMMENDATION_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_NOTIFICATION_ASSISTANT_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_PRINT_RECOMMENDATION_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_RESOLVER_RANKER_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_SETTINGS_SUGGESTIONS_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_SOUND_TRIGGER_DETECTION_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_TELEPHONY_DATA_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_TELEPHONY_NETWORK_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_TEXTCLASSIFIER_SERVICE:
-
-ServiceName: android.Manifest.permission#BIND_TV_REMOTE_SERVICE:
-
-ServiceName: android.Manifest.permission#PROVIDE_RESOLVER_RANKER_SERVICE:
-
-ServiceName: android.Manifest.permission#REQUEST_NOTIFICATION_ASSISTANT_SERVICE:
-
-ServiceName: android.provider.DeviceConfig#NAMESPACE_PACKAGE_MANAGER_SERVICE:
-
-
-
-UserHandle: android.companion.CompanionDeviceManager#isDeviceAssociated(String, android.net.MacAddress, android.os.UserHandle):
-
-
-
-UserHandleName: android.telephony.CellBroadcastIntents#sendOrderedBroadcastForBackgroundReceivers(android.content.Context, android.os.UserHandle, android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle):
-
diff --git a/api/system-removed.txt b/api/system-removed.txt
deleted file mode 100644
index 3acc22528438..000000000000
--- a/api/system-removed.txt
+++ /dev/null
@@ -1,198 +0,0 @@
-// Signature format: 2.0
-package android {
-
- public static final class Manifest.permission {
- field public static final String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
- }
-
-}
-
-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 {
- method public static Class<? extends android.app.Notification.Style> getNotificationStyleClass(String);
- }
-
- public static final class Notification.TvExtender implements android.app.Notification.Extender {
- method @Deprecated public String getChannel();
- }
-
-}
-
-package android.app.backup {
-
- public class RestoreSession {
- method @Deprecated public int restoreSome(long, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor, String[]);
- method @Deprecated public int restoreSome(long, android.app.backup.RestoreObserver, String[]);
- }
-
-}
-
-package android.app.prediction {
-
- public static final class AppTarget.Builder {
- ctor @Deprecated public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId);
- method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle);
- method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo);
- }
-
-}
-
-package android.content {
-
- public class Intent implements java.lang.Cloneable android.os.Parcelable {
- field @Deprecated public static final String ACTION_DEVICE_INITIALIZATION_WIZARD = "android.intent.action.DEVICE_INITIALIZATION_WIZARD";
- field @Deprecated public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
- field @Deprecated public static final String ACTION_SERVICE_STATE = "android.intent.action.SERVICE_STATE";
- field @Deprecated public static final String EXTRA_CDMA_DEFAULT_ROAMING_INDICATOR = "cdmaDefaultRoamingIndicator";
- field @Deprecated public static final String EXTRA_CDMA_ROAMING_INDICATOR = "cdmaRoamingIndicator";
- field @Deprecated public static final String EXTRA_CSS_INDICATOR = "cssIndicator";
- field @Deprecated public static final String EXTRA_DATA_OPERATOR_ALPHA_LONG = "data-operator-alpha-long";
- field @Deprecated public static final String EXTRA_DATA_OPERATOR_ALPHA_SHORT = "data-operator-alpha-short";
- field @Deprecated public static final String EXTRA_DATA_OPERATOR_NUMERIC = "data-operator-numeric";
- field @Deprecated public static final String EXTRA_DATA_RADIO_TECH = "dataRadioTechnology";
- field @Deprecated public static final String EXTRA_DATA_REG_STATE = "dataRegState";
- field @Deprecated public static final String EXTRA_DATA_ROAMING_TYPE = "dataRoamingType";
- field @Deprecated public static final String EXTRA_EMERGENCY_ONLY = "emergencyOnly";
- field @Deprecated public static final String EXTRA_IS_DATA_ROAMING_FROM_REGISTRATION = "isDataRoamingFromRegistration";
- field @Deprecated public static final String EXTRA_IS_USING_CARRIER_AGGREGATION = "isUsingCarrierAggregation";
- field @Deprecated public static final String EXTRA_LTE_EARFCN_RSRP_BOOST = "LteEarfcnRsrpBoost";
- field @Deprecated public static final String EXTRA_MANUAL = "manual";
- field @Deprecated public static final String EXTRA_NETWORK_ID = "networkId";
- field @Deprecated public static final String EXTRA_OPERATOR_ALPHA_LONG = "operator-alpha-long";
- field @Deprecated public static final String EXTRA_OPERATOR_ALPHA_SHORT = "operator-alpha-short";
- field @Deprecated public static final String EXTRA_OPERATOR_NUMERIC = "operator-numeric";
- field @Deprecated public static final String EXTRA_SYSTEM_ID = "systemId";
- field @Deprecated public static final String EXTRA_VOICE_RADIO_TECH = "radioTechnology";
- field @Deprecated public static final String EXTRA_VOICE_REG_STATE = "voiceRegState";
- field @Deprecated public static final String EXTRA_VOICE_ROAMING_TYPE = "voiceRoamingType";
- }
-
-}
-
-package android.content.pm {
-
- public class PackageItemInfo {
- field @Deprecated public static final int SAFE_LABEL_FLAG_FIRST_LINE = 4; // 0x4
- field @Deprecated public static final int SAFE_LABEL_FLAG_SINGLE_LINE = 2; // 0x2
- field @Deprecated public static final int SAFE_LABEL_FLAG_TRIM = 1; // 0x1
- }
-
-}
-
-package android.hardware.hdmi {
-
- public final class HdmiControlManager {
- method @Deprecated public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevicesList();
- method @Deprecated public boolean isRemoteDeviceConnected(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
- method @Deprecated public void powerOffRemoteDevice(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
- method @Deprecated public void powerOnRemoteDevice(android.hardware.hdmi.HdmiDeviceInfo);
- method @Deprecated public void requestRemoteDeviceToBecomeActiveSource(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
- }
-
-}
-
-package android.location {
-
- public class LocationManager {
- method @Deprecated public boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
- method @Deprecated public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
- method @Deprecated public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
- method @Deprecated public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackage(String);
- method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackageEnabled(boolean);
- }
-
-}
-
-package android.media.tv {
-
- public final class TvInputManager {
- method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
- }
-
- public static final class TvInputManager.Hardware {
- method public boolean dispatchKeyEventToHdmi(android.view.KeyEvent);
- }
-
-}
-
-package android.net.wifi {
-
- @Deprecated public class BatchedScanResult implements android.os.Parcelable {
- ctor public BatchedScanResult();
- ctor public BatchedScanResult(android.net.wifi.BatchedScanResult);
- field public final java.util.List<android.net.wifi.ScanResult> scanResults;
- field public boolean truncated;
- }
-
- public final class ScanResult implements android.os.Parcelable {
- field public boolean untrusted;
- }
-
-}
-
-package android.os {
-
- public class Build {
- field public static final boolean PERMISSIONS_REVIEW_REQUIRED = true;
- }
-
-}
-
-package android.service.notification {
-
- public abstract class NotificationListenerService extends android.app.Service {
- method public android.service.notification.StatusBarNotification[] getActiveNotifications(int);
- method public android.service.notification.StatusBarNotification[] getActiveNotifications(String[], int);
- method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException;
- method public final void setOnNotificationPostedTrim(int);
- method public final void snoozeNotification(String, String);
- method public void unregisterAsSystemService() throws android.os.RemoteException;
- field public static final int TRIM_FULL = 0; // 0x0
- field public static final int TRIM_LIGHT = 1; // 0x1
- }
-
- public static class NotificationListenerService.Ranking {
- method public java.util.List<java.lang.String> getAdditionalPeople();
- method public java.util.List<android.service.notification.SnoozeCriterion> getSnoozeCriteria();
- }
-
-}
-
-package android.telecom {
-
- public class TelecomManager {
- method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.WRITE_SECURE_SETTINGS}) public boolean setDefaultDialer(@Nullable String);
- }
-
-}
-
-package android.telephony {
-
- public class TelephonyManager {
- method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void answerRingingCall();
- method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public boolean endCall();
- method @Deprecated public void silenceRinger();
- }
-
-}
-
-package android.telephony.data {
-
- public final class DataCallResponse implements android.os.Parcelable {
- ctor public DataCallResponse(int, int, int, int, int, @Nullable String, @Nullable java.util.List<android.net.LinkAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.net.InetAddress>, int);
- }
-
-}
-
diff --git a/cmds/abx/Android.bp b/cmds/abx/Android.bp
new file mode 100644
index 000000000000..333acedfadad
--- /dev/null
+++ b/cmds/abx/Android.bp
@@ -0,0 +1,20 @@
+
+java_binary {
+ name: "abx",
+ wrapper: "abx",
+ srcs: ["**/*.java"],
+ required: [
+ "abx2xml",
+ "xml2abx",
+ ],
+}
+
+sh_binary {
+ name: "abx2xml",
+ src: "abx2xml",
+}
+
+sh_binary {
+ name: "xml2abx",
+ src: "xml2abx",
+}
diff --git a/cmds/abx/MODULE_LICENSE_APACHE2 b/cmds/abx/MODULE_LICENSE_APACHE2
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/cmds/abx/MODULE_LICENSE_APACHE2
diff --git a/cmds/abx/NOTICE b/cmds/abx/NOTICE
new file mode 100644
index 000000000000..50e9e9bfcd3e
--- /dev/null
+++ b/cmds/abx/NOTICE
@@ -0,0 +1,189 @@
+
+ Copyright (c) 2005-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.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
diff --git a/cmds/abx/abx b/cmds/abx/abx
new file mode 100755
index 000000000000..0a9362d64398
--- /dev/null
+++ b/cmds/abx/abx
@@ -0,0 +1,3 @@
+#!/system/bin/sh
+export CLASSPATH=/system/framework/abx.jar
+exec app_process /system/bin com.android.commands.abx.Abx "$0" "$@"
diff --git a/cmds/abx/abx2xml b/cmds/abx/abx2xml
new file mode 100755
index 000000000000..0a9362d64398
--- /dev/null
+++ b/cmds/abx/abx2xml
@@ -0,0 +1,3 @@
+#!/system/bin/sh
+export CLASSPATH=/system/framework/abx.jar
+exec app_process /system/bin com.android.commands.abx.Abx "$0" "$@"
diff --git a/cmds/abx/src/com/android/commands/abx/Abx.java b/cmds/abx/src/com/android/commands/abx/Abx.java
new file mode 100644
index 000000000000..8f1a4cf74564
--- /dev/null
+++ b/cmds/abx/src/com/android/commands/abx/Abx.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 com.android.commands.abx;
+
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Utility that offers to convert between human-readable XML and a custom binary
+ * XML protocol.
+ *
+ * @see Xml#newSerializer()
+ * @see Xml#newBinarySerializer()
+ */
+public class Abx {
+ private static final String USAGE = "" +
+ "usage: abx2xml [-i] input [output]\n" +
+ "usage: xml2abx [-i] input [output]\n\n" +
+ "Converts between human-readable XML and Android Binary XML.\n\n" +
+ "When invoked with the '-i' argument, the output of a successful conversion\n" +
+ "will overwrite the original input file. Input can be '-' to use stdin, and\n" +
+ "output can be '-' to use stdout.\n";
+
+ private static InputStream openInput(String arg) throws IOException {
+ if ("-".equals(arg)) {
+ return System.in;
+ } else {
+ return new FileInputStream(arg);
+ }
+ }
+
+ private static OutputStream openOutput(String arg) throws IOException {
+ if ("-".equals(arg)) {
+ return System.out;
+ } else {
+ return new FileOutputStream(arg);
+ }
+ }
+
+ private static void mainInternal(String[] args) {
+ if (args.length < 2) {
+ throw new IllegalArgumentException("Missing arguments");
+ }
+
+ final XmlPullParser in;
+ final XmlSerializer out;
+ if (args[0].endsWith("abx2xml")) {
+ in = Xml.newBinaryPullParser();
+ out = Xml.newSerializer();
+ } else if (args[0].endsWith("xml2abx")) {
+ in = Xml.newPullParser();
+ out = Xml.newBinarySerializer();
+ } else {
+ throw new IllegalArgumentException("Unsupported conversion");
+ }
+
+ final boolean inPlace = "-i".equals(args[1]);
+ final String inputArg = inPlace ? args[2] : args[1];
+ final String outputArg = inPlace ? args[2] + ".tmp" : args[2];
+
+ try (InputStream is = openInput(inputArg);
+ OutputStream os = openOutput(outputArg)) {
+ in.setInput(is, StandardCharsets.UTF_8.name());
+ out.setOutput(os, StandardCharsets.UTF_8.name());
+ out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ Xml.copy(in, out);
+ out.flush();
+ } catch (Exception e) {
+ // Clean up failed output before throwing
+ if (inPlace) {
+ new File(outputArg).delete();
+ }
+ throw new IllegalStateException(e);
+ }
+
+ // Successful in-place conversion of a file requires a rename
+ if (inPlace) {
+ if (!new File(outputArg).renameTo(new File(inputArg))) {
+ throw new IllegalStateException("Failed rename");
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ try {
+ mainInternal(args);
+ System.exit(0);
+ } catch (Exception e) {
+ System.err.println(e.toString());
+ System.err.println();
+ System.err.println(USAGE);
+ System.exit(1);
+ }
+ }
+}
diff --git a/cmds/abx/xml2abx b/cmds/abx/xml2abx
new file mode 100755
index 000000000000..0a9362d64398
--- /dev/null
+++ b/cmds/abx/xml2abx
@@ -0,0 +1,3 @@
+#!/system/bin/sh
+export CLASSPATH=/system/framework/abx.jar
+exec app_process /system/bin com.android.commands.abx.Abx "$0" "$@"
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index bdb83804d903..ebe6199690f7 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -186,6 +186,8 @@ public class Am extends BaseCommand {
instrument.userId = parseUserArg(nextArgRequired());
} else if (opt.equals("--abi")) {
instrument.abi = nextArgRequired();
+ } else if (opt.equals("--no-restart")) {
+ instrument.noRestart = true;
} else {
System.err.println("Error: Unknown option: " + opt);
return;
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index 7c30c8b1e1dd..2be8264856f8 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -19,6 +19,7 @@ package com.android.commands.am;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
+import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART;
import android.app.IActivityManager;
import android.app.IInstrumentationWatcher;
@@ -89,6 +90,7 @@ public class Instrument {
public boolean disableTestApiChecks = true;
public boolean disableIsolatedStorage = false;
public String abi = null;
+ public boolean noRestart = false;
public int userId = UserHandle.USER_CURRENT;
public Bundle args = new Bundle();
// Required
@@ -514,6 +516,9 @@ public class Instrument {
if (disableIsolatedStorage) {
flags |= INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
}
+ if (noRestart) {
+ flags |= INSTR_FLAG_NO_RESTART;
+ }
if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
abi)) {
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index c44170928992..8323d0ba2415 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -45,11 +45,8 @@ using android::ApkAssets;
using android::ApkAssetsCookie;
using android::AssetManager2;
using android::ConfigDescription;
-using android::is_valid_resid;
-using android::kInvalidCookie;
using android::Res_value;
using android::ResStringPool;
-using android::ResTable_config;
using android::StringPiece16;
using android::base::StringPrintf;
using android::idmap2::CommandLineOptions;
@@ -59,7 +56,6 @@ using android::idmap2::ResourceId;
using android::idmap2::Result;
using android::idmap2::Unit;
using android::idmap2::utils::ExtractOverlayManifestInfo;
-using android::util::Utf16ToUtf8;
namespace {
@@ -69,25 +65,23 @@ Result<ResourceId> WARN_UNUSED ParseResReference(const AssetManager2& am, const
// first, try to parse as a hex number
char* endptr = nullptr;
- ResourceId resid;
- resid = strtol(res.c_str(), &endptr, kBaseHex);
+ const ResourceId parsed_resid = strtol(res.c_str(), &endptr, kBaseHex);
if (*endptr == '\0') {
- return resid;
+ return parsed_resid;
}
// next, try to parse as a package:type/name string
- resid = am.GetResourceId(res, "", fallback_package);
- if (is_valid_resid(resid)) {
- return resid;
+ if (auto resid = am.GetResourceId(res, "", fallback_package)) {
+ return *resid;
}
// end of the road: res could not be parsed
return Error("failed to obtain resource id for %s", res.c_str());
}
-void PrintValue(AssetManager2* const am, const Res_value& value, const ApkAssetsCookie& cookie,
+void PrintValue(AssetManager2* const am, const AssetManager2::SelectedValue& value,
std::string* const out) {
- switch (value.dataType) {
+ switch (value.type) {
case Res_value::TYPE_INT_DEC:
out->append(StringPrintf("%d", value.data));
break;
@@ -98,30 +92,21 @@ void PrintValue(AssetManager2* const am, const Res_value& value, const ApkAssets
out->append(value.data != 0 ? "true" : "false");
break;
case Res_value::TYPE_STRING: {
- const ResStringPool* pool = am->GetStringPoolForCookie(cookie);
+ const ResStringPool* pool = am->GetStringPoolForCookie(value.cookie);
out->append("\"");
- size_t len;
- if (pool->isUTF8()) {
- const char* str = pool->string8At(value.data, &len);
- out->append(str, len);
- } else {
- const char16_t* str16 = pool->stringAt(value.data, &len);
- out->append(Utf16ToUtf8(StringPiece16(str16, len)));
+ if (auto str = pool->string8ObjectAt(value.data)) {
+ out->append(*str);
}
- out->append("\"");
} break;
default:
- out->append(StringPrintf("dataType=0x%02x data=0x%08x", value.dataType, value.data));
+ out->append(StringPrintf("dataType=0x%02x data=0x%08x", value.type, value.data));
break;
}
}
Result<std::string> WARN_UNUSED GetValue(AssetManager2* const am, ResourceId resid) {
- Res_value value;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = am->GetResource(resid, true, 0, &value, &config, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = am->GetResource(resid);
+ if (!value.has_value()) {
return Error("no resource 0x%08x in asset manager", resid);
}
@@ -129,41 +114,35 @@ Result<std::string> WARN_UNUSED GetValue(AssetManager2* const am, ResourceId res
// TODO(martenkongstad): use optional parameter GetResource(..., std::string*
// stacktrace = NULL) instead
- out.append(StringPrintf("cookie=%d ", cookie));
+ out.append(StringPrintf("cookie=%d ", value->cookie));
out.append("config='");
- out.append(config.toString().c_str());
+ out.append(value->config.toString().c_str());
out.append("' value=");
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- const android::ResolvedBag* bag = am->GetBag(static_cast<uint32_t>(value.data));
- if (bag == nullptr) {
- out.append(StringPrintf("dataType=0x%02x data=0x%08x", value.dataType, value.data));
+ if (value->type == Res_value::TYPE_REFERENCE) {
+ auto bag_result = am->GetBag(static_cast<uint32_t>(value->data));
+ if (!bag_result.has_value()) {
+ out.append(StringPrintf("dataType=0x%02x data=0x%08x", value->type, value->data));
return out;
}
+
out.append("[");
- Res_value bag_val;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie bag_cookie;
+ const android::ResolvedBag* bag = bag_result.value();
for (size_t i = 0; i < bag->entry_count; ++i) {
- const android::ResolvedBag::Entry& entry = bag->entries[i];
- bag_val = entry.value;
- bag_cookie = am->ResolveReference(entry.cookie, &bag_val, &selected_config, &flags, &ref);
- if (bag_cookie == kInvalidCookie) {
- out.append(
- StringPrintf("Error: dataType=0x%02x data=0x%08x", bag_val.dataType, bag_val.data));
+ AssetManager2::SelectedValue entry(bag, bag->entries[i]);
+ if (am->ResolveReference(entry).has_value()) {
+ out.append(StringPrintf("Error: dataType=0x%02x data=0x%08x", entry.type, entry.data));
continue;
}
- PrintValue(am, bag_val, bag_cookie, &out);
+ PrintValue(am, entry, &out);
if (i != bag->entry_count - 1) {
out.append(", ");
}
}
out.append("]");
} else {
- PrintValue(am, value, cookie, &out);
+ PrintValue(am, *value, &out);
}
return out;
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index 1d2090c431ae..0127e874b444 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -17,8 +17,6 @@
#ifndef IDMAP2_IDMAP2D_IDMAP2SERVICE_H_
#define IDMAP2_IDMAP2D_IDMAP2SERVICE_H_
-#include <string>
-
#include <android-base/unique_fd.h>
#include <binder/BinderService.h>
diff --git a/cmds/idmap2/include/idmap2/ResourceMapping.h b/cmds/idmap2/include/idmap2/ResourceMapping.h
index 0a58ec43d8ff..f66916ccb78c 100644
--- a/cmds/idmap2/include/idmap2/ResourceMapping.h
+++ b/cmds/idmap2/include/idmap2/ResourceMapping.h
@@ -117,7 +117,8 @@ class ResourceMapping {
static Result<ResourceMapping> CreateResourceMappingLegacy(const AssetManager2* target_am,
const AssetManager2* overlay_am,
const LoadedPackage* target_package,
- const LoadedPackage* overlay_package);
+ const LoadedPackage* overlay_package,
+ LogInfo& log_info);
// Removes resources that do not pass policy or overlayable checks of the target package.
void FilterOverlayableResources(const AssetManager2* target_am,
diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
index a93202a64d31..3037a791328e 100644
--- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
@@ -100,10 +100,9 @@ void PrettyPrintVisitor::visit(const IdmapData& data) {
stream_ << TAB << base::StringPrintf("0x%08x -> ", target_entry.target_id)
<< utils::DataTypeToString(target_entry.value.data_type);
- size_t unused;
if (target_entry.value.data_type == Res_value::TYPE_STRING) {
- auto str = string_pool.stringAt(target_entry.value.data_value - string_pool_offset, &unused);
- stream_ << " \"" << StringPiece16(str) << "\"";
+ auto str = string_pool.stringAt(target_entry.value.data_value - string_pool_offset);
+ stream_ << " \"" << str.value_or(StringPiece16(u"")) << "\"";
} else {
stream_ << " " << base::StringPrintf("0x%08x", target_entry.value.data_value);
}
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 31f1c16ba5a6..d777cbfa9a14 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -71,9 +71,10 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
if (!target_package.DefinesOverlayable()) {
return (sDefaultPolicies & fulfilled_policies) != 0
? Result<Unit>({})
- : Error("overlay must be preinstalled, signed with the same signature as the target,"
- " or signed with the same signature as the package referenced through"
- " <overlay-config-signature>.");
+ : Error(
+ "overlay must be preinstalled, signed with the same signature as the target,"
+ " or signed with the same signature as the package referenced through"
+ " <overlay-config-signature>.");
}
const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(target_resource);
@@ -119,32 +120,25 @@ const LoadedPackage* GetPackageAtIndex0(const LoadedArsc& loaded_arsc) {
Result<std::unique_ptr<Asset>> OpenNonAssetFromResource(const ResourceId& resource_id,
const AssetManager2& asset_manager) {
- Res_value value{};
- ResTable_config selected_config{};
- uint32_t flags;
- auto cookie =
- asset_manager.GetResource(resource_id, /* may_be_bag */ false,
- /* density_override */ 0U, &value, &selected_config, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = asset_manager.GetResource(resource_id);
+ if (!value.has_value()) {
return Error("failed to find resource for id 0x%08x", resource_id);
}
- if (value.dataType != Res_value::TYPE_STRING) {
+ if (value->type != Res_value::TYPE_STRING) {
return Error("resource for is 0x%08x is not a file", resource_id);
}
- auto string_pool = asset_manager.GetStringPoolForCookie(cookie);
- size_t len;
- auto file_path16 = string_pool->stringAt(value.data, &len);
- if (file_path16 == nullptr) {
- return Error("failed to find string for index %d", value.data);
+ auto string_pool = asset_manager.GetStringPoolForCookie(value->cookie);
+ auto file = string_pool->string8ObjectAt(value->data);
+ if (!file.has_value()) {
+ return Error("failed to find string for index %d", value->data);
}
// Load the overlay resource mappings from the file specified using android:resourcesMap.
- auto file_path = String8(String16(file_path16));
- auto asset = asset_manager.OpenNonAsset(file_path.c_str(), Asset::AccessMode::ACCESS_BUFFER);
+ auto asset = asset_manager.OpenNonAsset(file->c_str(), Asset::AccessMode::ACCESS_BUFFER);
if (asset == nullptr) {
- return Error("file \"%s\" not found", file_path.c_str());
+ return Error("file \"%s\" not found", file->c_str());
}
return asset;
@@ -190,16 +184,16 @@ Result<ResourceMapping> ResourceMapping::CreateResourceMapping(const AssetManage
return Error(R"(<item> tag missing expected attribute "value")");
}
- ResourceId target_id =
+ auto target_id_result =
target_am->GetResourceId(*target_resource, "", target_package->GetPackageName());
- if (target_id == 0U) {
+ if (!target_id_result.has_value()) {
log_info.Warning(LogMessage() << "failed to find resource \"" << *target_resource
<< "\" in target resources");
continue;
}
// Retrieve the compile-time resource id of the target resource.
- target_id = REWRITE_PACKAGE(target_id, target_package_id);
+ uint32_t target_id = REWRITE_PACKAGE(*target_id_result, target_package_id);
if (overlay_resource->dataType == Res_value::TYPE_STRING) {
overlay_resource->data += string_pool_offset;
@@ -220,7 +214,7 @@ Result<ResourceMapping> ResourceMapping::CreateResourceMapping(const AssetManage
Result<ResourceMapping> ResourceMapping::CreateResourceMappingLegacy(
const AssetManager2* target_am, const AssetManager2* overlay_am,
- const LoadedPackage* target_package, const LoadedPackage* overlay_package) {
+ const LoadedPackage* target_package, const LoadedPackage* overlay_package, LogInfo& log_info) {
ResourceMapping resource_mapping;
const uint8_t target_package_id = target_package->GetPackageId();
const auto end = overlay_package->end();
@@ -234,13 +228,15 @@ Result<ResourceMapping> ResourceMapping::CreateResourceMappingLegacy(
// Find the resource with the same type and entry name within the target package.
const std::string full_name =
base::StringPrintf("%s:%s", target_package->GetPackageName().c_str(), name->c_str());
- ResourceId target_resource = target_am->GetResourceId(full_name);
- if (target_resource == 0U) {
+ auto target_resource_result = target_am->GetResourceId(full_name);
+ if (!target_resource_result.has_value()) {
+ log_info.Warning(LogMessage() << "failed to find resource \"" << full_name
+ << "\" in target resources");
continue;
}
// Retrieve the compile-time resource id of the target resource.
- target_resource = REWRITE_PACKAGE(target_resource, target_package_id);
+ ResourceId target_resource = REWRITE_PACKAGE(*target_resource_result, target_package_id);
resource_mapping.AddMapping(target_resource, overlay_resid,
false /* rewrite_overlay_reference */);
}
@@ -347,7 +343,9 @@ Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_a
auto& string_pool = (*parser)->get_strings();
string_pool_data_length = string_pool.bytes();
string_pool_data.reset(new uint8_t[string_pool_data_length]);
- memcpy(string_pool_data.get(), string_pool.data(), string_pool_data_length);
+
+ // Overlays should not be incrementally installed, so calling unsafe_ptr is fine here.
+ memcpy(string_pool_data.get(), string_pool.data().unsafe_ptr(), string_pool_data_length);
// Offset string indices by the size of the overlay resource table string pool.
string_pool_offset = overlay_arsc->GetStringPool()->size();
@@ -358,7 +356,7 @@ Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_a
// If no file is specified using android:resourcesMap, it is assumed that the overlay only
// defines resources intended to override target resources of the same type and name.
resource_mapping = CreateResourceMappingLegacy(&target_asset_manager, &overlay_asset_manager,
- target_pkg, overlay_pkg);
+ target_pkg, overlay_pkg, log_info);
}
if (!resource_mapping) {
diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp
index 98d026bc70dc..e817140238ae 100644
--- a/cmds/idmap2/libidmap2/ResourceUtils.cpp
+++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp
@@ -72,21 +72,21 @@ StringPiece DataTypeToString(uint8_t data_type) {
}
Result<std::string> ResToTypeEntryName(const AssetManager2& am, uint32_t resid) {
- AssetManager2::ResourceName name;
- if (!am.GetResourceName(resid, &name)) {
+ const auto name = am.GetResourceName(resid);
+ if (!name.has_value()) {
return Error("no resource 0x%08x in asset manager", resid);
}
std::string out;
- if (name.type != nullptr) {
- out.append(name.type, name.type_len);
+ if (name->type != nullptr) {
+ out.append(name->type, name->type_len);
} else {
- out += Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
+ out += Utf16ToUtf8(StringPiece16(name->type16, name->type_len));
}
out.append("/");
- if (name.entry != nullptr) {
- out.append(name.entry, name.entry_len);
+ if (name->entry != nullptr) {
+ out.append(name->entry, name->entry_len);
} else {
- out += Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
+ out += Utf16ToUtf8(StringPiece16(name->entry16, name->entry_len));
}
return out;
}
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
index 526a560907aa..7c55b64566f2 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -98,18 +98,19 @@ Result<std::string> XmlParser::Node::GetAttributeStringValue(const std::string&
switch ((*value).dataType) {
case Res_value::TYPE_STRING: {
- size_t len;
- const String16 value16(parser_.getStrings().stringAt((*value).data, &len));
- return std::string(String8(value16).c_str());
+ if (auto str = parser_.getStrings().string8ObjectAt((*value).data)) {
+ return std::string(str->string());
+ }
+ break;
}
case Res_value::TYPE_INT_DEC:
case Res_value::TYPE_INT_HEX:
case Res_value::TYPE_INT_BOOLEAN: {
return std::to_string((*value).data);
}
- default:
- return Error(R"(Failed to convert attribute "%s" value to a string)", name.c_str());
}
+
+ return Error(R"(Failed to convert attribute "%s" value to a string)", name.c_str());
}
Result<Res_value> XmlParser::Node::GetAttributeValue(const std::string& name) const {
diff --git a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
index 8683ca163fb6..a0361d0a39d3 100644
--- a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
+++ b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
@@ -294,9 +294,9 @@ public class RequestSync {
" -a|--authority <AUTHORITY>\n" +
" App-standby related options\n" +
"\n" +
- " -f|--foreground (cause WORKING_SET, FREQUENT sync adapters" +
- " to run immediately)\n" +
- " -F|--top (cause even RARE sync adapters to run immediately)\n" +
+ " -f|--foreground (defeat app-standby job throttling," +
+ " but not battery saver)\n" +
+ " -F|--top (defeat app-standby job throttling and battery saver)\n" +
" ContentResolver extra options:\n" +
" --is|--ignore-settings: Add SYNC_EXTRAS_IGNORE_SETTINGS\n" +
" --ib|--ignore-backoff: Add SYNC_EXTRAS_IGNORE_BACKOFF\n" +
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 012450d73266..d225f966c39d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -294,6 +294,7 @@ cc_test {
"tests/e2e/Anomaly_duration_sum_e2e_test.cpp",
"tests/e2e/Attribution_e2e_test.cpp",
"tests/e2e/ConfigTtl_e2e_test.cpp",
+ "tests/e2e/ConfigUpdate_e2e_test.cpp",
"tests/e2e/CountMetric_e2e_test.cpp",
"tests/e2e/DurationMetric_e2e_test.cpp",
"tests/e2e/GaugeMetric_e2e_pull_test.cpp",
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 7bee4e2d1a36..6eff639aca92 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -520,10 +520,10 @@ void StatsLogProcessor::GetActiveConfigsLocked(const int uid, vector<int64_t>& o
}
void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
- const StatsdConfig& config) {
+ const StatsdConfig& config, bool modularUpdate) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
WriteDataToDiskLocked(key, timestampNs, CONFIG_UPDATED, NO_TIME_CONSTRAINTS);
- OnConfigUpdatedLocked(timestampNs, key, config);
+ OnConfigUpdatedLocked(timestampNs, key, config, modularUpdate);
}
void StatsLogProcessor::OnConfigUpdatedLocked(const int64_t timestampNs, const ConfigKey& key,
@@ -549,9 +549,7 @@ void StatsLogProcessor::OnConfigUpdatedLocked(const int64_t timestampNs, const C
configValid = it->second->updateConfig(config, mTimeBaseNs, timestampNs,
mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
if (configValid) {
- // TODO(b/162323476): refresh TTL, ensure init() is handled properly.
mUidMap->OnConfigUpdated(key);
-
}
}
if (!configValid) {
@@ -720,7 +718,8 @@ void StatsLogProcessor::resetConfigsLocked(const int64_t timestampNs,
for (const auto& key : configs) {
StatsdConfig config;
if (StorageManager::readConfigFromDisk(key, &config)) {
- OnConfigUpdatedLocked(timestampNs, key, config);
+ // Force a full update when resetting a config.
+ OnConfigUpdatedLocked(timestampNs, key, config, /*modularUpdate=*/false);
StatsdStats::getInstance().noteConfigReset(key);
} else {
ALOGE("Failed to read backup config from disk for : %s", key.ToString().c_str());
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 383dbd9db2c1..2af277ad1e5b 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -48,7 +48,7 @@ public:
void OnLogEvent(LogEvent* event);
void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
- const StatsdConfig& config);
+ const StatsdConfig& config, bool modularUpdate = false);
void OnConfigRemoved(const ConfigKey& key);
size_t GetMetricsSize(const ConfigKey& key) const;
@@ -188,7 +188,7 @@ private:
void resetIfConfigTtlExpiredLocked(const int64_t timestampNs);
void OnConfigUpdatedLocked(const int64_t currentTimestampNs, const ConfigKey& key,
- const StatsdConfig& config, bool modularUpdate = false);
+ const StatsdConfig& config, bool modularUpdate);
void GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs);
@@ -338,6 +338,10 @@ private:
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation);
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);
+ FRIEND_TEST(ConfigUpdateE2eTest, TestHashStrings);
+ FRIEND_TEST(ConfigUpdateE2eTest, TestUidMapVersionStringInstaller);
+ FRIEND_TEST(ConfigUpdateE2eTest, TestConfigTtl);
+
FRIEND_TEST(CountMetricE2eTest, TestInitialConditionChanges);
FRIEND_TEST(CountMetricE2eTest, TestSlicedState);
FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index ac2a8e4ffcd2..f7bbcbb1834b 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -158,7 +158,7 @@ message Atom {
AppStartMemoryStateCaptured app_start_memory_state_captured = 55 [(module) = "framework"];
ShutdownSequenceReported shutdown_sequence_reported = 56 [(module) = "framework"];
BootSequenceReported boot_sequence_reported = 57;
- DaveyOccurred davey_occurred = 58 [(module) = "statsd"];
+ DaveyOccurred davey_occurred = 58 [(module) = "statsd", deprecated = true];
OverlayStateChanged overlay_state_changed =
59 [(module) = "framework", (module) = "statsdtest"];
ForegroundServiceStateChanged foreground_service_state_changed
@@ -502,6 +502,12 @@ message Atom {
MediametricsMediaParserReported mediametrics_mediaparser_reported = 316;
TlsHandshakeReported tls_handshake_reported = 317 [(module) = "conscrypt"];
TextClassifierApiUsageReported text_classifier_api_usage_reported = 318 [(module) = "textclassifier"];
+ KilledAppStatsReported killed_app_stats_reported = 319 [(module) = "carwatchdogd"];
+ MediametricsPlaybackReported mediametrics_playback_reported = 320;
+ MediaNetworkInfoChanged media_network_info_changed = 321;
+ MediaPlaybackStateChanged media_playback_state_changed = 322;
+ MediaPlaybackErrorReported media_playback_error_reported = 323;
+ MediaPlaybackTrackChanged media_playback_track_changed = 324;
// StatsdStats tracks platform atoms with ids upto 500.
// Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -3608,6 +3614,8 @@ message AppCrashOccurred {
optional ForegroundState foreground_state = 7;
optional android.server.ErrorSource error_source = 8;
+
+ optional bool is_package_loading = 9;
}
/**
@@ -3669,6 +3677,8 @@ message ANROccurred {
optional android.server.ErrorSource error_source = 7;
optional string package_name = 8;
+
+ optional bool is_package_loading = 9;
}
/**
@@ -4280,9 +4290,16 @@ message NotificationChannelModified {
optional android.stats.sysui.NotificationImportance old_importance = 5;
// New importance setting
optional android.stats.sysui.NotificationImportance importance = 6;
+ // whether or not this channel represents a conversation
+ optional bool is_conversation = 7;
+ // Hash of app-assigned notification conversation id
+ optional int32 conversation_id_hash = 8;
+ // whether or not the user demoted this channel out of the conversation space
+ optional bool is_conversation_demoted = 9;
+ // whether this conversation is marked as being a priority
+ optional bool is_conversation_priority = 10;
}
-
/**
* Logs when a biometric acquire event occurs.
*
@@ -5304,6 +5321,11 @@ message UIInteractionFrameInfoReported {
LAUNCHER_APP_CLOSE_TO_HOME = 10;
LAUNCHER_APP_CLOSE_TO_PIP = 11;
LAUNCHER_QUICK_SWITCH = 12;
+ SHADE_HEADS_UP_APPEAR = 13;
+ SHADE_HEADS_UP_DISAPPEAR = 14;
+ SHADE_NOTIFICATION_ADD = 15;
+ SHADE_NOTIFICATION_REMOVE = 16;
+ SHADE_APP_LAUNCH = 17;
}
optional InteractionType interaction_type = 1;
@@ -12067,3 +12089,262 @@ message TextClassifierApiUsageReported {
optional ResultType result_type = 2;
optional int64 latency_millis = 3;
}
+
+/**
+ * Logs the current state of an application before it is killed.
+ *
+ * Pushed from:
+ * packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
+ */
+message KilledAppStatsReported {
+ // Linux process uid for the package.
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // Name of the package that was killed.
+ optional string package_name = 2;
+
+ // State of the application when it was killed.
+ enum AppState {
+ UNKNOWN_APP_STATE = 0;
+ BACKGROUND = 1;
+ FOREGROUND = 2;
+ }
+ optional AppState app_state = 3;
+
+ // System state indicating whether the system was in normal mode or garage mode.
+ enum SystemState {
+ UNKNOWN_SYSTEM_STATE = 0;
+ USER_INTERACTION_MODE = 1;
+ NO_USER_INTERACTION_MODE = 2;
+ }
+ optional SystemState system_state = 4;
+
+ // Reason for killing the application.
+ // Keep in sync between:
+ // packages/services/Car/watchdog/server/src/ApplicationTerminator.h
+ // frameworks/base/cmds/statsd/src/atoms.proto
+ enum KillReason {
+ UNKNOWN_KILL_REASON = 0;
+ KILLED_ON_ANR = 1;
+ KILLED_ON_IO_OVERUSE = 2;
+ KILLED_ON_MEMORY_OVERUSE = 3;
+ }
+ optional KillReason kill_reason = 5;
+
+ // Stats of the processes owned by the application when the application was killed.
+ // The process stack traces are not collected when the application was killed due to IO_OVERUSE.
+ optional ProcessStats process_stat = 6 [(log_mode) = MODE_BYTES];
+
+ // The application's I/O overuse stats logged only when the kill reason is KILLED_ON_IO_OVERUSE.
+ optional IoOveruseStats io_overuse_stats = 7 [(log_mode) = MODE_BYTES];
+}
+
+/**
+ * Logs I/O overuse stats for a package.
+ *
+ * Keep in sync between:
+ * packages/services/Car/watchdog/server/src/proto/statsd.proto
+ * frameworks/base/cmds/statsd/src/atoms.proto
+ *
+ * Logged from:
+ * packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
+ */
+message IoOveruseStats {
+ enum Period {
+ DAILY = 0;
+ WEEKLY = 1;
+ }
+
+ // Threshold and usage stats period.
+ optional Period period = 1;
+
+ // Threshold in-terms of write bytes defined for the package.
+ optional PerStateBytes threshold = 2;
+
+ // Number of write bytes in each state for the specified period.
+ optional PerStateBytes written_bytes = 3;
+};
+
+/**
+ * Logs bytes attributed to each application and system states.
+ *
+ * Keep in sync between:
+ * packages/services/Car/watchdog/server/src/proto/statsd.proto
+ * frameworks/base/cmds/statsd/src/atoms.proto
+ *
+ * Logged from:
+ * packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
+ */
+message PerStateBytes {
+ // Number of bytes attributed to the application foreground.
+ optional int64 foreground_bytes = 1;
+
+ // Number of bytes attributed to the application background.
+ optional int64 background_bytes = 2;
+
+ // Number of bytes attributed to the garage mode.
+ optional int64 garage_mode_bytes = 3;
+}
+
+/**
+ * Logs each ProcessStat in ProcessStats.
+ * Keep in sync between:
+ * packages/services/Car/watchdog/server/src/proto/statsd.proto
+ * frameworks/base/cmds/statsd/src/atoms.proto
+ * Logged from:
+ * packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
+ */
+message ProcessStats {
+ // Records the stats of the processes owned by an application.
+ repeated ProcessStat process_stat = 1;
+}
+
+/**
+ * Logs a process's stats.
+ * Keep in sync between:
+ * packages/services/Car/watchdog/server/src/proto/statsd.proto
+ * frameworks/base/cmds/statsd/src/atoms.proto
+ * Logged from:
+ * packages/services/Car/watchdog/server/src/ApplicationTerminator.cpp
+ */
+message ProcessStat {
+ // Command name of the process.
+ optional string process_name = 1;
+
+ // Process uptime.
+ optional uint64 uptime_milliseconds = 2;
+
+ // Number of major page faults caused by the process and its children.
+ optional uint64 major_page_faults = 3;
+
+ // Peak virtual memory size in kb.
+ optional uint64 vm_peak_kb = 4;
+
+ // Virtual memory size in kb.
+ optional uint64 vm_size_kb = 5;
+
+ // Peak resident set size (high water mark) in kb.
+ optional uint64 vm_hwm_kb = 6;
+
+ // Resident set size in kb.
+ optional uint64 vm_rss_kb = 7;
+}
+
+/*
+ * pushes Media playback information.
+ * Logged from
+ * (WIP) frameworks/av/services/mediaanalytics/playback_statsd.cpp
+ */
+message MediametricsPlaybackReported {
+ optional int32 uid = 1 [(is_uid) = true];
+
+ // Randomly generated playback ID. A Base64 encoded hex string representing a 128-bit integer
+ optional string playback_id = 2;
+ // The total length of the media in milliseconds. 0 for live contents.
+ optional int64 media_duration_millis = 3;
+ // Network, device, or mixed.
+ optional android.stats.mediametrics.StreamSourceType stream_source = 4;
+ // Stream type. DASH, HLS, etc
+ optional android.stats.mediametrics.StreamType stream_type = 5;
+ // Live, VOD, others
+ optional android.stats.mediametrics.PlaybackType playback_type = 6;
+ // DRM type
+ optional android.stats.mediametrics.DrmType drm_type = 7;
+ // Main, AD, others
+ optional android.stats.mediametrics.ContentType content_type = 8;
+ // Player name. E.g. ExoPlayer
+ optional string player_name = 9;
+ // Player version. E.g. 1.10.3e
+ optional string player_version = 10;
+ // Player related experiment IDs
+ optional Experiments experiment_ids = 11 [(log_mode) = MODE_BYTES];
+ // Number of frames played. Dropped frames included. -1 means unknown.
+ optional int32 video_frames_played = 12;
+ // Number of frames dropped. -1 means unknown.
+ optional int32 video_frames_dropped = 13;
+ // Number of audio underruns. -1 means unknown.
+ optional int32 audio_underrun_count = 14;
+ // Total number of bytes read from the network
+ optional int64 network_bytes_read = 15;
+ // Total number of bytes read from on-device sources
+ optional int64 local_bytes_read = 16;
+ // Total transfer spent reading from the network in ms.
+ // For parallel requests, the overlapping time intervals are counted only once.
+ optional int64 network_transfer_duration_millis = 17;
+}
+
+message MediaNetworkInfoChanged {
+ // Randomly generated playback ID. A Base64 encoded hex string representing a 128-bit integer
+ optional string playback_id = 1;
+ // New network type
+ optional android.stats.mediametrics.NetworkType type = 2;
+ // Network Start time, relative to playback creation time in millisecond.
+ // It's in absolute time (e.g. always ticks even if the playback is paused).
+ optional int64 time_since_playback_created_millis = 3;
+}
+
+message MediaPlaybackStateChanged {
+ // Randomly generated playback ID. A Base64 encoded hex string representing a 128-bit integer
+ optional string playback_id = 1;
+ // New playback state
+ optional android.stats.mediametrics.PlaybackState playback_state = 2;
+ // State change time, relative to playback creation time in millisecond.
+ // It's in absolute time (e.g. always ticks even if the playback is paused).
+ optional int64 time_since_playback_created_millis = 3;
+}
+
+message MediaPlaybackErrorReported {
+ // Randomly generated playback ID. A Base64 encoded hex string representing a 128-bit integer
+ optional string playback_id = 1;
+ // A shortened call stack of the error
+ optional string exception_stack = 2;
+ // Error code
+ optional android.stats.mediametrics.PlaybackErrorCode error_code = 3;
+ // Sub-code of error type specified by the error code.
+ optional int32 sub_error_code = 4;
+ // Error time, relative to playback creation time in millisecond.
+ // It's in absolute time (e.g. always ticks even if the playback is paused).
+ optional int64 time_since_playback_created_millis = 5;
+}
+
+message MediaPlaybackTrackChanged {
+ // Randomly generated playback ID. A Base64 encoded hex string representing a 128-bit integer
+ optional string playback_id = 1;
+ // The track is on or off after the change
+ optional android.stats.mediametrics.TrackState state = 2;
+ // The reason of the track change
+ optional android.stats.mediametrics.TrackChangeReason reason = 3;
+ // The MIME type of the container. E.g. video/mp4
+ optional string container_mime_type = 4;
+ // The sample MIME type of the track. E.g. video/avc
+ optional string sample_mime_type = 5;
+
+ // Codec name
+ optional string codec_name = 6;
+ // Bits per second. 0 means unknown.
+ optional int32 bitrate = 7;
+
+ // Track change time, relative to playback creation time in millisecond.
+ // It's in absolute time (e.g. always ticks even if the playback is paused).
+ optional int64 time_since_playback_created_millis = 8;
+
+ // Track type. Audio, Video, Text
+ optional android.stats.mediametrics.TrackType type = 9;
+ // 2-letter ISO 639-1 language code.
+ optional string language = 10;
+ // IETF BCP 47 optional language region subtag based on a two-letter country code
+ optional string language_region = 11;
+ // Number of channels
+ optional int32 channel_count = 12;
+ // Samples per second
+ optional int32 sample_rate = 13;
+ // The width of the video in pixels.
+ optional int32 width = 14;
+ // The height of the video in pixels.
+ optional int32 height = 15;
+}
+
+message Experiments {
+ // Experiment IDs sent by the player.
+ repeated int64 experiments = 1;
+}
diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h
index dcd5e52feefd..3d301379f359 100644
--- a/cmds/statsd/src/config/ConfigListener.h
+++ b/cmds/statsd/src/config/ConfigListener.h
@@ -39,7 +39,7 @@ public:
* A configuration was added or updated.
*/
virtual void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
- const StatsdConfig& config) = 0;
+ const StatsdConfig& config, bool modularUpdate = false) = 0;
/**
* A configuration was removed.
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index d80f9dbb4256..f9b0a1030eee 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -90,11 +90,107 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
mVersionStringsInReport = config.version_strings_in_metric_report();
mInstallerInReport = config.installer_in_metric_report();
+ createAllLogSourcesFromConfig(config);
+ mPullerManager->RegisterPullUidProvider(mConfigKey, this);
+
+ // Store the sub-configs used.
+ for (const auto& annotation : config.annotation()) {
+ mAnnotations.emplace_back(annotation.field_int64(), annotation.field_int32());
+ }
+ verifyGuardrailsAndUpdateStatsdStats();
+ initializeConfigActiveStatus();
+}
+
+MetricsManager::~MetricsManager() {
+ for (auto it : mAllMetricProducers) {
+ for (int atomId : it->getSlicedStateAtoms()) {
+ StateManager::getInstance().unregisterListener(atomId, it);
+ }
+ }
+ mPullerManager->UnregisterPullUidProvider(mConfigKey, this);
+
+ VLOG("~MetricsManager()");
+}
+
+bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t timeBaseNs,
+ const int64_t currentTimeNs,
+ const sp<AlarmMonitor>& anomalyAlarmMonitor,
+ const sp<AlarmMonitor>& periodicAlarmMonitor) {
+ vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
+ unordered_map<int64_t, int> newAtomMatchingTrackerMap;
+ vector<sp<ConditionTracker>> newConditionTrackers;
+ unordered_map<int64_t, int> newConditionTrackerMap;
+ map<int64_t, uint64_t> newStateProtoHashes;
+ vector<sp<MetricProducer>> newMetricProducers;
+ unordered_map<int64_t, int> newMetricProducerMap;
+ vector<sp<AnomalyTracker>> newAnomalyTrackers;
+ unordered_map<int64_t, int> newAlertTrackerMap;
+ vector<sp<AlarmTracker>> newPeriodicAlarmTrackers;
+ mTagIds.clear();
+ mConditionToMetricMap.clear();
+ mTrackerToMetricMap.clear();
+ mTrackerToConditionMap.clear();
+ mActivationAtomTrackerToMetricMap.clear();
+ mDeactivationAtomTrackerToMetricMap.clear();
+ mMetricIndexesWithActivation.clear();
+ mNoReportMetricIds.clear();
+ mConfigValid = updateStatsdConfig(
+ mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
+ mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap,
+ mAllAnomalyTrackers, mAlertTrackerMap, mStateProtoHashes, mTagIds,
+ newAtomMatchingTrackers, newAtomMatchingTrackerMap, newConditionTrackers,
+ newConditionTrackerMap, newMetricProducers, newMetricProducerMap, newAnomalyTrackers,
+ newAlertTrackerMap, newPeriodicAlarmTrackers, mConditionToMetricMap,
+ mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
+ mDeactivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, newStateProtoHashes,
+ mNoReportMetricIds);
+ mAllAtomMatchingTrackers = newAtomMatchingTrackers;
+ mAtomMatchingTrackerMap = newAtomMatchingTrackerMap;
+ mAllConditionTrackers = newConditionTrackers;
+ mConditionTrackerMap = newConditionTrackerMap;
+ mAllMetricProducers = newMetricProducers;
+ mMetricProducerMap = newMetricProducerMap;
+ mStateProtoHashes = newStateProtoHashes;
+ mAllAnomalyTrackers = newAnomalyTrackers;
+ mAlertTrackerMap = newAlertTrackerMap;
+ mAllPeriodicAlarmTrackers = newPeriodicAlarmTrackers;
+
+ mTtlNs = config.has_ttl_in_seconds() ? config.ttl_in_seconds() * NS_PER_SEC : -1;
+ refreshTtl(currentTimeNs);
+
+ mHashStringsInReport = config.hash_strings_in_metric_report();
+ mVersionStringsInReport = config.version_strings_in_metric_report();
+ mInstallerInReport = config.installer_in_metric_report();
+ mWhitelistedAtomIds.clear();
+ mWhitelistedAtomIds.insert(config.whitelisted_atom_ids().begin(),
+ config.whitelisted_atom_ids().end());
+ mShouldPersistHistory = config.persist_locally();
+
+ // Store the sub-configs used.
+ mAnnotations.clear();
+ for (const auto& annotation : config.annotation()) {
+ mAnnotations.emplace_back(annotation.field_int64(), annotation.field_int32());
+ }
+
+ mAllowedUid.clear();
+ mAllowedPkg.clear();
+ mDefaultPullUids.clear();
+ mPullAtomUids.clear();
+ mPullAtomPackages.clear();
+ createAllLogSourcesFromConfig(config);
+
+ verifyGuardrailsAndUpdateStatsdStats();
+ initializeConfigActiveStatus();
+ return mConfigValid;
+}
+
+void MetricsManager::createAllLogSourcesFromConfig(const StatsdConfig& config) {
// Init allowed pushed atom uids.
if (config.allowed_log_source_size() == 0) {
mConfigValid = false;
ALOGE("Log source allowlist is empty! This config won't get any data. Suggest adding at "
- "least AID_SYSTEM and AID_STATSD to the allowed_log_source field.");
+ "least AID_SYSTEM and AID_STATSD to the allowed_log_source field.");
} else {
for (const auto& source : config.allowed_log_source()) {
auto it = UidMap::sAidToUidMapping.find(source);
@@ -109,7 +205,7 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
ALOGE("Too many log sources. This is likely to be an error in the config.");
mConfigValid = false;
} else {
- initLogSourceWhiteList();
+ initAllowedLogSources();
}
}
@@ -145,13 +241,9 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
} else {
initPullAtomSources();
}
- mPullerManager->RegisterPullUidProvider(mConfigKey, this);
-
- // Store the sub-configs used.
- for (const auto& annotation : config.annotation()) {
- mAnnotations.emplace_back(annotation.field_int64(), annotation.field_int32());
- }
+}
+void MetricsManager::verifyGuardrailsAndUpdateStatsdStats() {
// Guardrail. Reject the config if it's too big.
if (mAllMetricProducers.size() > StatsdStats::kMaxMetricCountPerConfig ||
mAllConditionTrackers.size() > StatsdStats::kMaxConditionCountPerConfig ||
@@ -163,88 +255,24 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
ALOGE("This config has too many alerts! Reject!");
mConfigValid = false;
}
-
- mIsAlwaysActive = (mMetricIndexesWithActivation.size() != mAllMetricProducers.size()) ||
- (mAllMetricProducers.size() == 0);
- bool isActive = mIsAlwaysActive;
- for (int metric : mMetricIndexesWithActivation) {
- isActive |= mAllMetricProducers[metric]->isActive();
- }
- mIsActive = isActive;
- VLOG("mIsActive is initialized to %d", mIsActive)
-
// no matter whether this config is valid, log it in the stats.
StatsdStats::getInstance().noteConfigReceived(
- key, mAllMetricProducers.size(), mAllConditionTrackers.size(),
+ mConfigKey, mAllMetricProducers.size(), mAllConditionTrackers.size(),
mAllAtomMatchingTrackers.size(), mAllAnomalyTrackers.size(), mAnnotations,
mConfigValid);
- // Check active
- for (const auto& metric : mAllMetricProducers) {
- if (metric->isActive()) {
- mIsActive = true;
- break;
- }
- }
}
-MetricsManager::~MetricsManager() {
- for (auto it : mAllMetricProducers) {
- for (int atomId : it->getSlicedStateAtoms()) {
- StateManager::getInstance().unregisterListener(atomId, it);
- }
+void MetricsManager::initializeConfigActiveStatus() {
+ mIsAlwaysActive = (mMetricIndexesWithActivation.size() != mAllMetricProducers.size()) ||
+ (mAllMetricProducers.size() == 0);
+ mIsActive = mIsAlwaysActive;
+ for (int metric : mMetricIndexesWithActivation) {
+ mIsActive |= mAllMetricProducers[metric]->isActive();
}
- mPullerManager->UnregisterPullUidProvider(mConfigKey, this);
-
- VLOG("~MetricsManager()");
-}
-
-bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t timeBaseNs,
- const int64_t currentTimeNs,
- const sp<AlarmMonitor>& anomalyAlarmMonitor,
- const sp<AlarmMonitor>& periodicAlarmMonitor) {
- vector<sp<AtomMatchingTracker>> newAtomMatchingTrackers;
- unordered_map<int64_t, int> newAtomMatchingTrackerMap;
- vector<sp<ConditionTracker>> newConditionTrackers;
- unordered_map<int64_t, int> newConditionTrackerMap;
- map<int64_t, uint64_t> newStateProtoHashes;
- vector<sp<MetricProducer>> newMetricProducers;
- unordered_map<int64_t, int> newMetricProducerMap;
- vector<sp<AnomalyTracker>> newAnomalyTrackers;
- unordered_map<int64_t, int> newAlertTrackerMap;
- vector<sp<AlarmTracker>> newPeriodicAlarmTrackers;
- mTagIds.clear();
- mConditionToMetricMap.clear();
- mTrackerToMetricMap.clear();
- mTrackerToConditionMap.clear();
- mActivationAtomTrackerToMetricMap.clear();
- mDeactivationAtomTrackerToMetricMap.clear();
- mMetricIndexesWithActivation.clear();
- mNoReportMetricIds.clear();
- mConfigValid = updateStatsdConfig(
- mConfigKey, config, mUidMap, mPullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseNs, currentTimeNs, mAllAtomMatchingTrackers, mAtomMatchingTrackerMap,
- mAllConditionTrackers, mConditionTrackerMap, mAllMetricProducers, mMetricProducerMap,
- mAllAnomalyTrackers, mAlertTrackerMap, mStateProtoHashes, mTagIds,
- newAtomMatchingTrackers, newAtomMatchingTrackerMap, newConditionTrackers,
- newConditionTrackerMap, newMetricProducers, newMetricProducerMap, newAnomalyTrackers,
- newAlertTrackerMap, newPeriodicAlarmTrackers, mConditionToMetricMap,
- mTrackerToMetricMap, mTrackerToConditionMap, mActivationAtomTrackerToMetricMap,
- mDeactivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, newStateProtoHashes,
- mNoReportMetricIds);
- mAllAtomMatchingTrackers = newAtomMatchingTrackers;
- mAtomMatchingTrackerMap = newAtomMatchingTrackerMap;
- mAllConditionTrackers = newConditionTrackers;
- mConditionTrackerMap = newConditionTrackerMap;
- mAllMetricProducers = newMetricProducers;
- mMetricProducerMap = newMetricProducerMap;
- mStateProtoHashes = newStateProtoHashes;
- mAllAnomalyTrackers = newAnomalyTrackers;
- mAlertTrackerMap = newAlertTrackerMap;
- mAllPeriodicAlarmTrackers = newPeriodicAlarmTrackers;
- return mConfigValid;
+ VLOG("mIsActive is initialized to %d", mIsActive);
}
-void MetricsManager::initLogSourceWhiteList() {
+void MetricsManager::initAllowedLogSources() {
std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
mAllowedLogSources.clear();
mAllowedLogSources.insert(mAllowedUid.begin(), mAllowedUid.end());
@@ -288,7 +316,7 @@ void MetricsManager::notifyAppUpgrade(const int64_t& eventTimeNs, const string&
if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) != mAllowedPkg.end()) {
// We will re-initialize the whole list because we don't want to keep the multi mapping of
// UID<->pkg inside MetricsManager to reduce the memory usage.
- initLogSourceWhiteList();
+ initAllowedLogSources();
}
for (const auto& it : mPullAtomPackages) {
@@ -309,7 +337,7 @@ void MetricsManager::notifyAppRemoved(const int64_t& eventTimeNs, const string&
if (std::find(mAllowedPkg.begin(), mAllowedPkg.end(), apk) != mAllowedPkg.end()) {
// We will re-initialize the whole list because we don't want to keep the multi mapping of
// UID<->pkg inside MetricsManager to reduce the memory usage.
- initLogSourceWhiteList();
+ initAllowedLogSources();
}
for (const auto& it : mPullAtomPackages) {
@@ -329,7 +357,7 @@ void MetricsManager::onUidMapReceived(const int64_t& eventTimeNs) {
if (mAllowedPkg.size() == 0) {
return;
}
- initLogSourceWhiteList();
+ initAllowedLogSources();
}
void MetricsManager::onStatsdInitCompleted(const int64_t& eventTimeNs) {
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 27f3d51b07ce..3c9ecdb46fd2 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -172,7 +172,7 @@ private:
bool mVersionStringsInReport = false;
bool mInstallerInReport = false;
- const int64_t mTtlNs;
+ int64_t mTtlNs;
int64_t mTtlEndNs;
int64_t mLastReportTimeNs;
@@ -193,7 +193,7 @@ private:
// To guard access to mAllowedLogSources
mutable std::mutex mAllowedLogSourcesMutex;
- const std::set<int32_t> mWhitelistedAtomIds;
+ std::set<int32_t> mWhitelistedAtomIds;
// We can pull any atom from these uids.
std::set<int32_t> mDefaultPullUids;
@@ -211,8 +211,7 @@ private:
// Contains the annotations passed in with StatsdConfig.
std::list<std::pair<const int64_t, const int32_t>> mAnnotations;
- const bool mShouldPersistHistory;
-
+ bool mShouldPersistHistory;
// All event tags that are interesting to my metrics.
std::set<int> mTagIds;
@@ -285,10 +284,22 @@ private:
std::vector<int> mMetricIndexesWithActivation;
- void initLogSourceWhiteList();
+ void initAllowedLogSources();
void initPullAtomSources();
+ // Only called on config creation/update to initialize log sources from the config.
+ // Calls initAllowedLogSources and initPullAtomSources. Sets mConfigValid to false on error.
+ void createAllLogSourcesFromConfig(const StatsdConfig& config);
+
+ // Verifies the config meets guardrails and updates statsdStats.
+ // Sets mConfigValid to false on error. Should be called on config creation/update
+ void verifyGuardrailsAndUpdateStatsdStats();
+
+ // Initializes mIsAlwaysActive and mIsActive.
+ // Should be called on config creation/update.
+ void initializeConfigActiveStatus();
+
// The metrics that don't need to be uploaded or even reported.
std::set<int64_t> mNoReportMetricIds;
@@ -323,6 +334,7 @@ private:
FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
+ FRIEND_TEST(ConfigUpdateE2eTest, TestConfigTtl);
FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation);
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations);
@@ -330,6 +342,7 @@ private:
FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations);
FRIEND_TEST(MetricsManagerTest, TestLogSources);
+ FRIEND_TEST(MetricsManagerTest, TestLogSourcesOnConfigUpdate);
FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
index 637236145bf5..39789cd86bb1 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
@@ -396,6 +396,23 @@ bool updateConditions(const ConfigKey& key, const StatsdConfig& config,
return true;
}
+bool updateStates(const StatsdConfig& config, const map<int64_t, uint64_t>& oldStateProtoHashes,
+ unordered_map<int64_t, int>& stateAtomIdMap,
+ unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
+ map<int64_t, uint64_t>& newStateProtoHashes, set<int64_t>& replacedStates) {
+ // Share with metrics_manager_util.
+ if (!initStates(config, stateAtomIdMap, allStateGroupMaps, newStateProtoHashes)) {
+ return false;
+ }
+
+ for (const auto& [stateId, stateHash] : oldStateProtoHashes) {
+ const auto& it = newStateProtoHashes.find(stateId);
+ if (it != newStateProtoHashes.end() && it->second != stateHash) {
+ replacedStates.insert(stateId);
+ }
+ }
+ return true;
+}
// Returns true if any matchers in the metric activation were replaced.
bool metricActivationDepsChange(const StatsdConfig& config,
const unordered_map<int64_t, int>& metricToActivationMap,
@@ -869,6 +886,14 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64
newMetricProducers.push_back(producer.value());
}
+ for (int i = 0; i < config.no_report_metric_size(); ++i) {
+ const int64_t noReportMetric = config.no_report_metric(i);
+ if (newMetricProducerMap.find(noReportMetric) == newMetricProducerMap.end()) {
+ ALOGW("no_report_metric %" PRId64 " not exist", noReportMetric);
+ return false;
+ }
+ noReportMetricIds.insert(noReportMetric);
+ }
const set<int> atomsAllowedFromAnyUid(config.whitelisted_atom_ids().begin(),
config.whitelisted_atom_ids().end());
for (int i = 0; i < allMetricsCount; i++) {
@@ -887,6 +912,12 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64
}
}
+ // Init new/replaced metrics.
+ for (size_t i = 0; i < newMetricProducers.size(); i++) {
+ if (metricsToUpdate[i] == UPDATE_REPLACE || metricsToUpdate[i] == UPDATE_NEW) {
+ newMetricProducers[i]->prepareFirstBucket();
+ }
+ }
return true;
}
@@ -1028,6 +1059,7 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const
set<int64_t>& noReportMetricIds) {
set<int64_t> replacedMatchers;
set<int64_t> replacedConditions;
+ set<int64_t> replacedStates;
set<int64_t> replacedMetrics;
vector<ConditionState> conditionCache;
unordered_map<int64_t, int> stateAtomIdMap;
@@ -1039,7 +1071,6 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const
ALOGE("updateAtomMatchingTrackers failed");
return false;
}
- VLOG("updateAtomMatchingTrackers succeeded");
if (!updateConditions(key, config, newAtomMatchingTrackerMap, replacedMatchers,
oldConditionTrackerMap, oldConditionTrackers, newConditionTrackerMap,
@@ -1048,21 +1079,12 @@ bool updateStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const
ALOGE("updateConditions failed");
return false;
}
- VLOG("updateConditions succeeded");
- // Share with metrics_manager_util,
- if (!initStates(config, stateAtomIdMap, allStateGroupMaps, newStateProtoHashes)) {
- ALOGE("initStates failed");
+ if (!updateStates(config, oldStateProtoHashes, stateAtomIdMap, allStateGroupMaps,
+ newStateProtoHashes, replacedStates)) {
+ ALOGE("updateStates failed");
return false;
}
-
- set<int64_t> replacedStates;
- for (const auto& [stateId, stateHash] : oldStateProtoHashes) {
- const auto& it = newStateProtoHashes.find(stateId);
- if (it != newStateProtoHashes.end() && it->second != stateHash) {
- replacedStates.insert(stateId);
- }
- }
if (!updateMetrics(key, config, timeBaseNs, currentTimeNs, pullerManager,
oldAtomMatchingTrackerMap, newAtomMatchingTrackerMap, replacedMatchers,
newAtomMatchingTrackers, newConditionTrackerMap, replacedConditions,
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
index 178a9d220b4d..8e2be6899699 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
@@ -126,6 +126,13 @@ bool updateConditions(const ConfigKey& key, const StatsdConfig& config,
std::vector<ConditionState>& conditionCache,
std::set<int64_t>& replacedConditions);
+bool updateStates(const StatsdConfig& config,
+ const std::map<int64_t, uint64_t>& oldStateProtoHashes,
+ std::unordered_map<int64_t, int>& stateAtomIdMap,
+ std::unordered_map<int64_t, std::unordered_map<int, int64_t>>& allStateGroupMaps,
+ std::map<int64_t, uint64_t>& newStateProtoHashes,
+ std::set<int64_t>& replacedStates);
+
// Function to determine the update status (preserve/replace/new) of all metrics in the config.
// [config]: the input StatsdConfig
// [oldMetricProducerMap]: metric id to index mapping in the existing MetricsManager
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index 9455304a1af6..1d8371638e90 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -44,8 +44,8 @@ static ostream& operator<<(ostream& os, const StatsdConfig& config) {
*/
class MockListener : public ConfigListener {
public:
- MOCK_METHOD3(OnConfigUpdated, void(const int64_t timestampNs, const ConfigKey& key,
- const StatsdConfig& config));
+ MOCK_METHOD4(OnConfigUpdated, void(const int64_t timestampNs, const ConfigKey& key,
+ const StatsdConfig& config, bool modularUpdate));
MOCK_METHOD1(OnConfigRemoved, void(const ConfigKey& key));
};
@@ -89,26 +89,26 @@ TEST(ConfigManagerTest, TestAddUpdateRemove) {
manager->StartupForTest();
// Add another one
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")),
- StatsdConfigEq(91)))
+ EXPECT_CALL(*(listener.get()),
+ OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), StatsdConfigEq(91), _))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config91);
// Update It
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")),
- StatsdConfigEq(92)))
+ EXPECT_CALL(*(listener.get()),
+ OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), StatsdConfigEq(92), _))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config92);
// Add one with the same uid but a different name
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("yyy")),
- StatsdConfigEq(93)))
+ EXPECT_CALL(*(listener.get()),
+ OnConfigUpdated(_, ConfigKeyEq(1, StringToId("yyy")), StatsdConfigEq(93), _))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("yyy")), config93);
// Add one with the same name but a different uid
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(2, StringToId("zzz")),
- StatsdConfigEq(94)))
+ EXPECT_CALL(*(listener.get()),
+ OnConfigUpdated(_, ConfigKeyEq(2, StringToId("zzz")), StatsdConfigEq(94), _))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(2, StringToId("zzz")), config94);
@@ -143,7 +143,7 @@ TEST(ConfigManagerTest, TestRemoveUid) {
StatsdConfig config;
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _, _)).Times(5);
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _, _, _)).Times(5);
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("xxx"))));
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("yyy"))));
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("zzz"))));
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 2dd774e7dfc9..f05ec490dcee 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
#include <stdio.h>
@@ -92,8 +93,12 @@ StatsdConfig buildGoodConfig() {
return config;
}
-bool isSubset(const set<int32_t>& set1, const set<int32_t>& set2) {
- return std::includes(set2.begin(), set2.end(), set1.begin(), set1.end());
+set<int32_t> unionSet(const vector<set<int32_t>> sets) {
+ set<int32_t> toRet;
+ for (const set<int32_t>& s : sets) {
+ toRet.insert(s.begin(), s.end());
+ }
+ return toRet;
}
} // anonymous namespace
@@ -110,9 +115,7 @@ TEST(MetricsManagerTest, TestLogSources) {
pkgToUids[app2] = app2Uids;
pkgToUids[app3] = app3Uids;
- int32_t atom1 = 10;
- int32_t atom2 = 20;
- int32_t atom3 = 30;
+ int32_t atom1 = 10, atom2 = 20, atom3 = 30;
sp<MockUidMap> uidMap = new StrictMock<MockUidMap>();
EXPECT_CALL(*uidMap, getAppUid(_))
.Times(4)
@@ -150,42 +153,115 @@ TEST(MetricsManagerTest, TestLogSources) {
MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
+ EXPECT_TRUE(metricsManager.isConfigValid());
+
+ EXPECT_THAT(metricsManager.mAllowedUid, ElementsAre(AID_SYSTEM));
+ EXPECT_THAT(metricsManager.mAllowedPkg, ElementsAre(app1));
+ EXPECT_THAT(metricsManager.mAllowedLogSources,
+ ContainerEq(unionSet(vector<set<int32_t>>({app1Uids, {AID_SYSTEM}}))));
+ EXPECT_THAT(metricsManager.mDefaultPullUids, ContainerEq(defaultPullUids));
+
+ vector<int32_t> atom1Uids = metricsManager.getPullAtomUids(atom1);
+ EXPECT_THAT(atom1Uids,
+ UnorderedElementsAreArray(unionSet({defaultPullUids, app1Uids, app3Uids})));
+
+ vector<int32_t> atom2Uids = metricsManager.getPullAtomUids(atom2);
+ EXPECT_THAT(atom2Uids,
+ UnorderedElementsAreArray(unionSet({defaultPullUids, app2Uids, {AID_STATSD}})));
+
+ vector<int32_t> atom3Uids = metricsManager.getPullAtomUids(atom3);
+ EXPECT_THAT(atom3Uids, UnorderedElementsAreArray(defaultPullUids));
+}
+
+TEST(MetricsManagerTest, TestLogSourcesOnConfigUpdate) {
+ string app1 = "app1";
+ set<int32_t> app1Uids = {1111, 11111};
+ string app2 = "app2";
+ set<int32_t> app2Uids = {2222};
+ string app3 = "app3";
+ set<int32_t> app3Uids = {3333, 1111};
+ map<string, set<int32_t>> pkgToUids;
+ pkgToUids[app1] = app1Uids;
+ pkgToUids[app2] = app2Uids;
+ pkgToUids[app3] = app3Uids;
+
+ int32_t atom1 = 10, atom2 = 20, atom3 = 30;
+ sp<MockUidMap> uidMap = new StrictMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getAppUid(_))
+ .Times(8)
+ .WillRepeatedly(Invoke([&pkgToUids](const string& pkg) {
+ const auto& it = pkgToUids.find(pkg);
+ if (it != pkgToUids.end()) {
+ return it->second;
+ }
+ return set<int32_t>();
+ }));
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterPullUidProvider(kConfigKey, _)).Times(1);
+ EXPECT_CALL(*pullerManager, UnregisterPullUidProvider(kConfigKey, _)).Times(1);
+
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_SYSTEM");
+ config.add_allowed_log_source(app1);
+ config.add_default_pull_packages("AID_SYSTEM");
+ config.add_default_pull_packages("AID_ROOT");
+
+ PullAtomPackages* pullAtomPackages = config.add_pull_atom_packages();
+ pullAtomPackages->set_atom_id(atom1);
+ pullAtomPackages->add_packages(app1);
+ pullAtomPackages->add_packages(app3);
+
+ pullAtomPackages = config.add_pull_atom_packages();
+ pullAtomPackages->set_atom_id(atom2);
+ pullAtomPackages->add_packages(app2);
+ pullAtomPackages->add_packages("AID_STATSD");
+
+ MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap,
+ pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor);
EXPECT_TRUE(metricsManager.isConfigValid());
- ASSERT_EQ(metricsManager.mAllowedUid.size(), 1);
- EXPECT_EQ(metricsManager.mAllowedUid[0], AID_SYSTEM);
+ // Update with new allowed log sources.
+ StatsdConfig newConfig;
+ newConfig.add_allowed_log_source("AID_ROOT");
+ newConfig.add_allowed_log_source(app2);
+ newConfig.add_default_pull_packages("AID_SYSTEM");
+ newConfig.add_default_pull_packages("AID_STATSD");
- ASSERT_EQ(metricsManager.mAllowedPkg.size(), 1);
- EXPECT_EQ(metricsManager.mAllowedPkg[0], app1);
+ pullAtomPackages = newConfig.add_pull_atom_packages();
+ pullAtomPackages->set_atom_id(atom2);
+ pullAtomPackages->add_packages(app1);
+ pullAtomPackages->add_packages(app3);
- ASSERT_EQ(metricsManager.mAllowedLogSources.size(), 3);
- EXPECT_TRUE(isSubset({AID_SYSTEM}, metricsManager.mAllowedLogSources));
- EXPECT_TRUE(isSubset(app1Uids, metricsManager.mAllowedLogSources));
+ pullAtomPackages = newConfig.add_pull_atom_packages();
+ pullAtomPackages->set_atom_id(atom3);
+ pullAtomPackages->add_packages(app2);
+ pullAtomPackages->add_packages("AID_ADB");
+
+ metricsManager.updateConfig(newConfig, timeBaseSec, timeBaseSec, anomalyAlarmMonitor,
+ periodicAlarmMonitor);
+ EXPECT_TRUE(metricsManager.isConfigValid());
- ASSERT_EQ(metricsManager.mDefaultPullUids.size(), 2);
- EXPECT_TRUE(isSubset(defaultPullUids, metricsManager.mDefaultPullUids));
- ;
+ EXPECT_THAT(metricsManager.mAllowedUid, ElementsAre(AID_ROOT));
+ EXPECT_THAT(metricsManager.mAllowedPkg, ElementsAre(app2));
+ EXPECT_THAT(metricsManager.mAllowedLogSources,
+ ContainerEq(unionSet(vector<set<int32_t>>({app2Uids, {AID_ROOT}}))));
+ const set<int32_t> defaultPullUids = {AID_SYSTEM, AID_STATSD};
+ EXPECT_THAT(metricsManager.mDefaultPullUids, ContainerEq(defaultPullUids));
vector<int32_t> atom1Uids = metricsManager.getPullAtomUids(atom1);
- ASSERT_EQ(atom1Uids.size(), 5);
- set<int32_t> expectedAtom1Uids;
- expectedAtom1Uids.insert(defaultPullUids.begin(), defaultPullUids.end());
- expectedAtom1Uids.insert(app1Uids.begin(), app1Uids.end());
- expectedAtom1Uids.insert(app3Uids.begin(), app3Uids.end());
- EXPECT_TRUE(isSubset(expectedAtom1Uids, set<int32_t>(atom1Uids.begin(), atom1Uids.end())));
+ EXPECT_THAT(atom1Uids, UnorderedElementsAreArray(defaultPullUids));
vector<int32_t> atom2Uids = metricsManager.getPullAtomUids(atom2);
- ASSERT_EQ(atom2Uids.size(), 4);
- set<int32_t> expectedAtom2Uids;
- expectedAtom1Uids.insert(defaultPullUids.begin(), defaultPullUids.end());
- expectedAtom1Uids.insert(app2Uids.begin(), app2Uids.end());
- expectedAtom1Uids.insert(AID_STATSD);
- EXPECT_TRUE(isSubset(expectedAtom2Uids, set<int32_t>(atom2Uids.begin(), atom2Uids.end())));
+ EXPECT_THAT(atom2Uids,
+ UnorderedElementsAreArray(unionSet({defaultPullUids, app1Uids, app3Uids})));
vector<int32_t> atom3Uids = metricsManager.getPullAtomUids(atom3);
- ASSERT_EQ(atom3Uids.size(), 2);
- EXPECT_TRUE(isSubset(defaultPullUids, set<int32_t>(atom3Uids.begin(), atom3Uids.end())));
+ EXPECT_THAT(atom3Uids,
+ UnorderedElementsAreArray(unionSet({defaultPullUids, app2Uids, {AID_ADB}})));
}
TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom) {
diff --git a/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp
new file mode 100644
index 000000000000..e01a0b63a0ca
--- /dev/null
+++ b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp
@@ -0,0 +1,307 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+#include <thread> // std::this_thread::sleep_for
+
+#include "android-base/stringprintf.h"
+#include "src/StatsLogProcessor.h"
+#include "src/storage/StorageManager.h"
+#include "tests/statsd_test_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+#define STATS_DATA_DIR "/data/misc/stats-data"
+using android::base::StringPrintf;
+
+namespace {
+
+StatsdConfig CreateSimpleConfig() {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_STATSD");
+ config.set_hash_strings_in_metric_report(false);
+
+ *config.add_atom_matcher() = CreateBatteryStateUsbMatcher();
+ // Simple count metric so the config isn't empty.
+ CountMetric* countMetric1 = config.add_count_metric();
+ countMetric1->set_id(StringToId("Count1"));
+ countMetric1->set_what(config.atom_matcher(0).id());
+ countMetric1->set_bucket(FIVE_MINUTES);
+ return config;
+}
+} // namespace
+
+// Setup for parameterized tests.
+class ConfigUpdateE2eTest : public TestWithParam<bool> {};
+
+INSTANTIATE_TEST_SUITE_P(ConfigUpdateE2eTest, ConfigUpdateE2eTest, testing::Bool());
+
+TEST_P(ConfigUpdateE2eTest, TestUidMapVersionStringInstaller) {
+ sp<UidMap> uidMap = new UidMap();
+ vector<int32_t> uids({1000});
+ vector<int64_t> versions({1});
+ vector<String16> apps({String16("app1")});
+ vector<String16> versionStrings({String16("v1")});
+ vector<String16> installers({String16("installer1")});
+ uidMap->updateMap(1, uids, versions, versionStrings, apps, installers);
+
+ StatsdConfig config = CreateSimpleConfig();
+ config.set_version_strings_in_metric_report(true);
+ config.set_installer_in_metric_report(false);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+
+ // Now update.
+ config.set_version_strings_in_metric_report(false);
+ config.set_installer_in_metric_report(true);
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
+ EXPECT_TRUE(metricsManager->isConfigValid());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ // First report is written to disk when the update happens.
+ ASSERT_EQ(reports.reports_size(), 2);
+ UidMapping uidMapping = reports.reports(1).uid_map();
+ ASSERT_EQ(uidMapping.snapshots_size(), 1);
+ ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
+ EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string());
+ EXPECT_EQ(uidMapping.snapshots(0).package_info(0).installer(), "installer1");
+}
+
+TEST_P(ConfigUpdateE2eTest, TestHashStrings) {
+ sp<UidMap> uidMap = new UidMap();
+ vector<int32_t> uids({1000});
+ vector<int64_t> versions({1});
+ vector<String16> apps({String16("app1")});
+ vector<String16> versionStrings({String16("v1")});
+ vector<String16> installers({String16("installer1")});
+ uidMap->updateMap(1, uids, versions, versionStrings, apps, installers);
+
+ StatsdConfig config = CreateSimpleConfig();
+ config.set_version_strings_in_metric_report(true);
+ config.set_hash_strings_in_metric_report(true);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+
+ // Now update.
+ config.set_hash_strings_in_metric_report(false);
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
+ EXPECT_TRUE(metricsManager->isConfigValid());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ // First report is written to disk when the update happens.
+ ASSERT_EQ(reports.reports_size(), 2);
+ UidMapping uidMapping = reports.reports(1).uid_map();
+ ASSERT_EQ(uidMapping.snapshots_size(), 1);
+ ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
+ EXPECT_TRUE(uidMapping.snapshots(0).package_info(0).has_version_string());
+ EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string_hash());
+}
+
+TEST_P(ConfigUpdateE2eTest, TestAnnotations) {
+ StatsdConfig config = CreateSimpleConfig();
+ StatsdConfig_Annotation* annotation = config.add_annotation();
+ annotation->set_field_int64(11);
+ annotation->set_field_int32(1);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
+
+ // Now update
+ config.clear_annotation();
+ annotation = config.add_annotation();
+ annotation->set_field_int64(22);
+ annotation->set_field_int32(2);
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ // First report is written to disk when the update happens.
+ ASSERT_EQ(reports.reports_size(), 2);
+ ConfigMetricsReport report = reports.reports(1);
+ EXPECT_EQ(report.annotation_size(), 1);
+ EXPECT_EQ(report.annotation(0).field_int64(), 22);
+ EXPECT_EQ(report.annotation(0).field_int32(), 2);
+}
+
+TEST_P(ConfigUpdateE2eTest, TestPersistLocally) {
+ StatsdConfig config = CreateSimpleConfig();
+ config.set_persist_locally(false);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 1);
+ // Number of reports should still be 1 since persist_locally is false.
+ reports.Clear();
+ buffer.clear();
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 1);
+
+ // Now update.
+ config.set_persist_locally(true);
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
+
+ // Should get 2: 1 in memory + 1 on disk. Both should be saved on disk.
+ reports.Clear();
+ buffer.clear();
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 2);
+ // Should get 3, 2 on disk + 1 in memory.
+ reports.Clear();
+ buffer.clear();
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 3);
+ string suffix = StringPrintf("%d_%lld", cfgKey.GetUid(), (long long)cfgKey.GetId());
+ StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, suffix.c_str());
+ string historySuffix =
+ StringPrintf("%d_%lld_history", cfgKey.GetUid(), (long long)cfgKey.GetId());
+ StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, historySuffix.c_str());
+}
+
+TEST_P(ConfigUpdateE2eTest, TestNoReportMetrics) {
+ StatsdConfig config = CreateSimpleConfig();
+ // Second simple count metric.
+ CountMetric* countMetric = config.add_count_metric();
+ countMetric->set_id(StringToId("Count2"));
+ countMetric->set_what(config.atom_matcher(0).id());
+ countMetric->set_bucket(FIVE_MINUTES);
+ config.add_no_report_metric(config.count_metric(0).id());
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
+
+ // Now update.
+ config.clear_no_report_metric();
+ config.add_no_report_metric(config.count_metric(1).id());
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ // First report is written to disk when the update happens.
+ ASSERT_EQ(reports.reports_size(), 2);
+ // First report (before update) has the first count metric.
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).metric_id(), config.count_metric(1).id());
+ // Second report (after update) has the first count metric.
+ ASSERT_EQ(reports.reports(1).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(1).metrics(0).metric_id(), config.count_metric(0).id());
+}
+
+TEST_P(ConfigUpdateE2eTest, TestAtomsAllowedFromAnyUid) {
+ StatsdConfig config = CreateSimpleConfig();
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
+ // Uses AID_ROOT, which isn't in allowed log sources.
+ unique_ptr<LogEvent> event = CreateBatteryStateChangedEvent(
+ baseTimeNs + 2, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
+ processor->OnLogEvent(event.get());
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 1001, true, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 1);
+ // Check the metric and make sure it has 0 count.
+ ASSERT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_FALSE(reports.reports(0).metrics(0).has_count_metrics());
+
+ // Now update. Allow plugged state to be logged from any uid, so the atom will be counted.
+ config.add_whitelisted_atom_ids(util::PLUGGED_STATE_CHANGED);
+ processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam());
+ unique_ptr<LogEvent> event2 = CreateBatteryStateChangedEvent(
+ baseTimeNs + 2000, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
+ processor->OnLogEvent(event.get());
+ reports.Clear();
+ buffer.clear();
+ processor->onDumpReport(cfgKey, baseTimeNs + 3000, true, true, ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ ASSERT_EQ(reports.reports_size(), 2);
+ // Check the metric and make sure it has 0 count.
+ ASSERT_EQ(reports.reports(1).metrics_size(), 1);
+ EXPECT_TRUE(reports.reports(1).metrics(0).has_count_metrics());
+ ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data_size(), 1);
+ ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
+ EXPECT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
+}
+
+TEST_P(ConfigUpdateE2eTest, TestConfigTtl) {
+ StatsdConfig config = CreateSimpleConfig();
+ config.set_ttl_in_seconds(1);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ ConfigKey cfgKey(0, 12345);
+ sp<StatsLogProcessor> processor =
+ CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + NS_PER_SEC);
+
+ config.set_ttl_in_seconds(5);
+ processor->OnConfigUpdated(baseTimeNs + 2 * NS_PER_SEC, cfgKey, config,
+ /*modularUpdate=*/GetParam());
+ metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + 7 * NS_PER_SEC);
+
+ // Clear the data stored on disk as a result of the update.
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, baseTimeNs + 3 * NS_PER_SEC, false, true, ADB_DUMP, FAST,
+ &buffer);
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
index 66bab4ea70da..d78c14c6ed82 100644
--- a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
+++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
@@ -997,6 +997,57 @@ TEST_F(ConfigUpdateTest, TestUpdateConditions) {
EXPECT_THAT(combinationTracker1->mSlicedChildren, IsEmpty());
}
+TEST_F(ConfigUpdateTest, TestUpdateStates) {
+ StatsdConfig config;
+ // Add states.
+ // Will be replaced because we add a state map.
+ State state1 = CreateScreenState();
+ int64_t state1Id = state1.id();
+ *config.add_state() = state1;
+
+ // Will be preserved.
+ State state2 = CreateUidProcessState();
+ int64_t state2Id = state2.id();
+ *config.add_state() = state2;
+
+ // Will be replaced since the atom changes from overlay to screen.
+ State state3 = CreateOverlayState();
+ int64_t state3Id = state3.id();
+ *config.add_state() = state3;
+
+ EXPECT_TRUE(initConfig(config));
+
+ // Change definitions of state1 and state3.
+ int64_t screenOnId = 0x4321, screenOffId = 0x1234;
+ *state1.mutable_map() = CreateScreenStateSimpleOnOffMap(screenOnId, screenOffId);
+ state3.set_atom_id(util::SCREEN_STATE_CHANGED);
+
+ StatsdConfig newConfig;
+ *newConfig.add_state() = state3;
+ *newConfig.add_state() = state1;
+ *newConfig.add_state() = state2;
+
+ unordered_map<int64_t, int> stateAtomIdMap;
+ unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
+ map<int64_t, uint64_t> newStateProtoHashes;
+ set<int64_t> replacedStates;
+ EXPECT_TRUE(updateStates(newConfig, oldStateHashes, stateAtomIdMap, allStateGroupMaps,
+ newStateProtoHashes, replacedStates));
+ EXPECT_THAT(replacedStates, ContainerEq(set({state1Id, state3Id})));
+
+ unordered_map<int64_t, int> expectedStateAtomIdMap = {
+ {state1Id, util::SCREEN_STATE_CHANGED},
+ {state2Id, util::UID_PROCESS_STATE_CHANGED},
+ {state3Id, util::SCREEN_STATE_CHANGED}};
+ EXPECT_THAT(stateAtomIdMap, ContainerEq(expectedStateAtomIdMap));
+
+ unordered_map<int64_t, unordered_map<int, int64_t>> expectedStateGroupMaps = {
+ {state1Id,
+ {{android::view::DisplayStateEnum::DISPLAY_STATE_OFF, screenOffId},
+ {android::view::DisplayStateEnum::DISPLAY_STATE_ON, screenOnId}}}};
+ EXPECT_THAT(allStateGroupMaps, ContainerEq(expectedStateGroupMaps));
+}
+
TEST_F(ConfigUpdateTest, TestEventMetricPreserve) {
StatsdConfig config;
AtomMatcher startMatcher = CreateScreenTurnedOnAtomMatcher();
diff --git a/config/hiddenapi-temp-blocklist.txt b/config/hiddenapi-temp-blocklist.txt
new file mode 100644
index 000000000000..246eeea35a19
--- /dev/null
+++ b/config/hiddenapi-temp-blocklist.txt
@@ -0,0 +1,55 @@
+Landroid/app/IActivityManager$Stub$Proxy;->setActivityController(Landroid/app/IActivityController;Z)V
+Landroid/app/IActivityManager$Stub$Proxy;->updatePersistentConfiguration(Landroid/content/res/Configuration;)V
+Landroid/app/IActivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
+Landroid/app/IInstrumentationWatcher$Stub;-><init>()V
+Landroid/app/INotificationManager$Stub;->TRANSACTION_enqueueNotificationWithTag:I
+Landroid/bluetooth/IBluetooth$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
+Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_enable:I
+Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_enable:I
+Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V
+Landroid/content/om/IOverlayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/om/IOverlayManager;
+Landroid/content/pm/IPackageManager$Stub;->TRANSACTION_getApplicationInfo:I
+Landroid/hardware/ICameraService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/ICameraService;
+Landroid/hardware/input/IInputManager$Stub;->TRANSACTION_injectInputEvent:I
+Landroid/hardware/location/IActivityRecognitionHardwareClient$Stub;-><init>()V
+Landroid/hardware/usb/IUsbManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/usb/IUsbManager;
+Landroid/location/ICountryDetector$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ICountryDetector;
+Landroid/location/IGeofenceProvider$Stub;-><init>()V
+Landroid/location/ILocationManager$Stub;->TRANSACTION_getAllProviders:I
+Landroid/Manifest$permission;->CAPTURE_SECURE_VIDEO_OUTPUT:Ljava/lang/String;
+Landroid/Manifest$permission;->CAPTURE_VIDEO_OUTPUT:Ljava/lang/String;
+Landroid/Manifest$permission;->READ_FRAME_BUFFER:Ljava/lang/String;
+Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController;
+Landroid/net/INetworkPolicyListener$Stub;-><init>()V
+Landroid/net/nsd/INsdManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/nsd/INsdManager;
+Landroid/net/sip/ISipSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/sip/ISipSession;
+Landroid/net/wifi/IWifiManager$Stub;->TRANSACTION_getScanResults:I
+Landroid/net/wifi/p2p/IWifiP2pManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/wifi/p2p/IWifiP2pManager;
+Landroid/nfc/INfcAdapter$Stub;->TRANSACTION_enable:I
+Landroid/os/IPowerManager$Stub;->TRANSACTION_acquireWakeLock:I
+Landroid/os/IPowerManager$Stub;->TRANSACTION_goToSleep:I
+Landroid/service/euicc/IEuiccService$Stub;-><init>()V
+Landroid/service/media/IMediaBrowserServiceCallbacks$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/media/IMediaBrowserServiceCallbacks;
+Landroid/telephony/mbms/IMbmsStreamingSessionCallback$Stub;-><init>()V
+Landroid/telephony/mbms/IStreamingServiceCallback$Stub;-><init>()V
+Landroid/telephony/mbms/vendor/IMbmsStreamingService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/telephony/mbms/vendor/IMbmsStreamingService;
+Lcom/android/ims/ImsConfigListener$Stub;-><init>()V
+Lcom/android/ims/internal/IImsCallSession$Stub;-><init>()V
+Lcom/android/ims/internal/IImsConfig$Stub;-><init>()V
+Lcom/android/ims/internal/IImsEcbm$Stub;-><init>()V
+Lcom/android/ims/internal/IImsService$Stub;-><init>()V
+Lcom/android/ims/internal/IImsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/ims/internal/IImsService;
+Lcom/android/ims/internal/IImsUt$Stub;-><init>()V
+Lcom/android/ims/internal/IImsVideoCallProvider$Stub;-><init>()V
+Lcom/android/ims/internal/uce/options/IOptionsService$Stub;-><init>()V
+Lcom/android/ims/internal/uce/presence/IPresenceService$Stub;-><init>()V
+Lcom/android/ims/internal/uce/uceservice/IUceListener$Stub;-><init>()V
+Lcom/android/ims/internal/uce/uceservice/IUceService$Stub;-><init>()V
+Lcom/android/internal/app/IVoiceInteractionManagerService$Stub$Proxy;->showSessionFromSession(Landroid/os/IBinder;Landroid/os/Bundle;I)Z
+Lcom/android/internal/appwidget/IAppWidgetService$Stub;->TRANSACTION_bindAppWidgetId:I
+Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
+Lcom/android/internal/location/ILocationProviderManager$Stub;-><init>()V
+Lcom/android/internal/location/ILocationProviderManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProviderManager;
+Lcom/android/internal/telephony/ITelephony$Stub;->DESCRIPTOR:Ljava/lang/String;
+Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_dial:I
+Lcom/android/internal/widget/IRemoteViewsFactory$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/widget/IRemoteViewsFactory;
diff --git a/config/hiddenapi-unsupported.txt b/config/hiddenapi-unsupported.txt
index a3543dc7f4ee..8a377ac051b0 100644
--- a/config/hiddenapi-unsupported.txt
+++ b/config/hiddenapi-unsupported.txt
@@ -26,19 +26,14 @@ Landroid/app/IActivityManager$Stub$Proxy;->getLaunchedFromUid(Landroid/os/IBinde
Landroid/app/IActivityManager$Stub$Proxy;->getProcessLimit()I
Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J
Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/app/IActivityManager$Stub$Proxy;->setActivityController(Landroid/app/IActivityController;Z)V
-Landroid/app/IActivityManager$Stub$Proxy;->updatePersistentConfiguration(Landroid/content/res/Configuration;)V
-Landroid/app/IActivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
Landroid/app/IAlarmManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/IAlarmManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IAlarmManager;
Landroid/app/IAlarmManager$Stub;->TRANSACTION_remove:I
Landroid/app/IAlarmManager$Stub;->TRANSACTION_set:I
Landroid/app/IAssistDataReceiver$Stub;-><init>()V
-Landroid/app/IInstrumentationWatcher$Stub;-><init>()V
Landroid/app/INotificationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/INotificationManager$Stub$Proxy;->areNotificationsEnabledForPackage(Ljava/lang/String;I)Z
Landroid/app/INotificationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/INotificationManager;
-Landroid/app/INotificationManager$Stub;->TRANSACTION_enqueueNotificationWithTag:I
Landroid/app/IProcessObserver$Stub;-><init>()V
Landroid/app/ISearchManager$Stub$Proxy;->getGlobalSearchActivity()Landroid/content/ComponentName;
Landroid/app/ISearchManager$Stub$Proxy;->getWebSearchActivity()Landroid/content/ComponentName;
@@ -68,9 +63,7 @@ Landroid/app/job/IJobService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/ap
Landroid/app/trust/ITrustManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/usage/IUsageStatsManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/usage/IUsageStatsManager;
Landroid/bluetooth/IBluetooth$Stub$Proxy;->getAddress()Ljava/lang/String;
-Landroid/bluetooth/IBluetooth$Stub$Proxy;->getConnectionState(Landroid/bluetooth/BluetoothDevice;)I
Landroid/bluetooth/IBluetooth$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetooth;
-Landroid/bluetooth/IBluetooth$Stub;->TRANSACTION_enable:I
Landroid/bluetooth/IBluetoothA2dp$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothA2dp;
Landroid/bluetooth/IBluetoothCallback$Stub;-><init>()V
Landroid/bluetooth/IBluetoothGattCallback$Stub;-><init>()V
@@ -79,11 +72,9 @@ Landroid/bluetooth/IBluetoothHeadset$Stub;->asInterface(Landroid/os/IBinder;)Lan
Landroid/bluetooth/IBluetoothHidDeviceCallback$Stub;-><init>()V
Landroid/bluetooth/IBluetoothManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/bluetooth/IBluetoothManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothManager;
-Landroid/bluetooth/IBluetoothManager$Stub;->TRANSACTION_enable:I
Landroid/bluetooth/IBluetoothManagerCallback$Stub;-><init>()V
Landroid/bluetooth/IBluetoothPbap$Stub;->asInterface(Landroid/os/IBinder;)Landroid/bluetooth/IBluetoothPbap;
Landroid/bluetooth/IBluetoothStateChangeCallback$Stub;-><init>()V
-Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V
Landroid/content/IClipboard$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -108,7 +99,6 @@ Landroid/content/ISyncStatusObserver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/ISyncStatusObserver$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Landroid/content/ISyncStatusObserver$Stub;-><init>()V
Landroid/content/ISyncStatusObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/ISyncStatusObserver;
-Landroid/content/om/IOverlayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/om/IOverlayManager;
Landroid/content/pm/IPackageDataObserver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/content/pm/IPackageDataObserver$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Landroid/content/pm/IPackageDataObserver$Stub;-><init>()V
@@ -141,7 +131,6 @@ Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackageInfo(Ljava/lang/Strin
Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String;
Landroid/content/pm/IPackageManager$Stub$Proxy;->getSystemSharedLibraryNames()[Ljava/lang/String;
Landroid/content/pm/IPackageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageManager;
-Landroid/content/pm/IPackageManager$Stub;->TRANSACTION_getApplicationInfo:I
Landroid/content/pm/IPackageMoveObserver$Stub;-><init>()V
Landroid/content/pm/IPackageMoveObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageMoveObserver;
Landroid/content/pm/IPackageStatsObserver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -155,30 +144,20 @@ Landroid/database/IContentObserver$Stub;->asInterface(Landroid/os/IBinder;)Landr
Landroid/hardware/display/IDisplayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/display/IDisplayManager;
Landroid/hardware/fingerprint/IFingerprintService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/hardware/fingerprint/IFingerprintService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/fingerprint/IFingerprintService;
-Landroid/hardware/ICameraService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/ICameraService;
Landroid/hardware/input/IInputManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/hardware/input/IInputManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/input/IInputManager;
-Landroid/hardware/input/IInputManager$Stub;->TRANSACTION_injectInputEvent:I
-Landroid/hardware/location/IActivityRecognitionHardwareClient$Stub;-><init>()V
Landroid/hardware/location/IContextHubService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/location/IContextHubService;
Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/hardware/usb/IUsbManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/usb/IUsbManager;
-Landroid/location/ICountryDetector$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ICountryDetector;
Landroid/location/ICountryListener$Stub;-><init>()V
Landroid/location/IGeocodeProvider$Stub;-><init>()V
Landroid/location/IGeocodeProvider$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/IGeocodeProvider;
-Landroid/location/IGeofenceProvider$Stub;-><init>()V
Landroid/location/ILocationListener$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/location/ILocationListener$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Landroid/location/ILocationListener$Stub;-><init>()V
Landroid/location/ILocationListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationListener;
Landroid/location/ILocationManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/location/ILocationManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ILocationManager;
-Landroid/location/ILocationManager$Stub;->TRANSACTION_getAllProviders:I
Landroid/location/INetInitiatedListener$Stub;-><init>()V
-Landroid/Manifest$permission;->CAPTURE_SECURE_VIDEO_OUTPUT:Ljava/lang/String;
-Landroid/Manifest$permission;->CAPTURE_VIDEO_OUTPUT:Ljava/lang/String;
-Landroid/Manifest$permission;->READ_FRAME_BUFFER:Ljava/lang/String;
Landroid/media/IAudioRoutesObserver$Stub;-><init>()V
Landroid/media/IAudioService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/media/IAudioService$Stub;-><init>()V
@@ -186,7 +165,6 @@ Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/me
Landroid/media/IMediaRouterService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IMediaRouterService;
Landroid/media/IMediaScannerListener$Stub;-><init>()V
Landroid/media/IMediaScannerService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IMediaScannerService;
-Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController;
Landroid/media/session/ISessionManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/session/ISessionManager;
Landroid/media/tv/ITvRemoteProvider$Stub;-><init>()V
Landroid/net/IConnectivityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -200,23 +178,17 @@ Landroid/net/IConnectivityManager$Stub$Proxy;->getTetheredIfaces()[Ljava/lang/St
Landroid/net/IConnectivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Landroid/net/IConnectivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IConnectivityManager;
Landroid/net/INetworkManagementEventObserver$Stub;-><init>()V
-Landroid/net/INetworkPolicyListener$Stub;-><init>()V
Landroid/net/INetworkPolicyManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkPolicyManager;
Landroid/net/INetworkScoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkScoreService;
Landroid/net/INetworkStatsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/INetworkStatsService$Stub$Proxy;->getMobileIfaces()[Ljava/lang/String;
Landroid/net/INetworkStatsService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/INetworkStatsService;
-Landroid/net/nsd/INsdManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/nsd/INsdManager;
-Landroid/net/sip/ISipSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/sip/ISipSession;
Landroid/net/wifi/IWifiManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/wifi/IWifiManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/wifi/IWifiManager;
-Landroid/net/wifi/IWifiManager$Stub;->TRANSACTION_getScanResults:I
Landroid/net/wifi/IWifiScanner$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/wifi/IWifiScanner$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Landroid/net/wifi/IWifiScanner$Stub;-><init>()V
Landroid/net/wifi/IWifiScanner$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/wifi/IWifiScanner;
-Landroid/net/wifi/p2p/IWifiP2pManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/wifi/p2p/IWifiP2pManager;
-Landroid/nfc/INfcAdapter$Stub;->TRANSACTION_enable:I
Landroid/os/IBatteryPropertiesRegistrar$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/IDeviceIdentifiersPolicyService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IDeviceIdentifiersPolicyService;
Landroid/os/IDeviceIdleController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IDeviceIdleController;
@@ -227,8 +199,6 @@ Landroid/os/IPermissionController$Stub;->asInterface(Landroid/os/IBinder;)Landro
Landroid/os/IPowerManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/IPowerManager$Stub$Proxy;->isLightDeviceIdleMode()Z
Landroid/os/IPowerManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IPowerManager;
-Landroid/os/IPowerManager$Stub;->TRANSACTION_acquireWakeLock:I
-Landroid/os/IPowerManager$Stub;->TRANSACTION_goToSleep:I
Landroid/os/IRecoverySystem$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IRecoverySystem;
Landroid/os/IRemoteCallback$Stub;-><init>()V
Landroid/os/IUpdateEngine$Stub;-><init>()V
@@ -241,16 +211,11 @@ Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Land
Landroid/security/IKeyChainService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeyChainService;
Landroid/security/keystore/IKeystoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/keystore/IKeystoreService;
Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager;
-Landroid/service/euicc/IEuiccService$Stub;-><init>()V
-Landroid/service/media/IMediaBrowserServiceCallbacks$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/media/IMediaBrowserServiceCallbacks;
Landroid/service/notification/INotificationListener$Stub;-><init>()V
Landroid/service/persistentdata/IPersistentDataBlockService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/persistentdata/IPersistentDataBlockService;
Landroid/service/vr/IVrManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/vr/IVrManager;
Landroid/service/wallpaper/IWallpaperConnection$Stub;-><init>()V
Landroid/service/wallpaper/IWallpaperService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/wallpaper/IWallpaperService;
-Landroid/telephony/mbms/IMbmsStreamingSessionCallback$Stub;-><init>()V
-Landroid/telephony/mbms/IStreamingServiceCallback$Stub;-><init>()V
-Landroid/telephony/mbms/vendor/IMbmsStreamingService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/telephony/mbms/vendor/IMbmsStreamingService;
Landroid/view/accessibility/IAccessibilityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/view/accessibility/IAccessibilityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/accessibility/IAccessibilityManager;
Landroid/view/autofill/IAutoFillManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -274,19 +239,7 @@ Landroid/view/IWindowSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/vi
Landroid/webkit/IWebViewUpdateService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/webkit/IWebViewUpdateService$Stub$Proxy;->waitForAndGetProvider()Landroid/webkit/WebViewProviderResponse;
Landroid/webkit/IWebViewUpdateService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/webkit/IWebViewUpdateService;
-Lcom/android/ims/ImsConfigListener$Stub;-><init>()V
-Lcom/android/ims/internal/IImsCallSession$Stub;-><init>()V
Lcom/android/ims/internal/IImsCallSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/ims/internal/IImsCallSession;
-Lcom/android/ims/internal/IImsConfig$Stub;-><init>()V
-Lcom/android/ims/internal/IImsEcbm$Stub;-><init>()V
-Lcom/android/ims/internal/IImsService$Stub;-><init>()V
-Lcom/android/ims/internal/IImsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/ims/internal/IImsService;
-Lcom/android/ims/internal/IImsUt$Stub;-><init>()V
-Lcom/android/ims/internal/IImsVideoCallProvider$Stub;-><init>()V
-Lcom/android/ims/internal/uce/options/IOptionsService$Stub;-><init>()V
-Lcom/android/ims/internal/uce/presence/IPresenceService$Stub;-><init>()V
-Lcom/android/ims/internal/uce/uceservice/IUceListener$Stub;-><init>()V
-Lcom/android/ims/internal/uce/uceservice/IUceService$Stub;-><init>()V
Lcom/android/internal/app/IAppOpsCallback$Stub;-><init>()V
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
@@ -313,15 +266,10 @@ Lcom/android/internal/app/IAppOpsService$Stub;->TRANSACTION_stopWatchingMode:I
Lcom/android/internal/app/IBatteryStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/app/IBatteryStats$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IBatteryStats;
Lcom/android/internal/app/IMediaContainerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IMediaContainerService;
-Lcom/android/internal/app/IVoiceInteractionManagerService$Stub$Proxy;->showSessionFromSession(Landroid/os/IBinder;Landroid/os/Bundle;I)Z
Lcom/android/internal/app/IVoiceInteractionManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IVoiceInteractionManagerService;
Lcom/android/internal/appwidget/IAppWidgetService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/appwidget/IAppWidgetService;
-Lcom/android/internal/appwidget/IAppWidgetService$Stub;->TRANSACTION_bindAppWidgetId:I
Lcom/android/internal/backup/IBackupTransport$Stub;-><init>()V
-Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
Lcom/android/internal/location/ILocationProvider$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProvider;
-Lcom/android/internal/location/ILocationProviderManager$Stub;-><init>()V
-Lcom/android/internal/location/ILocationProviderManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProviderManager;
Lcom/android/internal/os/IDropBoxManagerService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/os/IDropBoxManagerService;
Lcom/android/internal/policy/IKeyguardService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardService;
Lcom/android/internal/policy/IKeyguardStateCallback$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/policy/IKeyguardStateCallback;
@@ -343,9 +291,7 @@ Lcom/android/internal/telephony/ISub$Stub;->asInterface(Landroid/os/IBinder;)Lco
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->mRemote:Landroid/os/IBinder;
Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony;
-Lcom/android/internal/telephony/ITelephony$Stub;->DESCRIPTOR:Ljava/lang/String;
Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_call:I
-Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_dial:I
Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I
Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Lcom/android/internal/telephony/ITelephonyRegistry$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephonyRegistry;
@@ -355,4 +301,3 @@ Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;-><init>(Landroid/os/I
Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager;
Lcom/android/internal/view/IInputMethodSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodSession;
Lcom/android/internal/widget/ILockSettings$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/widget/ILockSettings;
-Lcom/android/internal/widget/IRemoteViewsFactory$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/widget/IRemoteViewsFactory;
diff --git a/core/api/current.txt b/core/api/current.txt
index 05b57af1dccd..d2a97f5ec1f8 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -31,6 +31,7 @@ package android {
field @Deprecated public static final String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
field public static final String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
field @Deprecated public static final String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+ field public static final String BIND_COMPANION_DEVICE_SERVICE = "android.permission.BIND_COMPANION_DEVICE_SERVICE";
field public static final String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
field public static final String BIND_CONTROLS = "android.permission.BIND_CONTROLS";
field public static final String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
@@ -133,6 +134,7 @@ package android {
field public static final String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
field public static final String RECORD_BACKGROUND_AUDIO = "android.permission.RECORD_BACKGROUND_AUDIO";
field public static final String REORDER_TASKS = "android.permission.REORDER_TASKS";
+ field public static final String REQUEST_COMPANION_PROFILE_WATCH = "android.permission.REQUEST_COMPANION_PROFILE_WATCH";
field public static final String REQUEST_COMPANION_RUN_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND";
field public static final String REQUEST_COMPANION_USE_DATA_IN_BACKGROUND = "android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND";
field public static final String REQUEST_DELETE_PACKAGES = "android.permission.REQUEST_DELETE_PACKAGES";
@@ -5489,7 +5491,9 @@ package android.app {
field public static final String CATEGORY_EMAIL = "email";
field public static final String CATEGORY_ERROR = "err";
field public static final String CATEGORY_EVENT = "event";
+ field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
field public static final String CATEGORY_MESSAGE = "msg";
+ field public static final String CATEGORY_MISSED_CALL = "missed_call";
field public static final String CATEGORY_NAVIGATION = "navigation";
field public static final String CATEGORY_PROGRESS = "progress";
field public static final String CATEGORY_PROMO = "promo";
@@ -5498,8 +5502,10 @@ package android.app {
field public static final String CATEGORY_SERVICE = "service";
field public static final String CATEGORY_SOCIAL = "social";
field public static final String CATEGORY_STATUS = "status";
+ field public static final String CATEGORY_STOPWATCH = "stopwatch";
field public static final String CATEGORY_SYSTEM = "sys";
field public static final String CATEGORY_TRANSPORT = "transport";
+ field public static final String CATEGORY_WORKOUT = "workout";
field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification> CREATOR;
field public static final int DEFAULT_ALL = -1; // 0xffffffff
@@ -5528,6 +5534,7 @@ package android.app {
field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
field public static final String EXTRA_PICTURE = "android.picture";
+ field public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION = "android.pictureContentDescription";
field public static final String EXTRA_PROGRESS = "android.progress";
field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
@@ -5673,6 +5680,7 @@ package android.app {
method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.Bitmap);
method public android.app.Notification.BigPictureStyle bigLargeIcon(android.graphics.drawable.Icon);
method public android.app.Notification.BigPictureStyle bigPicture(android.graphics.Bitmap);
+ method @NonNull public android.app.Notification.BigPictureStyle bigPictureContentDescription(@Nullable CharSequence);
method public android.app.Notification.BigPictureStyle setBigContentTitle(CharSequence);
method public android.app.Notification.BigPictureStyle setSummaryText(CharSequence);
}
@@ -5972,6 +5980,7 @@ package android.app {
method public long[] getVibrationPattern();
method public boolean hasUserSetImportance();
method public boolean hasUserSetSound();
+ method public boolean isConversation();
method public boolean isDemoted();
method public boolean isImportantConversation();
method public void setAllowBubbles(boolean);
@@ -6138,6 +6147,7 @@ package android.app {
method public android.content.IntentSender getIntentSender();
method public static android.app.PendingIntent getService(android.content.Context, int, @NonNull android.content.Intent, int);
method @Deprecated public String getTargetPackage();
+ method public boolean isImmutable();
method @Nullable public static android.app.PendingIntent readPendingIntentOrNullFromParcel(@NonNull android.os.Parcel);
method public void send() throws android.app.PendingIntent.CanceledException;
method public void send(int) throws android.app.PendingIntent.CanceledException;
@@ -6940,6 +6950,7 @@ package android.app.admin {
method @Nullable public java.util.List<java.lang.String> getPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName);
method @Nullable public java.util.List<java.lang.String> getPermittedInputMethods(@NonNull android.content.ComponentName);
method public int getPersonalAppsSuspendedReasons(@NonNull android.content.ComponentName);
+ method public int getRequiredPasswordComplexity();
method public long getRequiredStrongAuthTimeout(@Nullable android.content.ComponentName);
method public boolean getScreenCaptureDisabled(@Nullable android.content.ComponentName);
method public java.util.List<android.os.UserHandle> getSecondaryUsers(@NonNull android.content.ComponentName);
@@ -7071,6 +7082,7 @@ package android.app.admin {
method public void setProfileEnabled(@NonNull android.content.ComponentName);
method public void setProfileName(@NonNull android.content.ComponentName, String);
method public void setRecommendedGlobalProxy(@NonNull android.content.ComponentName, @Nullable android.net.ProxyInfo);
+ method public void setRequiredPasswordComplexity(int);
method public void setRequiredStrongAuthTimeout(@NonNull android.content.ComponentName, long);
method public boolean setResetPasswordToken(android.content.ComponentName, byte[]);
method public void setRestrictionsProvider(@NonNull android.content.ComponentName, @Nullable android.content.ComponentName);
@@ -7393,6 +7405,12 @@ package android.app.admin {
field public static final int ERROR_UNKNOWN = 1; // 0x1
}
+ public final class UnsafeStateException extends java.lang.IllegalStateException implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.UnsafeStateException> CREATOR;
+ }
+
}
package android.app.assist {
@@ -9430,14 +9448,16 @@ package android.companion {
public final class AssociationRequest implements android.os.Parcelable {
method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.companion.AssociationRequest> CREATOR;
+ field public static final String DEVICE_PROFILE_WATCH = "android.app.role.COMPANION_DEVICE_WATCH";
}
public static final class AssociationRequest.Builder {
ctor public AssociationRequest.Builder();
method @NonNull public android.companion.AssociationRequest.Builder addDeviceFilter(@Nullable android.companion.DeviceFilter<?>);
method @NonNull public android.companion.AssociationRequest build();
+ method @NonNull public android.companion.AssociationRequest.Builder setDeviceProfile(@NonNull String);
method @NonNull public android.companion.AssociationRequest.Builder setSingleDevice(boolean);
}
@@ -9487,6 +9507,14 @@ package android.companion {
method public abstract void onFailure(CharSequence);
}
+ public abstract class CompanionDeviceService extends android.app.Service {
+ ctor public CompanionDeviceService();
+ method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
+ method @MainThread public abstract void onDeviceAppeared(@NonNull String);
+ method @MainThread public abstract void onDeviceDisappeared(@NonNull String);
+ field public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService";
+ }
+
public interface DeviceFilter<D extends android.os.Parcelable> extends android.os.Parcelable {
}
@@ -10679,8 +10707,6 @@ package android.content {
field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
- field public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
- field public static final String ACTION_PACKAGE_UNSTARTABLE = "android.intent.action.PACKAGE_UNSTARTABLE";
field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
field public static final String ACTION_PASTE = "android.intent.action.PASTE";
field public static final String ACTION_PICK = "android.intent.action.PICK";
@@ -11718,10 +11744,9 @@ package android.content.pm {
method public long getFirstInstallTime();
method public android.graphics.drawable.Drawable getIcon(int);
method public CharSequence getLabel();
- method public float getLoadingProgress();
+ method @FloatRange(from=0.0, to=1.0) public float getLoadingProgress();
method public String getName();
method public android.os.UserHandle getUser();
- method public boolean isStartable();
}
public class LauncherApps {
@@ -12308,9 +12333,6 @@ package android.content.pm {
field public static final int SYNCHRONOUS = 2; // 0x2
field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
- field public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1; // 0x1
- field public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2; // 0x2
- field public static final int UNSTARTABLE_REASON_UNKNOWN = 0; // 0x0
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
@@ -15581,6 +15603,19 @@ package android.graphics {
method public final boolean next(android.graphics.Rect);
}
+ public final class RenderEffect {
+ method @NonNull public static android.graphics.RenderEffect createBitmapEffect(@NonNull android.graphics.Bitmap);
+ method @NonNull public static android.graphics.RenderEffect createBitmapEffect(@NonNull android.graphics.Bitmap, @Nullable android.graphics.Rect, @NonNull android.graphics.Rect);
+ method @NonNull public static android.graphics.RenderEffect createBlendModeEffect(@NonNull android.graphics.RenderEffect, @NonNull android.graphics.RenderEffect, @NonNull android.graphics.BlendMode);
+ method @NonNull public static android.graphics.RenderEffect createBlurEffect(float, float, @NonNull android.graphics.RenderEffect, @NonNull android.graphics.Shader.TileMode);
+ method @NonNull public static android.graphics.RenderEffect createBlurEffect(float, float, @NonNull android.graphics.Shader.TileMode);
+ method @NonNull public static android.graphics.RenderEffect createChainEffect(@NonNull android.graphics.RenderEffect, @NonNull android.graphics.RenderEffect);
+ method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter, @NonNull android.graphics.RenderEffect);
+ method @NonNull public static android.graphics.RenderEffect createColorFilterEffect(@NonNull android.graphics.ColorFilter);
+ method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float);
+ method @NonNull public static android.graphics.RenderEffect createOffsetEffect(float, float, @NonNull android.graphics.RenderEffect);
+ }
+
public final class RenderNode {
ctor public RenderNode(@Nullable String);
method @NonNull public android.graphics.RecordingCanvas beginRecording(int, int);
@@ -15640,6 +15675,7 @@ package android.graphics {
method public boolean setPosition(@NonNull android.graphics.Rect);
method public boolean setProjectBackwards(boolean);
method public boolean setProjectionReceiver(boolean);
+ method public void setRenderEffect(@Nullable android.graphics.RenderEffect);
method public boolean setRotationX(float);
method public boolean setRotationY(float);
method public boolean setRotationZ(float);
@@ -16407,6 +16443,7 @@ package android.graphics.fonts {
method public float getGlyphBounds(@IntRange(from=0) int, @NonNull android.graphics.Paint, @Nullable android.graphics.RectF);
method @NonNull public android.os.LocaleList getLocaleList();
method public void getMetrics(@NonNull android.graphics.Paint, @Nullable android.graphics.Paint.FontMetrics);
+ method public int getSourceIdentifier();
method @NonNull public android.graphics.fonts.FontStyle getStyle();
method @IntRange(from=0) public int getTtcIndex();
}
@@ -23921,7 +23958,7 @@ package android.location {
method public float getBearingAccuracyDegrees();
method public long getElapsedRealtimeNanos();
method public double getElapsedRealtimeUncertaintyNanos();
- method public android.os.Bundle getExtras();
+ method @Deprecated public android.os.Bundle getExtras();
method public double getLatitude();
method public double getLongitude();
method public String getProvider();
@@ -23950,7 +23987,7 @@ package android.location {
method public void setBearingAccuracyDegrees(float);
method public void setElapsedRealtimeNanos(long);
method public void setElapsedRealtimeUncertaintyNanos(double);
- method public void setExtras(android.os.Bundle);
+ method @Deprecated public void setExtras(android.os.Bundle);
method public void setLatitude(double);
method public void setLongitude(double);
method public void setProvider(String);
@@ -23966,7 +24003,9 @@ package android.location {
}
public interface LocationListener {
+ method public default void onFlushComplete(int);
method public void onLocationChanged(@NonNull android.location.Location);
+ method public default void onLocationChanged(@NonNull android.location.LocationResult);
method public default void onProviderDisabled(@NonNull String);
method public default void onProviderEnabled(@NonNull String);
method @Deprecated public default void onStatusChanged(String, int, android.os.Bundle);
@@ -24014,6 +24053,8 @@ package android.location {
method public void removeTestProvider(@NonNull String);
method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeUpdates(@NonNull android.location.LocationListener);
method public void removeUpdates(@NonNull android.app.PendingIntent);
+ method public void requestFlush(@NonNull String, @NonNull android.location.LocationListener, int);
+ method public void requestFlush(@NonNull String, @NonNull android.app.PendingIntent, int);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
@@ -24039,7 +24080,9 @@ package android.location {
field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
field public static final String GPS_PROVIDER = "gps";
+ field public static final String KEY_FLUSH_COMPLETE = "flushComplete";
field public static final String KEY_LOCATION_CHANGED = "location";
+ field public static final String KEY_LOCATION_RESULT = "locationResult";
field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
field public static final String KEY_PROXIMITY_ENTERING = "entering";
field @Deprecated public static final String KEY_STATUS_CHANGED = "status";
@@ -24070,6 +24113,7 @@ package android.location {
method public int describeContents();
method @IntRange(from=1) public long getDurationMillis();
method @IntRange(from=0) public long getIntervalMillis();
+ method @IntRange(from=0) public long getMaxUpdateDelayMillis();
method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
method @IntRange(from=0) public long getMinUpdateIntervalMillis();
@@ -24089,12 +24133,25 @@ package android.location {
method @NonNull public android.location.LocationRequest.Builder clearMinUpdateIntervalMillis();
method @NonNull public android.location.LocationRequest.Builder setDurationMillis(@IntRange(from=1) long);
method @NonNull public android.location.LocationRequest.Builder setIntervalMillis(@IntRange(from=0) long);
+ method @NonNull public android.location.LocationRequest.Builder setMaxUpdateDelayMillis(@IntRange(from=0) long);
method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
method @NonNull public android.location.LocationRequest.Builder setQuality(int);
}
+ public final class LocationResult implements android.os.Parcelable {
+ method @NonNull public java.util.List<android.location.Location> asList();
+ method @NonNull public static android.location.LocationResult create(@NonNull android.location.Location);
+ method @NonNull public static android.location.LocationResult create(@NonNull java.util.List<android.location.Location>);
+ method public int describeContents();
+ method @NonNull public android.location.Location get(@IntRange(from=0) int);
+ method @NonNull public android.location.Location getLastLocation();
+ method @IntRange(from=1) public int size();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationResult> CREATOR;
+ }
+
public interface OnNmeaMessageListener {
method public void onNmeaMessage(String, long);
}
@@ -24315,6 +24372,8 @@ package android.media {
field public static final int ENCODING_MP3 = 9; // 0x9
field public static final int ENCODING_OPUS = 20; // 0x14
field public static final int ENCODING_PCM_16BIT = 2; // 0x2
+ field public static final int ENCODING_PCM_24BIT_PACKED = 21; // 0x15
+ field public static final int ENCODING_PCM_32BIT = 22; // 0x16
field public static final int ENCODING_PCM_8BIT = 3; // 0x3
field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
field public static final int SAMPLE_RATE_UNSPECIFIED = 0; // 0x0
@@ -25256,6 +25315,7 @@ package android.media {
public final class MediaCas implements java.lang.AutoCloseable {
ctor public MediaCas(int) throws android.media.MediaCasException.UnsupportedCasException;
ctor public MediaCas(@NonNull android.content.Context, int, @Nullable String, int) throws android.media.MediaCasException.UnsupportedCasException;
+ ctor public MediaCas(@NonNull android.content.Context, int, @Nullable String, int, @Nullable android.os.Handler, @Nullable android.media.MediaCas.EventListener) throws android.media.MediaCasException.UnsupportedCasException;
method public void close();
method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
method protected void finalize();
@@ -28570,7 +28630,6 @@ package android.media.session {
public final class MediaController {
ctor public MediaController(@NonNull android.content.Context, @NonNull android.media.session.MediaSession.Token);
method public void adjustVolume(int, int);
- method @Deprecated public boolean controlsSameSession(@Nullable android.media.session.MediaController);
method public boolean dispatchMediaButtonEvent(@NonNull android.view.KeyEvent);
method @Nullable public android.os.Bundle getExtras();
method public long getFlags();
@@ -41189,10 +41248,11 @@ package android.security.keystore {
method public String getKeystoreAlias();
method public int getOrigin();
method public int getPurposes();
+ method public int getSecurityLevel();
method @NonNull public String[] getSignaturePaddings();
method public int getUserAuthenticationType();
method public int getUserAuthenticationValidityDurationSeconds();
- method public boolean isInsideSecureHardware();
+ method @Deprecated public boolean isInsideSecureHardware();
method public boolean isInvalidatedByBiometricEnrollment();
method public boolean isTrustedUserPresenceRequired();
method public boolean isUserAuthenticationRequired();
@@ -41249,6 +41309,11 @@ package android.security.keystore {
field public static final int PURPOSE_SIGN = 4; // 0x4
field public static final int PURPOSE_VERIFY = 8; // 0x8
field public static final int PURPOSE_WRAP_KEY = 32; // 0x20
+ field public static final int SECURITY_LEVEL_SOFTWARE = 0; // 0x0
+ field public static final int SECURITY_LEVEL_STRONGBOX = 2; // 0x2
+ field public static final int SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1; // 0x1
+ field public static final int SECURITY_LEVEL_UNKNOWN = -2; // 0xfffffffe
+ field public static final int SECURITY_LEVEL_UNKNOWN_SECURE = -1; // 0xffffffff
field public static final String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
field public static final String SIGNATURE_PADDING_RSA_PSS = "PSS";
}
@@ -44189,6 +44254,8 @@ package android.telecom {
field public static final String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
field public static final String EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME = "android.telecom.extra.ANSWERING_DROPS_FG_CALL_APP_NAME";
field public static final String EXTRA_AUDIO_CODEC = "android.telecom.extra.AUDIO_CODEC";
+ field public static final String EXTRA_AUDIO_CODEC_BANDWIDTH_KHZ = "android.telecom.extra.AUDIO_CODEC_BANDWIDTH_KHZ";
+ field public static final String EXTRA_AUDIO_CODEC_BITRATE_KBPS = "android.telecom.extra.AUDIO_CODEC_BITRATE_KBPS";
field public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final String EXTRA_IS_RTT_AUDIO_PRESENT = "android.telecom.extra.IS_RTT_AUDIO_PRESENT";
@@ -50767,6 +50834,7 @@ package android.view {
public static final class Display.Mode implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public float[] getAlternativeRefreshRates();
method public int getModeId();
method public int getPhysicalHeight();
method public int getPhysicalWidth();
@@ -51897,16 +51965,17 @@ package android.view {
field public int toolType;
}
- public interface OnReceiveContentCallback<T extends android.view.View> {
- method public boolean onReceiveContent(@NonNull T, @NonNull android.view.OnReceiveContentCallback.Payload);
+ public interface OnReceiveContentListener {
+ method @Nullable public android.view.OnReceiveContentListener.Payload onReceiveContent(@NonNull android.view.View, @NonNull android.view.OnReceiveContentListener.Payload);
}
- public static final class OnReceiveContentCallback.Payload {
+ public static final class OnReceiveContentListener.Payload {
method @NonNull public android.content.ClipData getClip();
method @Nullable public android.os.Bundle getExtras();
method public int getFlags();
method @Nullable public android.net.Uri getLinkUri();
method public int getSource();
+ method @NonNull public java.util.Map<java.lang.Boolean,android.view.OnReceiveContentListener.Payload> partition(@NonNull java.util.function.Predicate<android.content.ClipData.Item>);
field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
field public static final int SOURCE_APP = 0; // 0x0
field public static final int SOURCE_AUTOFILL = 4; // 0x4
@@ -51916,12 +51985,15 @@ package android.view {
field public static final int SOURCE_PROCESS_TEXT = 5; // 0x5
}
- public static final class OnReceiveContentCallback.Payload.Builder {
- ctor public OnReceiveContentCallback.Payload.Builder(@NonNull android.content.ClipData, int);
- method @NonNull public android.view.OnReceiveContentCallback.Payload build();
- method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setExtras(@Nullable android.os.Bundle);
- method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setFlags(int);
- method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setLinkUri(@Nullable android.net.Uri);
+ public static final class OnReceiveContentListener.Payload.Builder {
+ ctor public OnReceiveContentListener.Payload.Builder(@NonNull android.view.OnReceiveContentListener.Payload);
+ ctor public OnReceiveContentListener.Payload.Builder(@NonNull android.content.ClipData, int);
+ method @NonNull public android.view.OnReceiveContentListener.Payload build();
+ method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setClip(@NonNull android.content.ClipData);
+ method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setExtras(@Nullable android.os.Bundle);
+ method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setFlags(int);
+ method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setLinkUri(@Nullable android.net.Uri);
+ method @NonNull public android.view.OnReceiveContentListener.Payload.Builder setSource(int);
}
public abstract class OrientationEventListener {
@@ -52670,7 +52742,7 @@ package android.view {
method public void onProvideContentCaptureStructure(@NonNull android.view.ViewStructure, int);
method public void onProvideStructure(android.view.ViewStructure);
method public void onProvideVirtualStructure(android.view.ViewStructure);
- method public boolean onReceiveContent(@NonNull android.view.OnReceiveContentCallback.Payload);
+ method @Nullable public android.view.OnReceiveContentListener.Payload onReceiveContent(@NonNull android.view.OnReceiveContentListener.Payload);
method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
method @CallSuper protected void onRestoreInstanceState(android.os.Parcelable);
method public void onRtlPropertiesChanged(int);
@@ -52828,7 +52900,7 @@ package android.view {
method public void setOnHoverListener(android.view.View.OnHoverListener);
method public void setOnKeyListener(android.view.View.OnKeyListener);
method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener);
- method public void setOnReceiveContentCallback(@Nullable String[], @Nullable android.view.OnReceiveContentCallback);
+ method public void setOnReceiveContentListener(@Nullable String[], @Nullable android.view.OnReceiveContentListener);
method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
method @Deprecated public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
method public void setOnTouchListener(android.view.View.OnTouchListener);
@@ -53213,6 +53285,7 @@ package android.view {
method @Deprecated public static int getMaximumDrawingCacheSize();
method @Deprecated public static int getMaximumFlingVelocity();
method @Deprecated public static int getMinimumFlingVelocity();
+ method public static int getMultiPressTimeout();
method public static int getPressedStateDuration();
method @FloatRange(from=1.0) public float getScaledAmbiguousGestureMultiplier();
method public int getScaledDoubleTapSlop();
@@ -59844,11 +59917,6 @@ package android.widget {
field @NonNull public static final android.os.Parcelable.Creator<android.widget.TextView.SavedState> CREATOR;
}
- public class TextViewOnReceiveContentCallback implements android.view.OnReceiveContentCallback<android.widget.TextView> {
- ctor public TextViewOnReceiveContentCallback();
- method public boolean onReceiveContent(@NonNull android.widget.TextView, @NonNull android.view.OnReceiveContentCallback.Payload);
- }
-
public interface ThemedSpinnerAdapter extends android.widget.SpinnerAdapter {
method @Nullable public android.content.res.Resources.Theme getDropDownViewTheme();
method public void setDropDownViewTheme(@Nullable android.content.res.Resources.Theme);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 06e6d9ccbbf0..3617967bfbdf 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -4,6 +4,7 @@ package android.app {
public class ActivityManager {
method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
+ method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
}
public class AppOpsManager {
@@ -42,18 +43,6 @@ package android.content.rollback {
}
-package android.graphics {
-
- public final class Compatibility {
- method public static void setTargetSdkVersion(int);
- }
-
- public final class ImageDecoder implements java.lang.AutoCloseable {
- method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(@NonNull android.content.ContentResolver, @NonNull android.net.Uri, @Nullable android.content.res.Resources);
- }
-
-}
-
package android.media {
public class AudioManager {
@@ -89,10 +78,17 @@ package android.media.session {
method public boolean dispatchMediaKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
method public void dispatchVolumeKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
+ method public void registerRemoteVolumeControllerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.session.MediaSessionManager.RemoteVolumeControllerCallback);
+ method public void unregisterRemoteVolumeControllerCallback(@NonNull android.media.session.MediaSessionManager.RemoteVolumeControllerCallback);
field public static final int RESULT_MEDIA_KEY_HANDLED = 1; // 0x1
field public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0; // 0x0
}
+ public static interface MediaSessionManager.RemoteVolumeControllerCallback {
+ method public void onSessionChanged(@Nullable android.media.session.MediaSession.Token);
+ method public void onVolumeChanged(@NonNull android.media.session.MediaSession.Token, int);
+ }
+
public final class PlaybackState implements android.os.Parcelable {
method public boolean isActiveState();
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b37f7386ab70..8214e31d5c0e 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -182,6 +182,7 @@ package android {
field public static final String READ_PRINT_SERVICES = "android.permission.READ_PRINT_SERVICES";
field public static final String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS";
field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
+ field public static final String READ_PROJECTION_STATE = "android.permission.READ_PROJECTION_STATE";
field public static final String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES";
field public static final String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
field public static final String READ_SYSTEM_UPDATE_INFO = "android.permission.READ_SYSTEM_UPDATE_INFO";
@@ -234,6 +235,7 @@ package android {
field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA";
field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
+ field public static final String TOGGLE_AUTOMOTIVE_PROJECTION = "android.permission.TOGGLE_AUTOMOTIVE_PROJECTION";
field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
field public static final String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
field public static final String UNLIMITED_SHORTCUTS_API_CALLS = "android.permission.UNLIMITED_SHORTCUTS_API_CALLS";
@@ -381,6 +383,7 @@ package android.app {
field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
+ field public static final String OPSTR_ACTIVATE_PLATFORM_VPN = "android:activate_platform_vpn";
field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
field public static final String OPSTR_ASSIST_STRUCTURE = "android:assist_structure";
@@ -743,12 +746,25 @@ package android.app {
}
public class UiModeManager {
+ method @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public void addOnProjectionStateChangeListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.app.UiModeManager.OnProjectionStateChangeListener);
method @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) public void enableCarMode(@IntRange(from=0) int, int);
+ method @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public int getActiveProjectionTypes();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public java.util.Set<java.lang.String> getProjectingPackages(int);
+ method @RequiresPermission(value=android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, conditional=true) public boolean releaseProjection(int);
+ method @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE) public void removeOnProjectionStateChangeListener(@NonNull android.app.UiModeManager.OnProjectionStateChangeListener);
+ method @RequiresPermission(value=android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, conditional=true) public boolean requestProjection(int);
field public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED = "android.app.action.ENTER_CAR_MODE_PRIORITIZED";
field public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED = "android.app.action.EXIT_CAR_MODE_PRIORITIZED";
field public static final int DEFAULT_PRIORITY = 0; // 0x0
field public static final String EXTRA_CALLING_PACKAGE = "android.app.extra.CALLING_PACKAGE";
field public static final String EXTRA_PRIORITY = "android.app.extra.PRIORITY";
+ field public static final int PROJECTION_TYPE_ALL = 65535; // 0xffff
+ field public static final int PROJECTION_TYPE_AUTOMOTIVE = 1; // 0x1
+ field public static final int PROJECTION_TYPE_NONE = 0; // 0x0
+ }
+
+ public static interface UiModeManager.OnProjectionStateChangeListener {
+ method public void onProjectionStateChanged(int, @NonNull java.util.Set<java.lang.String>);
}
public final class Vr2dDisplayProperties implements android.os.Parcelable {
@@ -3765,7 +3781,8 @@ package android.location {
method public boolean hasMeasurementCorrectionsReflectingPane();
method public boolean hasMeasurements();
method public boolean hasNavMessages();
- method public boolean hasSatelliteBlacklist();
+ method @Deprecated public boolean hasSatelliteBlacklist();
+ method public boolean hasSatelliteBlocklist();
}
public final class GnssMeasurementCorrections implements android.os.Parcelable {
@@ -4093,17 +4110,17 @@ package android.location {
}
public class LocationManager {
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @Nullable public String getExtraLocationControllerPackage();
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
+ method @Deprecated public int getGnssBatchSize();
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
method public boolean isExtraLocationControllerPackageEnabled();
method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
+ method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
@@ -4112,7 +4129,8 @@ package android.location {
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
+ field public static final String FUSED_PROVIDER = "fused";
}
public final class LocationRequest implements android.os.Parcelable {
@@ -4159,6 +4177,10 @@ package android.location {
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
+ public final class LocationResult implements android.os.Parcelable {
+ method @NonNull public static android.location.LocationResult wrap(@NonNull android.location.Location);
+ }
+
}
package android.media {
@@ -4363,11 +4385,11 @@ package android.media {
}
public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
- method @RequiresPermission("android.permission.BIND_IMS_SERVICE") public void setOnImsRxNoticeListener(@Nullable android.media.MediaPlayer.OnImsRxNoticeListener, @Nullable android.os.Handler);
+ method @RequiresPermission("android.permission.BIND_IMS_SERVICE") public void setOnRtpRxNoticeListener(@NonNull android.content.Context, @NonNull android.media.MediaPlayer.OnRtpRxNoticeListener, @Nullable android.os.Handler);
}
- public static interface MediaPlayer.OnImsRxNoticeListener {
- method public void onImsRxNotice(@NonNull android.media.MediaPlayer, @NonNull byte[]);
+ public static interface MediaPlayer.OnRtpRxNoticeListener {
+ method public void onRtpRxNotice(@NonNull android.media.MediaPlayer, int, @NonNull int[]);
}
public final class MediaRecorder.AudioSource {
@@ -5010,6 +5032,7 @@ package android.media.tv.tuner {
method public long getAvSyncTime(int);
method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
+ method @Nullable public java.util.List<android.media.tv.tuner.frontend.FrontendInfo> getFrontendInfoList();
method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
method public int linkFrontendToCiCam(int);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler();
@@ -5030,7 +5053,10 @@ package android.media.tv.tuner {
field public static final int INVALID_AV_SYNC_ID = -1; // 0xffffffff
field public static final int INVALID_FILTER_ID = -1; // 0xffffffff
field public static final long INVALID_FILTER_ID_64BIT = -1L; // 0xffffffffffffffffL
+ field public static final int INVALID_FIRST_MACROBLOCK_IN_SLICE = -1; // 0xffffffff
+ field public static final int INVALID_FRONTEND_ID = -1; // 0xffffffff
field public static final int INVALID_FRONTEND_SETTING_FREQUENCY = -1; // 0xffffffff
+ field @NonNull public static final byte[] INVALID_KEYTOKEN;
field public static final int INVALID_LTS_ID = -1; // 0xffffffff
field public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1; // 0xffffffff
field public static final int INVALID_STREAM_ID = 65535; // 0xffff
@@ -5223,6 +5249,7 @@ package android.media.tv.tuner.filter {
public class Filter implements java.lang.AutoCloseable {
method public void close();
method public int configure(@NonNull android.media.tv.tuner.filter.FilterConfiguration);
+ method public int configureScramblingStatusEvent(int);
method public int flush();
method public int getId();
method public long getId64Bit();
@@ -5230,6 +5257,9 @@ package android.media.tv.tuner.filter {
method public int setDataSource(@Nullable android.media.tv.tuner.filter.Filter);
method public int start();
method public int stop();
+ field public static final int SCRAMBLING_STATUS_NOT_SCRAMBLED = 2; // 0x2
+ field public static final int SCRAMBLING_STATUS_SCRAMBLED = 4; // 0x4
+ field public static final int SCRAMBLING_STATUS_UNKNOWN = 1; // 0x1
field public static final int STATUS_DATA_READY = 1; // 0x1
field public static final int STATUS_HIGH_WATER = 4; // 0x4
field public static final int STATUS_LOW_WATER = 2; // 0x2
@@ -5330,9 +5360,11 @@ package android.media.tv.tuner.filter {
public class MmtpRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
method public long getDataLength();
+ method public int getFirstMacroblockInSlice();
method public int getMpuSequenceNumber();
method public long getPts();
method public int getScHevcIndexMask();
+ method public int getTsIndexMask();
}
public class PesEvent extends android.media.tv.tuner.filter.FilterEvent {
@@ -5361,6 +5393,11 @@ package android.media.tv.tuner.filter {
field public static final int INDEX_TYPE_NONE = 0; // 0x0
field public static final int INDEX_TYPE_SC = 1; // 0x1
field public static final int INDEX_TYPE_SC_HEVC = 2; // 0x2
+ field public static final int MPT_INDEX_AUDIO = 262144; // 0x40000
+ field public static final int MPT_INDEX_MPT = 65536; // 0x10000
+ field public static final int MPT_INDEX_TIMESTAMP_TARGET_AUDIO = 1048576; // 0x100000
+ field public static final int MPT_INDEX_TIMESTAMP_TARGET_VIDEO = 524288; // 0x80000
+ field public static final int MPT_INDEX_VIDEO = 131072; // 0x20000
field public static final int SC_HEVC_INDEX_AUD = 2; // 0x2
field public static final int SC_HEVC_INDEX_SLICE_BLA_N_LP = 16; // 0x10
field public static final int SC_HEVC_INDEX_SLICE_BLA_W_RADL = 8; // 0x8
@@ -5370,15 +5407,21 @@ package android.media.tv.tuner.filter {
field public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA = 128; // 0x80
field public static final int SC_HEVC_INDEX_SPS = 1; // 0x1
field public static final int SC_INDEX_B_FRAME = 4; // 0x4
+ field public static final int SC_INDEX_B_SLICE = 64; // 0x40
field public static final int SC_INDEX_I_FRAME = 1; // 0x1
+ field public static final int SC_INDEX_I_SLICE = 16; // 0x10
field public static final int SC_INDEX_P_FRAME = 2; // 0x2
+ field public static final int SC_INDEX_P_SLICE = 32; // 0x20
field public static final int SC_INDEX_SEQUENCE = 8; // 0x8
+ field public static final int SC_INDEX_SI_SLICE = 128; // 0x80
+ field public static final int SC_INDEX_SP_SLICE = 256; // 0x100
field public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG = 4096; // 0x1000
field public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED = 8; // 0x8
field public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED = 4; // 0x4
field public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED = 16; // 0x10
field public static final int TS_INDEX_DISCONTINUITY_INDICATOR = 32; // 0x20
field public static final int TS_INDEX_FIRST_PACKET = 1; // 0x1
+ field public static final int TS_INDEX_INVALID = 0; // 0x0
field public static final int TS_INDEX_OPCR_FLAG = 512; // 0x200
field public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR = 2; // 0x2
field public static final int TS_INDEX_PCR_FLAG = 256; // 0x100
@@ -5395,6 +5438,10 @@ package android.media.tv.tuner.filter {
method @NonNull public android.media.tv.tuner.filter.RecordSettings.Builder setTsIndexMask(int);
}
+ public final class ScramblingStatusEvent extends android.media.tv.tuner.filter.FilterEvent {
+ method public int getScramblingStatus();
+ }
+
public class SectionEvent extends android.media.tv.tuner.filter.FilterEvent {
method public int getDataLength();
method public int getSectionNumber();
@@ -5493,6 +5540,7 @@ package android.media.tv.tuner.filter {
public class TsRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
method public long getDataLength();
+ method public int getFirstMacroblockInSlice();
method public int getPacketId();
method public long getPts();
method public int getScIndexMask();
@@ -5730,7 +5778,8 @@ package android.media.tv.tuner.frontend {
public class DvbcFrontendCapabilities extends android.media.tv.tuner.frontend.FrontendCapabilities {
method public int getAnnexCapability();
- method public int getFecCapability();
+ method public long getCodeRateCapability();
+ method @Deprecated public int getFecCapability();
method public int getModulationCapability();
}
@@ -5818,6 +5867,7 @@ package android.media.tv.tuner.frontend {
public class DvbsFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
method @NonNull public static android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder builder();
method @Nullable public android.media.tv.tuner.frontend.DvbsCodeRate getCodeRate();
+ method public boolean getCouldHandleDiseqcRxMessage();
method public int getInputStreamId();
method public int getModulation();
method public int getPilot();
@@ -5827,7 +5877,6 @@ package android.media.tv.tuner.frontend {
method public int getSymbolRate();
method public int getType();
method public int getVcmMode();
- method public boolean isDiseqcRxMessage();
field public static final int MODULATION_AUTO = 1; // 0x1
field public static final int MODULATION_MOD_128APSK = 2048; // 0x800
field public static final int MODULATION_MOD_16APSK = 256; // 0x100
@@ -5871,7 +5920,7 @@ package android.media.tv.tuner.frontend {
public static class DvbsFrontendSettings.Builder {
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings build();
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCodeRate(@Nullable android.media.tv.tuner.frontend.DvbsCodeRate);
- method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setDiseqcRxMessage(boolean);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setCouldHandleDiseqcRxMessage(boolean);
method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setFrequency(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setInputStreamId(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setModulation(int);
@@ -6011,7 +6060,7 @@ package android.media.tv.tuner.frontend {
}
public abstract class FrontendSettings {
- method public int getEndFrequency();
+ method @IntRange(from=1) public int getEndFrequency();
method public int getFrequency();
method public int getFrontendSpectralInversion();
method public abstract int getType();
@@ -6091,6 +6140,7 @@ package android.media.tv.tuner.frontend {
method public int getPer();
method public int getPerBer();
method public int getPlpId();
+ method public int getRollOff();
method public int getSignalQuality();
method public int getSignalStrength();
method public int getSnr();
@@ -6102,8 +6152,11 @@ package android.media.tv.tuner.frontend {
method public int getUec();
method public boolean isDemodLocked();
method public boolean isEwbs();
+ method public boolean isLinear();
method public boolean isLnaOn();
+ method public boolean isMisoEnabled();
method public boolean isRfLocked();
+ method public boolean isShortFramesEnabled();
field public static final int FRONTEND_STATUS_TYPE_AGC = 14; // 0xe
field public static final int FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO = 21; // 0x15
field public static final int FRONTEND_STATUS_TYPE_BANDWIDTH = 25; // 0x19
@@ -6118,6 +6171,9 @@ package android.media.tv.tuner.frontend {
field public static final int FRONTEND_STATUS_TYPE_HIERARCHY = 19; // 0x13
field public static final int FRONTEND_STATUS_TYPE_INTERLEAVINGS = 30; // 0x1e
field public static final int FRONTEND_STATUS_TYPE_ISDBT_SEGMENTS = 31; // 0x1f
+ field public static final int FRONTEND_STATUS_TYPE_IS_LINEAR = 35; // 0x23
+ field public static final int FRONTEND_STATUS_TYPE_IS_MISO = 34; // 0x22
+ field public static final int FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES = 36; // 0x24
field public static final int FRONTEND_STATUS_TYPE_LAYER_ERROR = 16; // 0x10
field public static final int FRONTEND_STATUS_TYPE_LNA = 15; // 0xf
field public static final int FRONTEND_STATUS_TYPE_LNB_VOLTAGE = 11; // 0xb
@@ -6128,6 +6184,7 @@ package android.media.tv.tuner.frontend {
field public static final int FRONTEND_STATUS_TYPE_PLP_ID = 12; // 0xc
field public static final int FRONTEND_STATUS_TYPE_PRE_BER = 4; // 0x4
field public static final int FRONTEND_STATUS_TYPE_RF_LOCK = 20; // 0x14
+ field public static final int FRONTEND_STATUS_TYPE_ROLL_OFF = 33; // 0x21
field public static final int FRONTEND_STATUS_TYPE_SIGNAL_QUALITY = 5; // 0x5
field public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH = 6; // 0x6
field public static final int FRONTEND_STATUS_TYPE_SNR = 1; // 0x1
@@ -6293,6 +6350,7 @@ package android.media.tv.tuner.frontend {
public interface ScanCallback {
method public void onAnalogSifStandardReported(int);
method public void onAtsc3PlpInfosReported(@NonNull android.media.tv.tuner.frontend.Atsc3PlpInfo[]);
+ method public default void onDvbcAnnexReported(int);
method public void onDvbsStandardReported(int);
method public void onDvbtStandardReported(int);
method public void onFrequenciesReported(@NonNull int[]);
@@ -8712,8 +8770,13 @@ package android.security.keystore {
ctor public DeviceIdAttestationException(@Nullable String, @Nullable Throwable);
}
+ public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
+ method public int getNamespace();
+ }
+
public static final class KeyGenParameterSpec.Builder {
- method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
+ method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setNamespace(int);
+ method @Deprecated @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
}
}
@@ -8880,6 +8943,32 @@ package android.service.attention {
}
+package android.service.attestation {
+
+ public abstract class ImpressionAttestationService extends android.app.Service {
+ ctor public ImpressionAttestationService();
+ method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
+ method @Nullable public abstract android.service.attestation.ImpressionToken onGenerateImpressionToken(@NonNull android.hardware.HardwareBuffer, @NonNull android.graphics.Rect, @NonNull String);
+ method public abstract int onVerifyImpressionToken(@NonNull android.service.attestation.ImpressionToken);
+ field public static final int VERIFICATION_STATUS_APP_DECLARED = 2; // 0x2
+ field public static final int VERIFICATION_STATUS_OS_VERIFIED = 1; // 0x1
+ field public static final int VERIFICATION_STATUS_UNKNOWN = 0; // 0x0
+ }
+
+ public final class ImpressionToken implements android.os.Parcelable {
+ ctor public ImpressionToken(long, @NonNull android.graphics.Rect, @NonNull String, @NonNull byte[], @NonNull byte[]);
+ method public int describeContents();
+ method @NonNull public android.graphics.Rect getBoundsInWindow();
+ method @NonNull public String getHashingAlgorithm();
+ method @NonNull public byte[] getHmac();
+ method @NonNull public byte[] getImageHash();
+ method public long getScreenshotTimeMillis();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.attestation.ImpressionToken> CREATOR;
+ }
+
+}
+
package android.service.autofill {
public abstract class AutofillFieldClassificationService extends android.app.Service {
@@ -9969,6 +10058,17 @@ package android.telephony {
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallQuality> CREATOR;
}
+ public final class CarrierBandwidth implements android.os.Parcelable {
+ ctor public CarrierBandwidth(int, int, int, int);
+ method public int describeContents();
+ method public int getPrimaryDownlinkCapacityKbps();
+ method public int getPrimaryUplinkCapacityKbps();
+ method public int getSecondaryDownlinkCapacityKbps();
+ method public int getSecondaryUplinkCapacityKbps();
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CarrierBandwidth> CREATOR;
+ field public static final int INVALID = -1; // 0xffffffff
+ }
+
public class CarrierConfigManager {
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultCarrierServicePackageName();
method @NonNull public static android.os.PersistableBundle getDefaultConfig();
@@ -10266,6 +10366,18 @@ package android.telephony {
field public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; // 0xffffffff
}
+ public final class PinResult implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getAttemptsRemaining();
+ method public int getResult();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PinResult> CREATOR;
+ field public static final int PIN_RESULT_TYPE_ABORTED = 3; // 0x3
+ field public static final int PIN_RESULT_TYPE_FAILURE = 2; // 0x2
+ field public static final int PIN_RESULT_TYPE_INCORRECT = 1; // 0x1
+ field public static final int PIN_RESULT_TYPE_SUCCESS = 0; // 0x0
+ }
+
public final class PreciseCallState implements android.os.Parcelable {
ctor public PreciseCallState(int, int, int, int, int);
method public int describeContents();
@@ -10609,6 +10721,7 @@ package android.telephony {
public class TelephonyManager {
method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult changeIccLockPin(@NonNull String, @NonNull String);
method public int checkCarrierPrivilegesForPackage(String);
method public int checkCarrierPrivilegesForPackageAnyPhone(String);
method public void dial(String);
@@ -10622,6 +10735,7 @@ package android.telephony {
method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierBandwidth getCarrierBandwidth();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
@@ -10634,6 +10748,8 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int);
method public String getCdmaPrlVersion();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaRoamingMode();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaSubscriptionMode();
method public int getCurrentPhoneType();
method public int getCurrentPhoneType(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getDataActivationState();
@@ -10706,9 +10822,12 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaRoamingMode(int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaSubscriptionMode(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult setIccLockEnabled(boolean, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMobileDataPolicyEnabledStatus(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
method public int setNrDualConnectivityState(int);
@@ -10724,10 +10843,12 @@ package android.telephony {
method @Deprecated public void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoiceActivationState(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void shutdownAllRadios();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult supplyIccLockPin(@NonNull String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult supplyIccLockPuk(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPin(String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPinReportResult(String);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPinReportResult(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPuk(String, String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPukReportResult(String, String);
+ 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);
@@ -10751,6 +10872,9 @@ package android.telephony {
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
+ field public static final int CDMA_SUBSCRIPTION_NV = 1; // 0x1
+ field public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // 0x0
+ field public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; // 0xffffffff
field public static final int ENABLE_NR_DUAL_CONNECTIVITY_INVALID_STATE = 4; // 0x4
field public static final int ENABLE_NR_DUAL_CONNECTIVITY_NOT_SUPPORTED = 1; // 0x1
field public static final int ENABLE_NR_DUAL_CONNECTIVITY_RADIO_ERROR = 3; // 0x3
@@ -10887,6 +11011,24 @@ package android.telephony.cdma {
package android.telephony.data {
+ public class ApnSetting implements android.os.Parcelable {
+ method public static int getApnTypeInt(@NonNull String);
+ method @NonNull public static String getApnTypeString(int);
+ field public static final String TYPE_ALL_STRING = "*";
+ field public static final String TYPE_CBS_STRING = "cbs";
+ field public static final String TYPE_DEFAULT_STRING = "default";
+ field public static final String TYPE_DUN_STRING = "dun";
+ field public static final String TYPE_EMERGENCY_STRING = "emergency";
+ field public static final String TYPE_FOTA_STRING = "fota";
+ field public static final String TYPE_HIPRI_STRING = "hipri";
+ field public static final String TYPE_IA_STRING = "ia";
+ field public static final String TYPE_IMS_STRING = "ims";
+ field public static final String TYPE_MCX_STRING = "mcx";
+ field public static final String TYPE_MMS_STRING = "mms";
+ field public static final String TYPE_SUPL_STRING = "supl";
+ field public static final String TYPE_XCAP_STRING = "xcap";
+ }
+
public final class DataCallResponse implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.net.LinkAddress> getAddresses();
@@ -10902,7 +11044,7 @@ package android.telephony.data {
method public int getMtuV6();
method @NonNull public java.util.List<java.net.InetAddress> getPcscfAddresses();
method public int getProtocolType();
- method public long getRetryIntervalMillis();
+ method public long getRetryDurationMillis();
method @Deprecated public int getSuggestedRetryTime();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
@@ -10915,7 +11057,7 @@ package android.telephony.data {
field public static final int LINK_STATUS_DORMANT = 1; // 0x1
field public static final int LINK_STATUS_INACTIVE = 0; // 0x0
field public static final int LINK_STATUS_UNKNOWN = -1; // 0xffffffff
- field public static final int RETRY_INTERVAL_UNDEFINED = -1; // 0xffffffff
+ field public static final int RETRY_DURATION_UNDEFINED = -1; // 0xffffffff
}
public static final class DataCallResponse.Builder {
@@ -10934,7 +11076,7 @@ package android.telephony.data {
method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV6(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>);
method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryIntervalMillis(long);
+ method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
}
@@ -11179,6 +11321,17 @@ package android.telephony.euicc {
package android.telephony.ims {
+ public final class AudioCodecAttributes implements android.os.Parcelable {
+ ctor public AudioCodecAttributes(float, @NonNull android.util.Range<java.lang.Float>, float, @NonNull android.util.Range<java.lang.Float>);
+ method public int describeContents();
+ method public float getBandwidthKhz();
+ method @NonNull public android.util.Range<java.lang.Float> getBandwidthRangeKhz();
+ method public float getBitrateKbps();
+ method @NonNull public android.util.Range<java.lang.Float> getBitrateRangeKbps();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.AudioCodecAttributes> CREATOR;
+ }
+
public final class ImsCallForwardInfo implements android.os.Parcelable {
ctor public ImsCallForwardInfo(int, int, int, int, @NonNull String, int);
method public int describeContents();
@@ -11208,6 +11361,7 @@ package android.telephony.ims {
ctor public ImsCallProfile(int, int);
ctor public ImsCallProfile(int, int, android.os.Bundle, android.telephony.ims.ImsStreamMediaProfile);
method public int describeContents();
+ method @NonNull public java.util.Set<android.telephony.ims.RtpHeaderExtensionType> getAcceptedRtpHeaderExtensionTypes();
method public String getCallExtra(String);
method public String getCallExtra(String, String);
method public boolean getCallExtraBoolean(String);
@@ -11232,6 +11386,7 @@ package android.telephony.ims {
method public boolean isVideoCall();
method public boolean isVideoPaused();
method public static int presentationToOir(int);
+ method public void setAcceptedRtpHeaderExtensionTypes(@NonNull java.util.Set<android.telephony.ims.RtpHeaderExtensionType>);
method public void setCallExtra(String, String);
method public void setCallExtraBoolean(String, boolean);
method public void setCallExtraInt(String, int);
@@ -11301,6 +11456,7 @@ package android.telephony.ims {
method public void callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
method public void callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
method public void callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState);
+ method public void callSessionDtmfReceived(char);
method @Deprecated public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo);
method @Deprecated public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo);
method public void callSessionHeld(android.telephony.ims.ImsCallProfile);
@@ -11321,6 +11477,7 @@ package android.telephony.ims {
method public void callSessionResumeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionResumeReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionResumed(android.telephony.ims.ImsCallProfile);
+ method public void callSessionRtpHeaderExtensionsReceived(@NonNull java.util.Set<android.telephony.ims.RtpHeaderExtension>);
method public void callSessionRttAudioIndicatorChanged(@NonNull android.telephony.ims.ImsStreamMediaProfile);
method public void callSessionRttMessageReceived(String);
method public void callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile);
@@ -11547,6 +11704,7 @@ package android.telephony.ims {
ctor public ImsStreamMediaProfile(int, int, int, int, int);
method public void copyFrom(android.telephony.ims.ImsStreamMediaProfile);
method public int describeContents();
+ method @Nullable public android.telephony.ims.AudioCodecAttributes getAudioCodecAttributes();
method public int getAudioDirection();
method public int getAudioQuality();
method public int getRttMode();
@@ -11554,6 +11712,7 @@ package android.telephony.ims {
method public int getVideoQuality();
method public boolean isReceivingRttAudio();
method public boolean isRttCall();
+ method public void setAudioCodecAttributes(@NonNull android.telephony.ims.AudioCodecAttributes);
method public void setReceivingRttAudio(boolean);
method public void setRttMode(int);
method public void writeToParcel(android.os.Parcel, int);
@@ -11675,6 +11834,24 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
}
+ public final class RtpHeaderExtension implements android.os.Parcelable {
+ ctor public RtpHeaderExtension(@IntRange(from=1, to=14) int, @NonNull byte[]);
+ method public int describeContents();
+ method @NonNull public byte[] getExtensionData();
+ method @IntRange(from=1, to=14) public int getLocalIdentifier();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RtpHeaderExtension> CREATOR;
+ }
+
+ public final class RtpHeaderExtensionType implements android.os.Parcelable {
+ ctor public RtpHeaderExtensionType(@IntRange(from=1, to=14) int, @NonNull android.net.Uri);
+ method public int describeContents();
+ method @IntRange(from=1, to=14) public int getLocalIdentifier();
+ method @NonNull public android.net.Uri getUri();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RtpHeaderExtensionType> CREATOR;
+ }
+
public class SipDelegateManager {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSupported() throws android.telephony.ims.ImsException;
}
@@ -11728,6 +11905,7 @@ package android.telephony.ims.feature {
public class MmTelFeature extends android.telephony.ims.feature.ImsFeature {
ctor public MmTelFeature();
method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+ method public void changeOfferedRtpHeaderExtensionTypes(@NonNull java.util.Set<android.telephony.ims.RtpHeaderExtensionType>);
method @Nullable public android.telephony.ims.ImsCallProfile createCallProfile(int, int);
method @Nullable public android.telephony.ims.stub.ImsCallSessionImplBase createCallSession(@NonNull android.telephony.ims.ImsCallProfile);
method @NonNull public android.telephony.ims.stub.ImsEcbmImplBase getEcbm();
@@ -11791,6 +11969,7 @@ package android.telephony.ims.stub {
method public void removeParticipants(String[]);
method public void resume(android.telephony.ims.ImsStreamMediaProfile);
method public void sendDtmf(char, android.os.Message);
+ method public void sendRtpHeaderExtensions(@NonNull java.util.Set<android.telephony.ims.RtpHeaderExtension>);
method public void sendRttMessage(String);
method public void sendRttModifyRequest(android.telephony.ims.ImsCallProfile);
method public void sendRttModifyResponse(boolean);
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index 4db55e7e07eb..a3fb06cbd92f 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -6,7 +6,8 @@ ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
BuilderSetStyle: android.net.IpSecTransform.Builder#buildTunnelModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex):
Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.net.IpSecTransform.Builder.buildTunnelModeTransform(java.net.InetAddress,android.net.IpSecManager.SecurityParameterIndex)
-ExecutorRegistration: android.media.MediaPlayer#setOnImsRxNoticeListener(android.media.MediaPlayer.OnImsRxNoticeListener, android.os.Handler):
+ExecutorRegistration: android.media.MediaPlayer#setOnRtpRxNoticeListener(android.content.Context, android.media.MediaPlayer.OnRtpRxNoticeListener, android.os.Handler):
+ Registration methods should have overload that accepts delivery Executor: `setOnRtpRxNoticeListener`
GenericException: android.app.prediction.AppPredictor#finalize():
@@ -182,7 +183,8 @@ SamShouldBeLast: android.media.AudioRecordingMonitor#registerAudioRecordingCallb
SamShouldBeLast: android.media.AudioRouting#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
-SamShouldBeLast: android.media.MediaPlayer#setOnImsRxNoticeListener(android.media.MediaPlayer.OnImsRxNoticeListener, android.os.Handler):
+SamShouldBeLast: android.media.MediaPlayer#setOnRtpRxNoticeListener(android.content.Context, android.media.MediaPlayer.OnRtpRxNoticeListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 2, "listener", in android.media.MediaPlayer.setOnRtpRxNoticeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.AudioTrack#addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler):
diff --git a/api/test-current.txt b/core/api/test-current.txt
index 67b496b4f7ab..1c72d02204c6 100644
--- a/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -91,6 +91,7 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors();
method public static void resumeAppSwitches() throws android.os.RemoteException;
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
+ method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
field public static final int PROCESS_CAPABILITY_ALL = 7; // 0x7
field public static final int PROCESS_CAPABILITY_ALL_EXPLICIT = 1; // 0x1
field public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = 6; // 0x6
@@ -281,7 +282,7 @@ package android.app {
}
public class StatusBarManager {
- method public void collapsePanels();
+ method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void collapsePanels();
method public void expandNotificationsPanel();
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setExpansionDisabledForSimNetworkLock(boolean);
}
@@ -308,6 +309,11 @@ package android.app {
public class UiModeManager {
method public boolean isNightModeLocked();
method public boolean isUiModeLocked();
+ method @RequiresPermission(value=android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, conditional=true) public boolean releaseProjection(int);
+ method @RequiresPermission(value=android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION, conditional=true) public boolean requestProjection(int);
+ field public static final int PROJECTION_TYPE_ALL = 65535; // 0xffff
+ field public static final int PROJECTION_TYPE_AUTOMOTIVE = 1; // 0x1
+ field public static final int PROJECTION_TYPE_NONE = 0; // 0x0
}
public class WallpaperManager {
@@ -363,12 +369,17 @@ package android.app.admin {
method public boolean isCurrentInputMethodSetByOwner();
method public boolean isFactoryResetProtectionPolicySupported();
field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
+ field public static final int OPERATION_LOCK_NOW = 1; // 0x1
}
public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
ctor public SecurityLog.SecurityEvent(long, byte[]);
}
+ public final class UnsafeStateException extends java.lang.IllegalStateException implements android.os.Parcelable {
+ method public int getOperation();
+ }
+
}
package android.app.blob {
@@ -2412,6 +2423,7 @@ package android.window {
public class TaskOrganizer extends android.window.WindowOrganizer {
ctor public TaskOrganizer();
+ method @BinderThread public void addStartingWindow(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.os.IBinder);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void createRootTask(int, int, @Nullable android.os.IBinder);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean deleteRootTask(@NonNull android.window.WindowContainerToken);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]);
@@ -2422,6 +2434,7 @@ package android.window {
method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer();
+ method @BinderThread public void removeStartingWindow(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer();
diff --git a/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index c0b40931f1e6..c0b40931f1e6 100644
--- a/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
diff --git a/api/test-removed.txt b/core/api/test-removed.txt
index d802177e249b..d802177e249b 100644
--- a/api/test-removed.txt
+++ b/core/api/test-removed.txt
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index af74b036a796..5dc6e602e5d6 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -16,16 +16,23 @@
package android.accounts;
import android.app.Activity;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.widget.TextView;
-import android.widget.LinearLayout;
-import android.view.View;
-import android.view.LayoutInflater;
+import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
import com.android.internal.R;
import java.io.IOException;
@@ -42,11 +49,15 @@ public class GrantCredentialsPermissionActivity extends Activity implements View
private Account mAccount;
private String mAuthTokenType;
private int mUid;
+ private int mCallingUid;
private Bundle mResultBundle = null;
protected LayoutInflater mInflater;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getWindow().addSystemFlags(
+ android.view.WindowManager.LayoutParams
+ .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
setContentView(R.layout.grant_credentials_permission);
setTitle(R.string.grant_permissions_header_text);
@@ -74,6 +85,20 @@ public class GrantCredentialsPermissionActivity extends Activity implements View
return;
}
+ try {
+ IBinder activityToken = getActivityToken();
+ mCallingUid = ActivityTaskManager.getService().getLaunchedFromUid(activityToken);
+ } catch (RemoteException re) {
+ // Couldn't figure out caller details
+ Log.w(getClass().getSimpleName(), "Unable to get caller identity \n" + re);
+ }
+
+ if (!UserHandle.isSameApp(mCallingUid, Process.SYSTEM_UID) && mCallingUid != mUid) {
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ return;
+ }
+
String accountTypeLabel;
try {
accountTypeLabel = getAccountLabel(mAccount);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2ac345d2560a..fc95718cf0e4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -77,6 +77,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -2701,12 +2702,18 @@ public class Activity extends ContextThemeWrapper
*/
public void reportFullyDrawn() {
if (mDoReportFullyDrawn) {
+ if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "reportFullyDrawn() for " + mComponent.toShortString());
+ }
mDoReportFullyDrawn = false;
try {
ActivityTaskManager.getService().reportActivityFullyDrawn(
mToken, mRestoredFromBundle);
VMRuntime.getRuntime().notifyStartupCompleted();
} catch (RemoteException e) {
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
}
@@ -5814,7 +5821,7 @@ public class Activity extends ContextThemeWrapper
intent.migrateExtraStreamToClipData(this);
intent.prepareToLeaveProcess(this);
result = ActivityTaskManager.getService()
- .startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
+ .startActivity(mMainThread.getApplicationThread(), getOpPackageName(),
getAttributionTag(), intent,
intent.resolveTypeIfNeeded(getContentResolver()), mToken, mEmbeddedID,
requestCode, ActivityManager.START_FLAG_ONLY_IF_NEEDED, null, options);
@@ -8722,13 +8729,16 @@ public class Activity extends ContextThemeWrapper
* the activity is visible after the screen is turned on when the lockscreen is up. In addition,
* if this flag is set and the activity calls {@link
* KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)}
- * the screen will turn on.
+ * the screen will turn on. If the screen is off and device is not secured, this flag can turn
+ * screen on and dismiss keyguard to make this activity visible and resume, which can be used to
+ * replace {@link PowerManager#ACQUIRE_CAUSES_WAKEUP}
*
* @param turnScreenOn {@code true} to turn on the screen; {@code false} otherwise.
*
* @see #setShowWhenLocked(boolean)
* @see android.R.attr#turnScreenOn
* @see android.R.attr#showWhenLocked
+ * @see KeyguardManager#isDeviceSecure()
*/
public void setTurnScreenOn(boolean turnScreenOn) {
try {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index ec287fe10634..1e6e7844fdea 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.app.WindowConfiguration.activityTypeToString;
+import static android.app.WindowConfiguration.windowingModeToString;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
@@ -171,6 +173,12 @@ public class ActivityManager {
*/
public static final int INSTR_FLAG_DISABLE_TEST_API_CHECKS = 1 << 2;
+ /**
+ * Do not restart the target process when starting or finishing instrumentation.
+ * @hide
+ */
+ public static final int INSTR_FLAG_NO_RESTART = 1 << 3;
+
static final class UidObserver extends IUidObserver.Stub {
final OnUidImportanceListener mListener;
final Context mContext;
@@ -488,89 +496,98 @@ public class ActivityManager {
@Retention(RetentionPolicy.SOURCE)
public @interface ProcessState {}
+ /*
+ * PROCESS_STATE_* must come from frameworks/base/core/java/android/app/ProcessStateEnum.aidl.
+ * This is to make sure that Java side uses the same values as native.
+ */
/** @hide Not a real process state. */
- public static final int PROCESS_STATE_UNKNOWN = -1;
+ public static final int PROCESS_STATE_UNKNOWN = ProcessStateEnum.UNKNOWN;
/** @hide Process is a persistent system process. */
- public static final int PROCESS_STATE_PERSISTENT = 0;
+ public static final int PROCESS_STATE_PERSISTENT = ProcessStateEnum.PERSISTENT;
/** @hide Process is a persistent system process and is doing UI. */
- public static final int PROCESS_STATE_PERSISTENT_UI = 1;
+ public static final int PROCESS_STATE_PERSISTENT_UI = ProcessStateEnum.PERSISTENT_UI;
/** @hide Process is hosting the current top activities. Note that this covers
* all activities that are visible to the user. */
@UnsupportedAppUsage
- public static final int PROCESS_STATE_TOP = 2;
+ public static final int PROCESS_STATE_TOP = ProcessStateEnum.TOP;
/** @hide Process is bound to a TOP app. */
- public static final int PROCESS_STATE_BOUND_TOP = 3;
+ public static final int PROCESS_STATE_BOUND_TOP = ProcessStateEnum.BOUND_TOP;
/** @hide Process is hosting a foreground service. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4;
+ public static final int PROCESS_STATE_FOREGROUND_SERVICE = ProcessStateEnum.FOREGROUND_SERVICE;
/** @hide Process is hosting a foreground service due to a system binding. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 5;
+ public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE =
+ ProcessStateEnum.BOUND_FOREGROUND_SERVICE;
/** @hide Process is important to the user, and something they are aware of. */
- public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 6;
+ public static final int PROCESS_STATE_IMPORTANT_FOREGROUND =
+ ProcessStateEnum.IMPORTANT_FOREGROUND;
/** @hide Process is important to the user, but not something they are aware of. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 7;
+ public static final int PROCESS_STATE_IMPORTANT_BACKGROUND =
+ ProcessStateEnum.IMPORTANT_BACKGROUND;
/** @hide Process is in the background transient so we will try to keep running. */
- public static final int PROCESS_STATE_TRANSIENT_BACKGROUND = 8;
+ public static final int PROCESS_STATE_TRANSIENT_BACKGROUND =
+ ProcessStateEnum.TRANSIENT_BACKGROUND;
/** @hide Process is in the background running a backup/restore operation. */
- public static final int PROCESS_STATE_BACKUP = 9;
+ public static final int PROCESS_STATE_BACKUP = ProcessStateEnum.BACKUP;
/** @hide Process is in the background running a service. Unlike oom_adj, this level
* is used for both the normal running in background state and the executing
* operations state. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int PROCESS_STATE_SERVICE = 10;
+ public static final int PROCESS_STATE_SERVICE = ProcessStateEnum.SERVICE;
/** @hide Process is in the background running a receiver. Note that from the
* perspective of oom_adj, receivers run at a higher foreground level, but for our
* prioritization here that is not necessary and putting them below services means
* many fewer changes in some process states as they receive broadcasts. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int PROCESS_STATE_RECEIVER = 11;
+ public static final int PROCESS_STATE_RECEIVER = ProcessStateEnum.RECEIVER;
/** @hide Same as {@link #PROCESS_STATE_TOP} but while device is sleeping. */
- public static final int PROCESS_STATE_TOP_SLEEPING = 12;
+ public static final int PROCESS_STATE_TOP_SLEEPING = ProcessStateEnum.TOP_SLEEPING;
/** @hide Process is in the background, but it can't restore its state so we want
* to try to avoid killing it. */
- public static final int PROCESS_STATE_HEAVY_WEIGHT = 13;
+ public static final int PROCESS_STATE_HEAVY_WEIGHT = ProcessStateEnum.HEAVY_WEIGHT;
/** @hide Process is in the background but hosts the home activity. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int PROCESS_STATE_HOME = 14;
+ public static final int PROCESS_STATE_HOME = ProcessStateEnum.HOME;
/** @hide Process is in the background but hosts the last shown activity. */
- public static final int PROCESS_STATE_LAST_ACTIVITY = 15;
+ public static final int PROCESS_STATE_LAST_ACTIVITY = ProcessStateEnum.LAST_ACTIVITY;
/** @hide Process is being cached for later use and contains activities. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int PROCESS_STATE_CACHED_ACTIVITY = 16;
+ public static final int PROCESS_STATE_CACHED_ACTIVITY = ProcessStateEnum.CACHED_ACTIVITY;
/** @hide Process is being cached for later use and is a client of another cached
* process that contains activities. */
- public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 17;
+ public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT =
+ ProcessStateEnum.CACHED_ACTIVITY_CLIENT;
/** @hide Process is being cached for later use and has an activity that corresponds
* to an existing recent task. */
- public static final int PROCESS_STATE_CACHED_RECENT = 18;
+ public static final int PROCESS_STATE_CACHED_RECENT = ProcessStateEnum.CACHED_RECENT;
/** @hide Process is being cached for later use and is empty. */
- public static final int PROCESS_STATE_CACHED_EMPTY = 19;
+ public static final int PROCESS_STATE_CACHED_EMPTY = ProcessStateEnum.CACHED_EMPTY;
/** @hide Process does not exist. */
- public static final int PROCESS_STATE_NONEXISTENT = 20;
+ public static final int PROCESS_STATE_NONEXISTENT = ProcessStateEnum.NONEXISTENT;
/**
* The set of flags for process capability.
@@ -1693,6 +1710,13 @@ public class ActivityManager {
@Deprecated
public int affiliatedTaskId;
+ /**
+ * Information of organized child tasks.
+ *
+ * @hide
+ */
+ public ArrayList<RecentTaskInfo> childrenTaskInfos = new ArrayList<>();
+
public RecentTaskInfo() {
}
@@ -1708,6 +1732,7 @@ public class ActivityManager {
public void readFromParcel(Parcel source) {
id = source.readInt();
persistentId = source.readInt();
+ childrenTaskInfos = source.readArrayList(RecentTaskInfo.class.getClassLoader());
super.readFromParcel(source);
}
@@ -1715,6 +1740,7 @@ public class ActivityManager {
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeInt(persistentId);
+ dest.writeList(childrenTaskInfos);
super.writeToParcel(dest, flags);
}
@@ -1732,11 +1758,6 @@ public class ActivityManager {
* @hide
*/
public void dump(PrintWriter pw, String indent) {
- final String activityType = WindowConfiguration.activityTypeToString(
- configuration.windowConfiguration.getActivityType());
- final String windowingMode = WindowConfiguration.activityTypeToString(
- configuration.windowConfiguration.getActivityType());
-
pw.println(); pw.print(" ");
pw.print(" id="); pw.print(persistentId);
pw.print(" stackId="); pw.print(stackId);
@@ -1762,8 +1783,8 @@ public class ActivityManager {
pw.print(" ");
pw.print(" isExcluded=");
pw.print(((baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0));
- pw.print(" activityType="); pw.print(activityType);
- pw.print(" windowingMode="); pw.print(windowingMode);
+ pw.print(" activityType="); pw.print(activityTypeToString(getActivityType()));
+ pw.print(" windowingMode="); pw.print(windowingModeToString(getWindowingMode()));
pw.print(" supportsSplitScreenMultiWindow=");
pw.println(supportsSplitScreenMultiWindow);
if (taskDescription != null) {
@@ -1930,7 +1951,7 @@ public class ActivityManager {
ArrayList<AppTask> tasks = new ArrayList<AppTask>();
List<IBinder> appTasks;
try {
- appTasks = getTaskService().getAppTasks(mContext.getPackageName());
+ appTasks = getTaskService().getAppTasks(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2465,7 +2486,7 @@ public class ActivityManager {
try {
ActivityThread thread = ActivityThread.currentActivityThread();
IApplicationThread appThread = thread.getApplicationThread();
- String packageName = mContext.getPackageName();
+ String packageName = mContext.getOpPackageName();
getTaskService().moveTaskToFront(appThread, packageName, taskId, flags, options);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -4194,15 +4215,18 @@ public class ActivityManager {
}
/**
- * Updates mcc mnc configuration and applies changes to the entire system.
+ * Updates the MCC (Mobile Country Code) and MNC (Mobile Network Code) in the
+ * system configuration.
*
- * @param mcc mcc configuration to update.
- * @param mnc mnc configuration to update.
+ * @param mcc The new MCC.
+ * @param mnc The new MNC.
* @throws RemoteException; IllegalArgumentException if mcc or mnc is null;
* @return Returns {@code true} if the configuration was updated successfully;
* {@code false} otherwise.
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
@RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION)
public boolean updateMccMncConfiguration(@NonNull String mcc, @NonNull String mnc) {
if (mcc == null || mnc == null) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b68194792db1..2211807a422b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -186,6 +186,7 @@ import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.TrustedCertificateStore;
import com.android.server.am.MemInfoDumpProto;
+import dalvik.system.AppSpecializationHooks;
import dalvik.system.CloseGuard;
import dalvik.system.VMDebug;
import dalvik.system.VMRuntime;
@@ -380,6 +381,7 @@ public final class ActivityThread extends ClientTransactionHandler {
String mInstrumentedAppDir = null;
String[] mInstrumentedSplitAppDirs = null;
String mInstrumentedLibDir = null;
+ boolean mInstrumentingWithoutRestart;
boolean mSystemThread = false;
boolean mSomeActivitiesChanged = false;
/* package */ boolean mHiddenApiWarningShown = false;
@@ -1773,6 +1775,19 @@ public final class ActivityThread extends ClientTransactionHandler {
key.mLock.notifyAll();
}
}
+
+ @Override
+ public void instrumentWithoutRestart(ComponentName instrumentationName,
+ Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
+ IUiAutomationConnection instrumentationUiConnection, ApplicationInfo targetInfo) {
+ AppBindData data = new AppBindData();
+ data.instrumentationName = instrumentationName;
+ data.instrumentationArgs = instrumentationArgs;
+ data.instrumentationWatcher = instrumentationWatcher;
+ data.instrumentationUiAutomationConnection = instrumentationUiConnection;
+ data.appInfo = targetInfo;
+ sendMessage(H.INSTRUMENT_WITHOUT_RESTART, data);
+ }
}
private @NonNull SafeCancellationTransport createSafeCancellationTransport(
@@ -1878,6 +1893,9 @@ public final class ActivityThread extends ClientTransactionHandler {
public static final int PURGE_RESOURCES = 161;
public static final int ATTACH_STARTUP_AGENTS = 162;
+ public static final int INSTRUMENT_WITHOUT_RESTART = 170;
+ public static final int FINISH_INSTRUMENTATION_WITHOUT_RESTART = 171;
+
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
@@ -1920,6 +1938,9 @@ public final class ActivityThread extends ClientTransactionHandler {
case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
case PURGE_RESOURCES: return "PURGE_RESOURCES";
case ATTACH_STARTUP_AGENTS: return "ATTACH_STARTUP_AGENTS";
+ case INSTRUMENT_WITHOUT_RESTART: return "INSTRUMENT_WITHOUT_RESTART";
+ case FINISH_INSTRUMENTATION_WITHOUT_RESTART:
+ return "FINISH_INSTRUMENTATION_WITHOUT_RESTART";
}
}
return Integer.toString(code);
@@ -2101,6 +2122,12 @@ public final class ActivityThread extends ClientTransactionHandler {
case ATTACH_STARTUP_AGENTS:
handleAttachStartupAgents((String) msg.obj);
break;
+ case INSTRUMENT_WITHOUT_RESTART:
+ handleInstrumentWithoutRestart((AppBindData) msg.obj);
+ break;
+ case FINISH_INSTRUMENTATION_WITHOUT_RESTART:
+ handleFinishInstrumentationWithoutRestart();
+ break;
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
@@ -4971,15 +4998,8 @@ public final class ActivityThread extends ClientTransactionHandler {
}
private void relaunchAllActivities(boolean preserveWindows) {
- for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
- final ActivityClientRecord r = entry.getValue();
- // Schedule relaunch the activity if it is not a local object or finishing.
- if (!r.activity.mFinished && !(r.token instanceof Binder)) {
- if (preserveWindows && r.window != null) {
- r.mPreserveWindow = true;
- }
- scheduleRelaunchActivity(entry.getKey());
- }
+ for (int i = mActivities.size() - 1; i >= 0; i--) {
+ scheduleRelaunchActivityIfPossible(mActivities.valueAt(i), preserveWindows);
}
}
@@ -5348,15 +5368,31 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
+ void scheduleRelaunchActivity(IBinder token) {
+ final ActivityClientRecord r = mActivities.get(token);
+ if (r != null) {
+ scheduleRelaunchActivityIfPossible(r, !r.stopped /* preserveWindow */);
+ }
+ }
+
/**
* Post a message to relaunch the activity. We do this instead of launching it immediately,
* because this will destroy the activity from which it was called and interfere with the
* lifecycle changes it was going through before. We need to make sure that we have finished
* handling current transaction item before relaunching the activity.
*/
- void scheduleRelaunchActivity(IBinder token) {
- mH.removeMessages(H.RELAUNCH_ACTIVITY, token);
- sendMessage(H.RELAUNCH_ACTIVITY, token);
+ private void scheduleRelaunchActivityIfPossible(@NonNull ActivityClientRecord r,
+ boolean preserveWindow) {
+ if (r.activity.mFinished || r.token instanceof Binder) {
+ // Do not schedule relaunch if the activity is finishing or not a local object (e.g.
+ // created by ActivtiyGroup that server side doesn't recognize it).
+ return;
+ }
+ if (preserveWindow && r.window != null) {
+ r.mPreserveWindow = true;
+ }
+ mH.removeMessages(H.RELAUNCH_ACTIVITY, r.token);
+ sendMessage(H.RELAUNCH_ACTIVITY, r.token);
}
/** Performs the activity relaunch locally vs. requesting from system-server. */
@@ -6309,6 +6345,9 @@ public final class ActivityThread extends ClientTransactionHandler {
Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
AppCompatCallbacks.install(data.disabledCompatChanges);
+ // Let libcore handle any compat changes after installing the list of compat changes.
+ AppSpecializationHooks.handleCompatChangesBeforeBindingApplication();
+
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
mCompatConfiguration = new Configuration(data.config);
@@ -6487,32 +6526,7 @@ public final class ActivityThread extends ClientTransactionHandler {
// setting up the app context.
final InstrumentationInfo ii;
if (data.instrumentationName != null) {
- try {
- ii = new ApplicationPackageManager(
- null, getPackageManager(), getPermissionManager())
- .getInstrumentationInfo(data.instrumentationName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException(
- "Unable to find instrumentation info for: " + data.instrumentationName);
- }
-
- // Warn of potential ABI mismatches.
- if (!Objects.equals(data.appInfo.primaryCpuAbi, ii.primaryCpuAbi)
- || !Objects.equals(data.appInfo.secondaryCpuAbi, ii.secondaryCpuAbi)) {
- Slog.w(TAG, "Package uses different ABI(s) than its instrumentation: "
- + "package[" + data.appInfo.packageName + "]: "
- + data.appInfo.primaryCpuAbi + ", " + data.appInfo.secondaryCpuAbi
- + " instrumentation[" + ii.packageName + "]: "
- + ii.primaryCpuAbi + ", " + ii.secondaryCpuAbi);
- }
-
- mInstrumentationPackageName = ii.packageName;
- mInstrumentationAppDir = ii.sourceDir;
- mInstrumentationSplitAppDirs = ii.splitSourceDirs;
- mInstrumentationLibDir = getInstrumentationLibrary(data.appInfo, ii);
- mInstrumentedAppDir = data.info.getAppDir();
- mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
- mInstrumentedLibDir = data.info.getLibDir();
+ ii = prepareInstrumentation(data);
} else {
ii = null;
}
@@ -6541,48 +6555,7 @@ public final class ActivityThread extends ClientTransactionHandler {
// Continue loading instrumentation.
if (ii != null) {
- ApplicationInfo instrApp;
- try {
- instrApp = getPackageManager().getApplicationInfo(ii.packageName, 0,
- UserHandle.myUserId());
- } catch (RemoteException e) {
- instrApp = null;
- }
- if (instrApp == null) {
- instrApp = new ApplicationInfo();
- }
- ii.copyTo(instrApp);
- instrApp.initForUser(UserHandle.myUserId());
- final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
- appContext.getClassLoader(), false, true, false);
-
- // The test context's op package name == the target app's op package name, because
- // the app ops manager checks the op package name against the real calling UID,
- // which is what the target package name is associated with.
- final ContextImpl instrContext = ContextImpl.createAppContext(this, pi,
- appContext.getOpPackageName());
-
- try {
- final ClassLoader cl = instrContext.getClassLoader();
- mInstrumentation = (Instrumentation)
- cl.loadClass(data.instrumentationName.getClassName()).newInstance();
- } catch (Exception e) {
- throw new RuntimeException(
- "Unable to instantiate instrumentation "
- + data.instrumentationName + ": " + e.toString(), e);
- }
-
- final ComponentName component = new ComponentName(ii.packageName, ii.name);
- mInstrumentation.init(this, instrContext, appContext, component,
- data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
-
- if (mProfiler.profileFile != null && !ii.handleProfiling
- && mProfiler.profileFd == null) {
- mProfiler.handlingProfiling = true;
- final File file = new File(mProfiler.profileFile);
- file.getParentFile().mkdirs();
- Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
- }
+ initInstrumentation(ii, data, appContext);
} else {
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
@@ -6673,6 +6646,120 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
+ private void handleInstrumentWithoutRestart(AppBindData data) {
+ try {
+ data.compatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+ data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
+ mInstrumentingWithoutRestart = true;
+ final InstrumentationInfo ii = prepareInstrumentation(data);
+ final ContextImpl appContext =
+ ContextImpl.createAppContext(this, data.info);
+
+ initInstrumentation(ii, data, appContext);
+
+ try {
+ mInstrumentation.onCreate(data.instrumentationArgs);
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Exception thrown in onCreate() of "
+ + data.instrumentationName + ": " + e.toString(), e);
+ }
+
+ } catch (Exception e) {
+ Slog.e(TAG, "Error in handleInstrumentWithoutRestart", e);
+ }
+ }
+
+ private InstrumentationInfo prepareInstrumentation(AppBindData data) {
+ final InstrumentationInfo ii;
+ try {
+ ii = new ApplicationPackageManager(
+ null, getPackageManager(), getPermissionManager())
+ .getInstrumentationInfo(data.instrumentationName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(
+ "Unable to find instrumentation info for: " + data.instrumentationName);
+ }
+
+ // Warn of potential ABI mismatches.
+ if (!Objects.equals(data.appInfo.primaryCpuAbi, ii.primaryCpuAbi)
+ || !Objects.equals(data.appInfo.secondaryCpuAbi, ii.secondaryCpuAbi)) {
+ Slog.w(TAG, "Package uses different ABI(s) than its instrumentation: "
+ + "package[" + data.appInfo.packageName + "]: "
+ + data.appInfo.primaryCpuAbi + ", " + data.appInfo.secondaryCpuAbi
+ + " instrumentation[" + ii.packageName + "]: "
+ + ii.primaryCpuAbi + ", " + ii.secondaryCpuAbi);
+ }
+
+ mInstrumentationPackageName = ii.packageName;
+ mInstrumentationAppDir = ii.sourceDir;
+ mInstrumentationSplitAppDirs = ii.splitSourceDirs;
+ mInstrumentationLibDir = getInstrumentationLibrary(data.appInfo, ii);
+ mInstrumentedAppDir = data.info.getAppDir();
+ mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
+ mInstrumentedLibDir = data.info.getLibDir();
+
+ return ii;
+ }
+
+ private void initInstrumentation(
+ InstrumentationInfo ii, AppBindData data, ContextImpl appContext) {
+ ApplicationInfo instrApp;
+ try {
+ instrApp = getPackageManager().getApplicationInfo(ii.packageName, 0,
+ UserHandle.myUserId());
+ } catch (RemoteException e) {
+ instrApp = null;
+ }
+ if (instrApp == null) {
+ instrApp = new ApplicationInfo();
+ }
+ ii.copyTo(instrApp);
+ instrApp.initForUser(UserHandle.myUserId());
+ final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
+ appContext.getClassLoader(), false, true, false);
+
+ // The test context's op package name == the target app's op package name, because
+ // the app ops manager checks the op package name against the real calling UID,
+ // which is what the target package name is associated with.
+ final ContextImpl instrContext = ContextImpl.createAppContext(this, pi,
+ appContext.getOpPackageName());
+
+ try {
+ final ClassLoader cl = instrContext.getClassLoader();
+ mInstrumentation = (Instrumentation)
+ cl.loadClass(data.instrumentationName.getClassName()).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Unable to instantiate instrumentation "
+ + data.instrumentationName + ": " + e.toString(), e);
+ }
+
+ final ComponentName component = new ComponentName(ii.packageName, ii.name);
+ mInstrumentation.init(this, instrContext, appContext, component,
+ data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
+
+ if (mProfiler.profileFile != null && !ii.handleProfiling
+ && mProfiler.profileFd == null) {
+ mProfiler.handlingProfiling = true;
+ final File file = new File(mProfiler.profileFile);
+ file.getParentFile().mkdirs();
+ Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
+ }
+ }
+
+ private void handleFinishInstrumentationWithoutRestart() {
+ mInstrumentation.onDestroy();
+ mInstrumentationPackageName = null;
+ mInstrumentationAppDir = null;
+ mInstrumentationSplitAppDirs = null;
+ mInstrumentationLibDir = null;
+ mInstrumentedAppDir = null;
+ mInstrumentedSplitAppDirs = null;
+ mInstrumentedLibDir = null;
+ mInstrumentingWithoutRestart = false;
+ }
+
/*package*/ final void finishInstrumentation(int resultCode, Bundle results) {
IActivityManager am = ActivityManager.getService();
if (mProfiler.profileFile != null && mProfiler.handlingProfiling
@@ -6686,6 +6773,9 @@ public final class ActivityThread extends ClientTransactionHandler {
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
+ if (mInstrumentingWithoutRestart) {
+ sendMessage(H.FINISH_INSTRUMENTATION_WITHOUT_RESTART, null);
+ }
}
@UnsupportedAppUsage
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index c89f16e596b5..d6cf8fffe586 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1464,6 +1464,7 @@ public class AppOpsManager {
@SystemApi
public static final String OPSTR_INTERACT_ACROSS_PROFILES = "android:interact_across_profiles";
/** @hide Start Platform VPN without user intervention */
+ @SystemApi
public static final String OPSTR_ACTIVATE_PLATFORM_VPN = "android:activate_platform_vpn";
/** @hide */
@SystemApi
@@ -7617,16 +7618,18 @@ public class AppOpsManager {
mContext.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE);
final String voiceRecognitionServicePackageName =
- voiceRecognitionComponent != null ? ComponentName.unflattenFromString(
- voiceRecognitionComponent).getPackageName() : "";
+ getComponentPackageNameFromString(voiceRecognitionComponent);
final String voiceInteractionServicePackageName =
- voiceInteractionComponent != null ? ComponentName.unflattenFromString(
- voiceInteractionComponent).getPackageName() : "";
-
+ getComponentPackageNameFromString(voiceInteractionComponent);
return Objects.equals(packageName, voiceRecognitionServicePackageName) && Objects.equals(
voiceRecognitionServicePackageName, voiceInteractionServicePackageName);
}
+ private String getComponentPackageNameFromString(String from) {
+ ComponentName componentName = from != null ? ComponentName.unflattenFromString(from) : null;
+ return componentName != null ? componentName.getPackageName() : "";
+ }
+
/**
* Do a quick check for whether an application might be able to perform an operation.
* This is <em>not</em> a security check; you must use {@link #noteOp(String, int, String,
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index b0c2762c3439..db58c215ffe2 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -72,7 +72,7 @@ public final class AsyncNotedAppOp implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -261,10 +261,10 @@ public final class AsyncNotedAppOp implements Parcelable {
};
@DataClass.Generated(
- time = 1583866239013L,
- codegenVersion = "1.0.15",
+ time = 1604456255752L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
- 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 mAttributionTag\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)")
+ inputSignatures = "private final @android.annotation.IntRange int mOpCode\nprivate final @android.annotation.IntRange int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mAttributionTag\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/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5c3be316f924..9727a28ff0f9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1039,7 +1039,7 @@ class ContextImpl extends Context {
public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
try {
ActivityTaskManager.getService().startActivityAsUser(
- mMainThread.getApplicationThread(), getBasePackageName(), getAttributionTag(),
+ mMainThread.getApplicationThread(), getOpPackageName(), getAttributionTag(),
intent, intent.resolveTypeIfNeeded(getContentResolver()),
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options,
user.getIdentifier());
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 879d4373f964..86625d340a14 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -98,6 +98,8 @@ interface IActivityManager {
void unregisterUidObserver(in IUidObserver observer);
boolean isUidActive(int uid, String callingPackage);
int getUidProcessState(int uid, in String callingPackage);
+ @UnsupportedAppUsage
+ int checkPermission(in String permission, int pid, int uid);
// =============== End of transactions used on native side as well ============================
// Special low-level communication with activity manager.
@@ -215,8 +217,6 @@ interface IActivityManager {
void setProcessLimit(int max);
@UnsupportedAppUsage
int getProcessLimit();
- @UnsupportedAppUsage
- int checkPermission(in String permission, int pid, int uid);
int checkUriPermission(in Uri uri, int pid, int uid, int mode, int userId,
in IBinder callerToken);
void grantUriPermission(in IApplicationThread caller, in String targetPkg, in Uri uri,
@@ -342,6 +342,7 @@ interface IActivityManager {
@UnsupportedAppUsage
void unregisterProcessObserver(in IProcessObserver observer);
boolean isIntentSenderTargetedToPackage(in IIntentSender sender);
+ boolean isIntentSenderImmutable(in IIntentSender sender);
@UnsupportedAppUsage
void updatePersistentConfiguration(in Configuration values);
void updatePersistentConfigurationWithAttribution(in Configuration values,
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index dc9918ade9c2..22ca42eb9cf4 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -150,4 +150,9 @@ oneway interface IApplicationThread {
in RemoteCallback resultCallback);
void notifyContentProviderPublishStatus(in ContentProviderHolder holder, String auth,
int userId, boolean published);
+ void instrumentWithoutRestart(in ComponentName instrumentationName,
+ in Bundle instrumentationArgs,
+ IInstrumentationWatcher instrumentationWatcher,
+ IUiAutomationConnection instrumentationUiConnection,
+ in ApplicationInfo targetInfo);
}
diff --git a/core/java/android/app/IOnProjectionStateChangeListener.aidl b/core/java/android/app/IOnProjectionStateChangeListener.aidl
new file mode 100644
index 000000000000..f15498545a68
--- /dev/null
+++ b/core/java/android/app/IOnProjectionStateChangeListener.aidl
@@ -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.
+ */
+
+package android.app;
+
+/** {@hide} */
+oneway interface IOnProjectionStateChangeListener {
+ void onProjectionStateChanged(int activeProjectionTypes, in List<String> projectingPackages);
+} \ No newline at end of file
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index 41e2ec9e3572..0ba5beccbf32 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -16,6 +16,8 @@
package android.app;
+import android.app.IOnProjectionStateChangeListener;
+
/**
* Interface used to control special UI modes.
* @hide
@@ -93,4 +95,34 @@ interface IUiModeManager {
* Sets custom end clock time
*/
void setCustomNightModeEnd(long time);
+
+ /**
+ * Sets projection state for the caller for the given projection type.
+ */
+ boolean requestProjection(in IBinder binder, int projectionType, String callingPackage);
+
+ /**
+ * Releases projection state for the caller for the given projection type.
+ */
+ boolean releaseProjection(int projectionType, String callingPackage);
+
+ /**
+ * Registers a listener for changes to projection state.
+ */
+ void addOnProjectionStateChangeListener(in IOnProjectionStateChangeListener listener, int projectionType);
+
+ /**
+ * Unregisters a listener for changes to projection state.
+ */
+ void removeOnProjectionStateChangeListener(in IOnProjectionStateChangeListener listener);
+
+ /**
+ * Returns packages that have currently set the given projection type.
+ */
+ List<String> getProjectingPackages(int projectionType);
+
+ /**
+ * Returns currently set projection types.
+ */
+ int getActiveProjectionTypes();
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 9e967958c9cb..3e249bb24dd6 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1725,7 +1725,7 @@ public class Instrumentation {
intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivity(whoThread,
- who.getBasePackageName(), who.getAttributionTag(), intent,
+ who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
checkStartActivityResult(result, intent);
@@ -1797,7 +1797,7 @@ public class Instrumentation {
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
}
int result = ActivityTaskManager.getService().startActivities(whoThread,
- who.getBasePackageName(), who.getAttributionTag(), intents, resolvedTypes,
+ who.getOpPackageName(), who.getAttributionTag(), intents, resolvedTypes,
token, options, userId);
checkStartActivityResult(result, intents[0]);
return result;
@@ -1864,7 +1864,7 @@ public class Instrumentation {
intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivity(whoThread,
- who.getBasePackageName(), who.getAttributionTag(), intent,
+ who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token, target,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
@@ -1931,7 +1931,7 @@ public class Instrumentation {
intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivityAsUser(whoThread,
- who.getBasePackageName(), who.getAttributionTag(), intent,
+ who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token, resultWho,
requestCode, 0, null, options, user.getIdentifier());
checkStartActivityResult(result, intent);
@@ -1977,11 +1977,11 @@ public class Instrumentation {
intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService()
- .startActivityAsCaller(whoThread, who.getBasePackageName(), intent,
- intent.resolveTypeIfNeeded(who.getContentResolver()),
- token, target != null ? target.mEmbeddedID : null,
- requestCode, 0, null, options, permissionToken,
- ignoreTargetSecurity, userId);
+ .startActivityAsCaller(whoThread, who.getOpPackageName(), intent,
+ intent.resolveTypeIfNeeded(who.getContentResolver()),
+ token, target != null ? target.mEmbeddedID : null,
+ requestCode, 0, null, options, permissionToken,
+ ignoreTargetSecurity, userId);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
@@ -2023,7 +2023,7 @@ public class Instrumentation {
try {
intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
- int result = appTask.startActivity(whoThread.asBinder(), who.getBasePackageName(),
+ int result = appTask.startActivity(whoThread.asBinder(), who.getOpPackageName(),
who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), options);
checkStartActivityResult(result, intent);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index b6094627d1f6..6535387acdf3 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -102,7 +102,6 @@ final class ServiceConnectionLeaked extends AndroidRuntimeException {
public final class LoadedApk {
static final String TAG = "LoadedApk";
static final boolean DEBUG = false;
- private static final String PROPERTY_NAME_APPEND_NATIVE = "pi.append_native_lib_paths";
@UnsupportedAppUsage
private final ActivityThread mActivityThread;
@@ -286,7 +285,7 @@ public final class LoadedApk {
return mSecurityViolation;
}
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @UnsupportedAppUsage(trackingBug = 172409979)
public CompatibilityInfo getCompatibilityInfo() {
return mDisplayAdjustments.getCompatibilityInfo();
}
@@ -926,7 +925,7 @@ public final class LoadedApk {
needToSetupJitProfiles = true;
}
- if (!libPaths.isEmpty() && SystemProperties.getBoolean(PROPERTY_NAME_APPEND_NATIVE, true)) {
+ if (!libPaths.isEmpty()) {
// Temporarily disable logging of disk reads on the Looper thread as this is necessary
StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
try {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a1abe3d8190b..4c08e759f3cf 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -897,6 +897,26 @@ public class Notification implements Parcelable
public static final String CATEGORY_CAR_INFORMATION = "car_information";
/**
+ * Notification category: tracking a user's workout.
+ */
+ public static final String CATEGORY_WORKOUT = "workout";
+
+ /**
+ * Notification category: temporarily sharing location.
+ */
+ public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
+
+ /**
+ * Notification category: running stopwatch.
+ */
+ public static final String CATEGORY_STOPWATCH = "stopwatch";
+
+ /**
+ * Notification category: missed call.
+ */
+ public static final String CATEGORY_MISSED_CALL = "missed_call";
+
+ /**
* One of the predefined notification categories (see the <code>CATEGORY_*</code> constants)
* that best describes this Notification. May be used by the system for ranking and filtering.
*/
@@ -1147,6 +1167,14 @@ public class Notification implements Parcelable
public static final String EXTRA_PICTURE = "android.picture";
/**
+ * {@link #extras} key: this is a content description of the big picture supplied from
+ * {@link BigPictureStyle#bigPicture(Bitmap)}, supplied to
+ * {@link BigPictureStyle#bigPictureContentDescription(CharSequence)}.
+ */
+ public static final String EXTRA_PICTURE_CONTENT_DESCRIPTION =
+ "android.pictureContentDescription";
+
+ /**
* {@link #extras} key: An array of CharSequences to show in {@link InboxStyle} expanded
* notifications, each of which was supplied to {@link InboxStyle#addLine(CharSequence)}.
*/
@@ -6728,6 +6756,7 @@ public class Notification implements Parcelable
private Bitmap mPicture;
private Icon mBigLargeIcon;
private boolean mBigLargeIconSet = false;
+ private CharSequence mPictureContentDescription;
public BigPictureStyle() {
}
@@ -6758,6 +6787,16 @@ public class Notification implements Parcelable
}
/**
+ * Set the content description of the big picture.
+ */
+ @NonNull
+ public BigPictureStyle bigPictureContentDescription(
+ @Nullable CharSequence contentDescription) {
+ mPictureContentDescription = contentDescription;
+ return this;
+ }
+
+ /**
* @hide
*/
public Bitmap getBigPicture() {
@@ -6870,6 +6909,11 @@ public class Notification implements Parcelable
}
contentView.setImageViewBitmap(R.id.big_picture, mPicture);
+
+ if (mPictureContentDescription != null) {
+ contentView.setContentDescription(R.id.big_picture, mPictureContentDescription);
+ }
+
return contentView;
}
@@ -6882,6 +6926,10 @@ public class Notification implements Parcelable
if (mBigLargeIconSet) {
extras.putParcelable(EXTRA_LARGE_ICON_BIG, mBigLargeIcon);
}
+ if (mPictureContentDescription != null) {
+ extras.putCharSequence(EXTRA_PICTURE_CONTENT_DESCRIPTION,
+ mPictureContentDescription);
+ }
extras.putParcelable(EXTRA_PICTURE, mPicture);
}
@@ -6896,6 +6944,12 @@ public class Notification implements Parcelable
mBigLargeIconSet = true;
mBigLargeIcon = extras.getParcelable(EXTRA_LARGE_ICON_BIG);
}
+
+ if (extras.containsKey(EXTRA_PICTURE_CONTENT_DESCRIPTION)) {
+ mPictureContentDescription =
+ extras.getCharSequence(EXTRA_PICTURE_CONTENT_DESCRIPTION);
+ }
+
mPicture = extras.getParcelable(EXTRA_PICTURE);
}
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index a06ffbdb4301..080aac9a9e6a 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -629,12 +629,20 @@ public final class NotificationChannel implements Parcelable {
}
/**
+ * Whether or not this channel represents a conversation.
+ */
+ public boolean isConversation() {
+ return !TextUtils.isEmpty(getConversationId());
+ }
+
+
+ /**
* Whether or not notifications in this conversation are considered important.
*
* <p>Important conversations may get special visual treatment, and might be able to bypass DND.
*
- * <p>This is only valid for channels that represent conversations, that is, those with a valid
- * {@link #getConversationId() conversation id}.
+ * <p>This is only valid for channels that represent conversations, that is,
+ * where {@link #isConversation()} is true.
*/
public boolean isImportantConversation() {
return mImportantConvo;
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 21dfbbd6f15d..f76a75749480 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -1145,6 +1145,18 @@ public final class PendingIntent implements Parcelable {
}
/**
+ * Check if this PendingIntent is marked with {@link #FLAG_IMMUTABLE}.
+ */
+ public boolean isImmutable() {
+ try {
+ return ActivityManager.getService()
+ .isIntentSenderImmutable(mTarget);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* @hide
* Check whether this PendingIntent will launch an Activity.
*/
diff --git a/core/java/android/app/ProcessStateEnum.aidl b/core/java/android/app/ProcessStateEnum.aidl
new file mode 100644
index 000000000000..a14e7a651eec
--- /dev/null
+++ b/core/java/android/app/ProcessStateEnum.aidl
@@ -0,0 +1,100 @@
+/*
+ * 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;
+
+/**
+ * Defines the PROCESS_STATE_* values used by ActivityManager.
+ * These values are shared by Java and native side.
+ * {@hide}
+ */
+@Backing(type="int")
+enum ProcessStateEnum {
+ /** @hide Not a real process state. */
+ UNKNOWN = -1,
+
+ /** @hide Process is a persistent system process. */
+ PERSISTENT = 0,
+
+ /** @hide Process is a persistent system process and is doing UI. */
+ PERSISTENT_UI = 1,
+
+ /** @hide Process is hosting the current top activities. Note that this covers
+ * all activities that are visible to the user. */
+ TOP = 2,
+
+ /** @hide Process is bound to a TOP app. */
+ BOUND_TOP = 3,
+
+ /** @hide Process is hosting a foreground service. */
+ FOREGROUND_SERVICE = 4,
+
+ /** @hide Process is hosting a foreground service due to a system binding. */
+ BOUND_FOREGROUND_SERVICE = 5,
+
+ /** @hide Process is important to the user, and something they are aware of. */
+ IMPORTANT_FOREGROUND = 6,
+
+ /** @hide Process is important to the user, but not something they are aware of. */
+ IMPORTANT_BACKGROUND = 7,
+
+ /** @hide Process is in the background transient so we will try to keep running. */
+ TRANSIENT_BACKGROUND = 8,
+
+ /** @hide Process is in the background running a backup/restore operation. */
+ BACKUP = 9,
+
+ /** @hide Process is in the background running a service. Unlike oom_adj, this level
+ * is used for both the normal running in background state and the executing
+ * operations state. */
+ SERVICE = 10,
+
+ /** @hide Process is in the background running a receiver. Note that from the
+ * perspective of oom_adj, receivers run at a higher foreground level, but for our
+ * prioritization here that is not necessary and putting them below services means
+ * many fewer changes in some process states as they receive broadcasts. */
+ RECEIVER = 11,
+
+ /** @hide Same as {@link #PROCESS_STATE_TOP} but while device is sleeping. */
+ TOP_SLEEPING = 12,
+
+ /** @hide Process is in the background, but it can't restore its state so we want
+ * to try to avoid killing it. */
+ HEAVY_WEIGHT = 13,
+
+ /** @hide Process is in the background but hosts the home activity. */
+ HOME = 14,
+
+ /** @hide Process is in the background but hosts the last shown activity. */
+ LAST_ACTIVITY = 15,
+
+ /** @hide Process is being cached for later use and contains activities. */
+ CACHED_ACTIVITY = 16,
+
+ /** @hide Process is being cached for later use and is a client of another cached
+ * process that contains activities. */
+ CACHED_ACTIVITY_CLIENT = 17,
+
+ /** @hide Process is being cached for later use and has an activity that corresponds
+ * to an existing recent task. */
+ CACHED_RECENT = 18,
+
+ /** @hide Process is being cached for later use and is empty. */
+ CACHED_EMPTY = 19,
+
+ /** @hide Process does not exist. */
+ NONEXISTENT = 20,
+
+}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index b8fae6755bfd..4e3d85ca1b78 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -283,9 +283,15 @@ public class StatusBarManager {
/**
* Collapse the notifications and settings panels.
*
+ * Starting in Android {@link Build.VERSION_CODES.S}, apps targeting SDK level {@link
+ * Build.VERSION_CODES.S} or higher will need {@link android.Manifest.permission.STATUS_BAR}
+ * permission to call this API.
+ *
* @hide
*/
- @UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.STATUS_BAR)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Send {@link "
+ + "android.content.Intent#ACTION_CLOSE_SYSTEM_DIALOGS} instead.")
@TestApi
public void collapsePanels() {
try {
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 43b7722c0864..5dfab6efe490 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -257,6 +257,18 @@ public class TaskInfo {
}
/** @hide */
+ @WindowConfiguration.WindowingMode
+ public int getWindowingMode() {
+ return configuration.windowConfiguration.getWindowingMode();
+ }
+
+ /** @hide */
+ @WindowConfiguration.ActivityType
+ public int getActivityType() {
+ return configuration.windowConfiguration.getActivityType();
+ }
+
+ /** @hide */
public void addLaunchCookie(IBinder cookie) {
if (cookie == null || launchCookies.contains(cookie)) return;
launchCookies.add(cookie);
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index e2fc5dbf10e2..e1c262caf44f 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -27,20 +28,32 @@ import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
+import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
import java.time.LocalTime;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
/**
* This class provides access to the system uimode services. These services
* allow applications to control UI modes of the device.
* It provides functionality to disable the car mode and it gives access to the
* night mode settings.
- *
+ *
* <p>These facilities are built on top of the underlying
* {@link android.content.Intent#ACTION_DOCK_EVENT} broadcasts that are sent when the user
* physical places the device into and out of a dock. When that happens,
@@ -49,7 +62,7 @@ import java.time.LocalTime;
* starts the corresponding mode activity if appropriate. See the
* broadcasts {@link #ACTION_ENTER_CAR_MODE} and
* {@link #ACTION_ENTER_DESK_MODE} for more information.
- *
+ *
* <p>In addition, the user may manually switch the system to car mode without
* physically being in a dock. While in car mode -- whether by manual action
* from the user or being physically placed in a dock -- a notification is
@@ -59,6 +72,25 @@ import java.time.LocalTime;
*/
@SystemService(Context.UI_MODE_SERVICE)
public class UiModeManager {
+ /**
+ * A listener with a single method that is invoked whenever the packages projecting using the
+ * {@link ProjectionType}s for which it is registered change.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface OnProjectionStateChangeListener {
+ /**
+ * Callback invoked when projection state changes for a {@link ProjectionType} for which
+ * this listener was added.
+ * @param projectionType the listened-for {@link ProjectionType}s that have changed
+ * @param packageNames the {@link Set} of package names that have currently set those
+ * {@link ProjectionType}s.
+ */
+ void onProjectionStateChanged(@ProjectionType int projectionType,
+ @NonNull Set<String> packageNames);
+ }
+
private static final String TAG = "UiModeManager";
/**
@@ -100,7 +132,7 @@ public class UiModeManager {
@SystemApi
public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED =
"android.app.action.ENTER_CAR_MODE_PRIORITIZED";
-
+
/**
* Broadcast sent when the device's UI has switch away from car mode back
* to normal mode. Typically used by a car mode app, to dismiss itself
@@ -137,7 +169,7 @@ public class UiModeManager {
@SystemApi
public static final String ACTION_EXIT_CAR_MODE_PRIORITIZED =
"android.app.action.EXIT_CAR_MODE_PRIORITIZED";
-
+
/**
* Broadcast sent when the device's UI has switched to desk mode,
* by being placed in a desk dock. After
@@ -151,7 +183,7 @@ public class UiModeManager {
* of the broadcast to {@link Activity#RESULT_CANCELED}.
*/
public static String ACTION_ENTER_DESK_MODE = "android.app.action.ENTER_DESK_MODE";
-
+
/**
* Broadcast sent when the device's UI has switched away from desk mode back
* to normal mode. Typically used by a desk mode app, to dismiss itself
@@ -198,13 +230,13 @@ public class UiModeManager {
* automatically switch night mode on and off based on the time.
*/
public static final int MODE_NIGHT_CUSTOM = 3;
-
+
/**
* Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
* never run in night mode.
*/
public static final int MODE_NIGHT_NO = 1;
-
+
/**
* Constant for {@link #setNightMode(int)} and {@link #getNightMode()}:
* always run in night mode.
@@ -219,6 +251,24 @@ public class UiModeManager {
*/
private @Nullable Context mContext;
+ private final Object mLock = new Object();
+ /**
+ * Map that stores internally created {@link InnerListener} objects keyed by their corresponding
+ * externally provided {@link OnProjectionStateChangeListener} objects.
+ */
+ @GuardedBy("mLock")
+ private final Map<OnProjectionStateChangeListener, InnerListener>
+ mProjectionStateListenerMap = new ArrayMap<>();
+
+ /**
+ * Resource manager that prevents memory leakage of Contexts via binder objects if clients
+ * fail to remove listeners.
+ */
+ @GuardedBy("mLock")
+ private final OnProjectionStateChangeListenerResourceManager
+ mOnProjectionStateChangeListenerResourceManager =
+ new OnProjectionStateChangeListenerResourceManager();
+
@UnsupportedAppUsage
/*package*/ UiModeManager() throws ServiceNotFoundException {
this(null /* context */);
@@ -251,7 +301,7 @@ public class UiModeManager {
public static final int ENABLE_CAR_MODE_ALLOW_SLEEP = 0x0002;
/** @hide */
- @IntDef(prefix = { "ENABLE_CAR_MODE_" }, value = {
+ @IntDef(prefix = {"ENABLE_CAR_MODE_"}, value = {
ENABLE_CAR_MODE_GO_CAR_HOME,
ENABLE_CAR_MODE_ALLOW_SLEEP
})
@@ -362,7 +412,7 @@ public class UiModeManager {
*/
@SystemApi
public static final int DEFAULT_PRIORITY = 0;
-
+
/**
* Turn off special mode if currently in car mode.
* @param flags One of the disable car mode flags.
@@ -595,4 +645,269 @@ public class UiModeManager {
}
}
+ /**
+ * Indicates no projection type. Can be used to compare with the {@link ProjectionType} in
+ * {@link OnProjectionStateChangeListener#onProjectionStateChanged(int, Set)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int PROJECTION_TYPE_NONE = 0x0000;
+ /**
+ * Automotive projection prevents degradation of GPS to save battery, routes incoming calls to
+ * the automotive role holder, etc. For use with {@link #requestProjection(int)} and
+ * {@link #clearProjectionState(int)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int PROJECTION_TYPE_AUTOMOTIVE = 0x0001;
+ /**
+ * Indicates all projection types. For use with
+ * {@link #addOnProjectionStateChangeListener(int, Executor, OnProjectionStateChangeListener)}
+ * and {@link #getProjectingPackages(int)}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int PROJECTION_TYPE_ALL = 0xffff;
+
+ /** @hide */
+ @IntDef(prefix = {"PROJECTION_TYPE_"}, value = {
+ PROJECTION_TYPE_NONE,
+ PROJECTION_TYPE_AUTOMOTIVE,
+ PROJECTION_TYPE_ALL,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProjectionType {
+ }
+
+ /**
+ * Sets the given {@link ProjectionType}.
+ *
+ * Caller must have {@link android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION} if
+ * argument is {@link #PROJECTION_TYPE_AUTOMOTIVE}.
+ * @param projectionType the type of projection to request. This must be a single
+ * {@link ProjectionType} and cannot be a bitmask.
+ * @return true if the projection was successfully set
+ * @throws IllegalArgumentException if passed {@link #PROJECTION_TYPE_NONE},
+ * {@link #PROJECTION_TYPE_ALL}, or any combination of more than one {@link ProjectionType}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(value = android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION,
+ conditional = true)
+ public boolean requestProjection(@ProjectionType int projectionType) {
+ if (mService != null) {
+ try {
+ return mService.requestProjection(new Binder(), projectionType,
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Releases the given {@link ProjectionType}.
+ *
+ * Caller must have {@link android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION} if
+ * argument is {@link #PROJECTION_TYPE_AUTOMOTIVE}.
+ * @param projectionType the type of projection to release. This must be a single
+ * {@link ProjectionType} and cannot be a bitmask.
+ * @return true if the package had set projection and it was successfully released
+ * @throws IllegalArgumentException if passed {@link #PROJECTION_TYPE_NONE},
+ * {@link #PROJECTION_TYPE_ALL}, or any combination of more than one {@link ProjectionType}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(value = android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION,
+ conditional = true)
+ public boolean releaseProjection(@ProjectionType int projectionType) {
+ if (mService != null) {
+ try {
+ return mService.releaseProjection(projectionType, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Gets the packages that are currently projecting.
+ *
+ * @param projectionType the {@link ProjectionType}s to consider when computing which packages
+ * are projecting. Use {@link #PROJECTION_TYPE_ALL} to get all projecting
+ * packages.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE)
+ @NonNull
+ public Set<String> getProjectingPackages(@ProjectionType int projectionType) {
+ if (mService != null) {
+ try {
+ return new ArraySet<>(mService.getProjectingPackages(projectionType));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return Set.of();
+ }
+
+ /**
+ * Gets the {@link ProjectionType}s that are currently active.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE)
+ public @ProjectionType int getActiveProjectionTypes() {
+ if (mService != null) {
+ try {
+ return mService.getActiveProjectionTypes();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return PROJECTION_TYPE_NONE;
+ }
+
+ /**
+ * Configures the listener to receive callbacks when the packages projecting using the given
+ * {@link ProjectionType}s change.
+ *
+ * @param projectionType one or more {@link ProjectionType}s to listen for changes regarding
+ * @param executor an {@link Executor} on which to invoke the callbacks
+ * @param listener the {@link OnProjectionStateChangeListener} to add
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE)
+ public void addOnProjectionStateChangeListener(@ProjectionType int projectionType,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnProjectionStateChangeListener listener) {
+ synchronized (mLock) {
+ if (mProjectionStateListenerMap.containsKey(listener)) {
+ Slog.i(TAG, "Attempted to add listener that was already added.");
+ return;
+ }
+ if (mService != null) {
+ InnerListener innerListener = new InnerListener(executor, listener,
+ mOnProjectionStateChangeListenerResourceManager);
+ try {
+ mService.addOnProjectionStateChangeListener(innerListener, projectionType);
+ mProjectionStateListenerMap.put(listener, innerListener);
+ } catch (RemoteException e) {
+ mOnProjectionStateChangeListenerResourceManager.remove(innerListener);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes the listener so it stops receiving updates for all {@link ProjectionType}s.
+ *
+ * @param listener the {@link OnProjectionStateChangeListener} to remove
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE)
+ public void removeOnProjectionStateChangeListener(
+ @NonNull OnProjectionStateChangeListener listener) {
+ synchronized (mLock) {
+ InnerListener innerListener = mProjectionStateListenerMap.get(listener);
+ if (innerListener == null) {
+ Slog.i(TAG, "Attempted to remove listener that was not added.");
+ return;
+ }
+ if (mService != null) {
+ try {
+ mService.removeOnProjectionStateChangeListener(innerListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ mProjectionStateListenerMap.remove(listener);
+ mOnProjectionStateChangeListenerResourceManager.remove(innerListener);
+ }
+ }
+
+ private static class InnerListener extends IOnProjectionStateChangeListener.Stub {
+ private final WeakReference<OnProjectionStateChangeListenerResourceManager>
+ mResourceManager;
+
+ private InnerListener(@NonNull Executor executor,
+ @NonNull OnProjectionStateChangeListener outerListener,
+ @NonNull OnProjectionStateChangeListenerResourceManager resourceManager) {
+ resourceManager.put(this, executor, outerListener);
+ mResourceManager = new WeakReference<>(resourceManager);
+ }
+
+ @Override
+ public void onProjectionStateChanged(int activeProjectionTypes,
+ List<String> projectingPackages) {
+ OnProjectionStateChangeListenerResourceManager resourceManager = mResourceManager.get();
+ if (resourceManager == null) {
+ Slog.w(TAG, "Can't execute onProjectionStateChanged, resource manager is gone.");
+ return;
+ }
+
+ OnProjectionStateChangeListener outerListener = resourceManager.getOuterListener(this);
+ Executor executor = resourceManager.getExecutor(this);
+ if (outerListener == null || executor == null) {
+ Slog.w(TAG, "Can't execute onProjectionStatechanged, references are null.");
+ return;
+ }
+
+ executor.execute(PooledLambda.obtainRunnable(
+ OnProjectionStateChangeListener::onProjectionStateChanged,
+ outerListener,
+ activeProjectionTypes,
+ new ArraySet<>(projectingPackages)).recycleOnUse());
+ }
+ }
+
+ /**
+ * Wrapper class that ensures we don't leak {@link Activity} or other large {@link Context} in
+ * which this {@link UiModeManager} resides if/when it ends without unregistering associated
+ * {@link OnProjectionStateChangeListener}s.
+ */
+ private static class OnProjectionStateChangeListenerResourceManager {
+ private final Map<InnerListener, OnProjectionStateChangeListener> mOuterListenerMap =
+ new ArrayMap<>(1);
+ private final Map<InnerListener, Executor> mExecutorMap = new ArrayMap<>(1);
+
+ void put(@NonNull InnerListener innerListener, @NonNull Executor executor,
+ OnProjectionStateChangeListener outerListener) {
+ mOuterListenerMap.put(innerListener, outerListener);
+ mExecutorMap.put(innerListener, executor);
+ }
+
+ void remove(InnerListener innerListener) {
+ mOuterListenerMap.remove(innerListener);
+ mExecutorMap.remove(innerListener);
+ }
+
+ OnProjectionStateChangeListener getOuterListener(@NonNull InnerListener innerListener) {
+ return mOuterListenerMap.get(innerListener);
+ }
+
+ Executor getExecutor(@NonNull InnerListener innerListener) {
+ return mExecutorMap.get(innerListener);
+ }
+ }
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 224e3a8df5ef..16ae081049ef 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -122,6 +122,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
+// TODO(b/172376923) - add CarDevicePolicyManager examples below (or remove reference to it).
/**
* Public interface for managing policies enforced on a device. Most clients of this class must be
* registered with the system as a <a href="{@docRoot}guide/topics/admin/device-admin.html">device
@@ -130,6 +131,13 @@ import java.util.concurrent.Executor;
* for that method specifies that it is restricted to either device or profile owners. Any
* application calling an api may only pass as an argument a device administrator component it
* owns. Otherwise, a {@link SecurityException} will be thrown.
+ *
+ * <p><b>Note: </b>on
+ * {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}, some methods can
+ * throw an {@link UnsafeStateException} exception (for example, if the vehicle is moving), so
+ * callers running on automotive builds should wrap every method call under the methods provided by
+ * {@code android.car.admin.CarDevicePolicyManager}.
+ *
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>
@@ -525,7 +533,7 @@ public class DevicePolicyManager {
* @hide
*/
public static final String ACTION_REMOTE_BUGREPORT_DISPATCH =
- "com.android.server.action.REMOTE_BUGREPORT_DISPATCH";
+ "android.intent.action.REMOTE_BUGREPORT_DISPATCH";
/**
* Extra for shared bugreport's SHA-256 hash.
@@ -1972,6 +1980,7 @@ public class DevicePolicyManager {
public static final int CODE_CANNOT_ADD_MANAGED_PROFILE = 11;
/**
+ * TODO (b/137101239): clean up split system user codes
* Result code for {@link #checkProvisioningPreCondition}.
*
* <p>Returned for {@link #ACTION_PROVISION_MANAGED_USER} and
@@ -1995,6 +2004,7 @@ public class DevicePolicyManager {
public static final int CODE_DEVICE_ADMIN_NOT_SUPPORTED = 13;
/**
+ * TODO (b/137101239): clean up split system user codes
* Result code for {@link #checkProvisioningPreCondition}.
*
* <p>Returned for {@link #ACTION_PROVISION_MANAGED_PROFILE} when the device the user is a
@@ -2443,6 +2453,19 @@ public class DevicePolicyManager {
@Retention(RetentionPolicy.SOURCE)
public @interface PersonalAppsSuspensionReason {}
+ /** @hide */
+ @TestApi
+ public static final int OPERATION_LOCK_NOW = 1;
+
+ // TODO(b/172376923) - add all operations
+ /** @hide */
+ @IntDef(prefix = "OPERATION_", value = {
+ OPERATION_LOCK_NOW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public static @interface DevicePolicyOperation {
+ }
+
/**
* Return true if the given administrator component is currently active (enabled) in the system.
*
@@ -2729,6 +2752,9 @@ public class DevicePolicyManager {
* {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
* profile.
*
+ * <p><strong>Note:</strong> Specifying password requirements using this method clears the
+ * password complexity requirements set using {@link #setRequiredPasswordComplexity(int)}.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param quality The new desired quality. One of {@link #PASSWORD_QUALITY_UNSPECIFIED},
* {@link #PASSWORD_QUALITY_BIOMETRIC_WEAK},
@@ -3607,13 +3633,18 @@ public class DevicePolicyManager {
* <p>Note that when called from a profile which uses an unified challenge with its parent, the
* screen lock complexity of the parent will be returned.
*
+ * <p>Apps need the {@link permission#REQUEST_PASSWORD_COMPLEXITY} permission to call this
+ * method. On Android {@link android.os.Build.VERSION_CODES#S} and above, the calling
+ * application does not need this permission if it is a device owner or a profile owner.
+ *
* <p>This method can be called on the {@link DevicePolicyManager} instance
* returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
* restrictions on the parent profile.
*
* @throws IllegalStateException if the user is not unlocked.
* @throws SecurityException if the calling application does not have the permission
- * {@link permission#REQUEST_PASSWORD_COMPLEXITY}
+ * {@link permission#REQUEST_PASSWORD_COMPLEXITY}, and is not a
+ * device owner or a profile owner.
*/
@PasswordComplexity
@RequiresPermission(android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY)
@@ -3630,6 +3661,66 @@ public class DevicePolicyManager {
}
/**
+ * Sets a password complexity requirement for the user's screen lock.
+ * The complexity level is one of the pre-defined levels.
+ *
+ * <p>Note that when called on a profile which uses an unified challenge with its parent, the
+ * complexity would apply to the unified challenge.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to set
+ * restrictions on the parent profile.
+ *
+ * <p><strong>Note:</strong> Specifying password requirements using this method clears any
+ * password requirements set using the obsolete {@link #setPasswordQuality(ComponentName, int)}
+ * and any of its associated methods.
+ *
+ * @throws SecurityException if the calling application is not a device owner or a profile
+ * owner.
+ * @throws IllegalArgumentException if the complexity level is not one of the four above.
+ */
+ public void setRequiredPasswordComplexity(@PasswordComplexity int passwordComplexity) {
+ if (mService == null) {
+ return;
+ }
+
+ try {
+ mService.setRequiredPasswordComplexity(passwordComplexity, mParentInstance);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
+ * Gets the password complexity requirement set by {@link #setRequiredPasswordComplexity(int)},
+ * for the current user.
+ *
+ * <p>The difference between this method and {@link #getPasswordComplexity()} is that this
+ * method simply returns the value set by {@link #setRequiredPasswordComplexity(int)} while
+ * {@link #getPasswordComplexity()} returns the complexity of the actual password.
+ *
+ * <p>This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to get
+ * restrictions on the parent profile.
+ *
+ * @throws SecurityException if the calling application is not a device owner or a profile
+ * owner.
+ */
+ @PasswordComplexity
+ public int getRequiredPasswordComplexity() {
+ if (mService == null) {
+ return PASSWORD_COMPLEXITY_NONE;
+ }
+
+ try {
+ return mService.getRequiredPasswordComplexity(mParentInstance);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* When called by a profile owner of a managed profile returns true if the profile uses unified
* challenge with its parent user.
*
@@ -4271,6 +4362,9 @@ public class DevicePolicyManager {
* This method can be called on the {@link DevicePolicyManager} instance returned by
* {@link #getParentProfileInstance(ComponentName)} in order to lock the parent profile.
* <p>
+ * NOTE: on {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}, this
+ * method doesn't turn off the screen as it would be a driving safety distraction.
+ * <p>
* Equivalent to calling {@link #lockNow(int)} with no flags.
*
* @throws SecurityException if the calling application does not own an active administrator
@@ -4314,6 +4408,9 @@ public class DevicePolicyManager {
* Calling the method twice in this order ensures that all users are locked and does not
* stop the device admin on the managed profile from issuing a second call to lock its own
* profile.
+ * <p>
+ * NOTE: on {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}, this
+ * method doesn't turn off the screen as it would be a driving safety distraction.
*
* @param flags May be 0 or {@link #FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY}.
* @throws SecurityException if the calling application does not own an active administrator
@@ -6679,7 +6776,7 @@ public class DevicePolicyManager {
* @hide
*/
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public boolean isDeviceManaged() {
try {
return mService.hasDeviceOwner();
@@ -6990,7 +7087,7 @@ public class DevicePolicyManager {
throwIfParentInstance("isProfileOwnerApp");
if (mService != null) {
try {
- ComponentName profileOwner = mService.getProfileOwner(myUserId());
+ ComponentName profileOwner = mService.getProfileOwnerAsUser(myUserId());
return profileOwner != null
&& profileOwner.getPackageName().equals(packageName);
} catch (RemoteException re) {
@@ -9981,6 +10078,8 @@ public class DevicePolicyManager {
* <li>{@link #getRequiredStrongAuthTimeout}</li>
* <li>{@link #setRequiredStrongAuthTimeout}</li>
* <li>{@link #getAccountTypesWithManagementDisabled}</li>
+ * <li>{@link #setRequiredPasswordComplexity(int)} </li>
+ * <li>{@link #getRequiredPasswordComplexity()}</li>
* </ul>
* <p>
* The following methods are supported for the parent instance but can only be called by the
@@ -10388,7 +10487,7 @@ public class DevicePolicyManager {
* @hide
*/
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public @Nullable CharSequence getDeviceOwnerOrganizationName() {
try {
return mService.getDeviceOwnerOrganizationName();
diff --git a/core/java/android/app/admin/DevicePolicySafetyChecker.java b/core/java/android/app/admin/DevicePolicySafetyChecker.java
new file mode 100644
index 000000000000..1f8a9335b9ac
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicySafetyChecker.java
@@ -0,0 +1,42 @@
+/*
+ * 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.admin;
+
+import android.annotation.NonNull;
+import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
+
+/**
+ * Interface responsible to check if a {@link DevicePolicyManager} API can be safely executed.
+ *
+ * @hide
+ */
+public interface DevicePolicySafetyChecker {
+
+ /**
+ * Returns whether the given {@code operation} can be safely executed at the moment.
+ */
+ default boolean isDevicePolicyOperationSafe(@DevicePolicyOperation int operation) {
+ return true;
+ }
+
+ /**
+ * Returns a new exception for when the given {@code operation} cannot be safely executed.
+ */
+ @NonNull
+ default UnsafeStateException newUnsafeStateException(@DevicePolicyOperation int operation) {
+ return new UnsafeStateException(operation);
+ }
+}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 60dce22f35e5..58368bc3779a 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -87,6 +87,8 @@ interface IDevicePolicyManager {
boolean isProfileActivePasswordSufficientForParent(int userHandle);
boolean isPasswordSufficientAfterProfileUnification(int userHandle, int profileUser);
int getPasswordComplexity(boolean parent);
+ void setRequiredPasswordComplexity(int passwordComplexity, boolean parent);
+ int getRequiredPasswordComplexity(boolean parent);
boolean isUsingUnifiedPassword(in ComponentName admin);
int getCurrentFailedPasswordAttempts(int userHandle, boolean parent);
int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent);
@@ -156,7 +158,6 @@ interface IDevicePolicyManager {
boolean setProfileOwner(in ComponentName who, String ownerName, int userHandle);
ComponentName getProfileOwnerAsUser(int userHandle);
- ComponentName getProfileOwner(int userHandle);
ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent(in UserHandle userHandle);
String getProfileOwnerName(int userHandle);
void setProfileEnabled(in ComponentName who);
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index 20a60bbe0974..c95a74e0f333 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -407,11 +407,6 @@ public final class PasswordMetrics implements Parcelable {
}
@Override
- boolean allowsNumericPassword() {
- return false;
- }
-
- @Override
boolean allowsCredType(int credType) {
return credType == CREDENTIAL_TYPE_PASSWORD;
}
@@ -428,11 +423,6 @@ public final class PasswordMetrics implements Parcelable {
}
@Override
- boolean allowsNumericPassword() {
- return false;
- }
-
- @Override
boolean allowsCredType(int credType) {
return credType == CREDENTIAL_TYPE_PASSWORD;
}
@@ -449,11 +439,6 @@ public final class PasswordMetrics implements Parcelable {
}
@Override
- boolean allowsNumericPassword() {
- return true;
- }
-
- @Override
boolean allowsCredType(int credType) {
return credType != CREDENTIAL_TYPE_NONE;
}
@@ -470,11 +455,6 @@ public final class PasswordMetrics implements Parcelable {
}
@Override
- boolean allowsNumericPassword() {
- return true;
- }
-
- @Override
boolean allowsCredType(int credType) {
return true;
}
@@ -484,7 +464,6 @@ public final class PasswordMetrics implements Parcelable {
abstract boolean canHaveSequence();
abstract int getMinimumLength(boolean containsNonNumeric);
- abstract boolean allowsNumericPassword();
abstract boolean allowsCredType(int credType);
ComplexityBucket(int complexityLevel) {
@@ -591,7 +570,14 @@ public final class PasswordMetrics implements Parcelable {
result.add(new PasswordValidationError(TOO_LONG, MAX_PASSWORD_LENGTH));
}
- final PasswordMetrics minMetrics = applyComplexity(adminMetrics, isPin, bucket);
+ // A flag indicating whether the provided password already has non-numeric characters in
+ // it or if the admin imposes the requirement of any non-numeric characters.
+ final boolean hasOrWouldNeedNonNumeric =
+ actualMetrics.nonNumeric > 0 || adminMetrics.nonNumeric > 0
+ || adminMetrics.letters > 0 || adminMetrics.lowerCase > 0
+ || adminMetrics.upperCase > 0 || adminMetrics.symbols > 0;
+ final PasswordMetrics minMetrics =
+ applyComplexity(adminMetrics, hasOrWouldNeedNonNumeric, bucket);
// Clamp required length between maximum and minimum valid values.
minMetrics.length = Math.min(MAX_PASSWORD_LENGTH,
@@ -684,23 +670,23 @@ public final class PasswordMetrics implements Parcelable {
* TODO: move to PasswordPolicy
*/
public static PasswordMetrics applyComplexity(
- PasswordMetrics adminMetrics, boolean isPin, int complexity) {
- return applyComplexity(adminMetrics, isPin, ComplexityBucket.forComplexity(complexity));
+ PasswordMetrics adminMetrics, boolean withNonNumericCharacters,
+ int complexity) {
+ return applyComplexity(adminMetrics, withNonNumericCharacters,
+ ComplexityBucket.forComplexity(complexity));
}
private static PasswordMetrics applyComplexity(
- PasswordMetrics adminMetrics, boolean isPin, ComplexityBucket bucket) {
+ PasswordMetrics adminMetrics, boolean withNonNumericCharacters,
+ ComplexityBucket bucket) {
final PasswordMetrics minMetrics = new PasswordMetrics(adminMetrics);
if (!bucket.canHaveSequence()) {
minMetrics.seqLength = Math.min(minMetrics.seqLength, MAX_ALLOWED_SEQUENCE);
}
- minMetrics.length = Math.max(minMetrics.length, bucket.getMinimumLength(!isPin));
-
- if (!isPin && !bucket.allowsNumericPassword()) {
- minMetrics.nonNumeric = Math.max(minMetrics.nonNumeric, 1);
- }
+ minMetrics.length = Math.max(minMetrics.length,
+ bucket.getMinimumLength(withNonNumericCharacters));
return minMetrics;
}
diff --git a/core/java/android/app/admin/UnsafeStateException.java b/core/java/android/app/admin/UnsafeStateException.java
new file mode 100644
index 000000000000..9dcaae42e96e
--- /dev/null
+++ b/core/java/android/app/admin/UnsafeStateException.java
@@ -0,0 +1,74 @@
+/*
+ * 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.admin;
+
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Exception thrown when a {@link DevicePolicyManager} operation failed because it was not safe
+ * to be executed at that moment.
+ *
+ * <p>For example, it can be thrown on
+ * {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive devices} when the vehicle
+ * is moving.
+ */
+@SuppressWarnings("serial")
+public final class UnsafeStateException extends IllegalStateException implements Parcelable {
+
+ private final @DevicePolicyOperation int mOperation;
+
+ /** @hide */
+ public UnsafeStateException(@DevicePolicyOperation int operation) {
+ super();
+
+ mOperation = operation;
+ }
+
+ /** @hide */
+ @TestApi
+ public @DevicePolicyOperation int getOperation() {
+ return mOperation;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mOperation);
+ }
+
+ @NonNull
+ public static final Creator<UnsafeStateException> CREATOR =
+ new Creator<UnsafeStateException>() {
+
+ @Override
+ public UnsafeStateException createFromParcel(Parcel source) {
+ return new UnsafeStateException(source.readInt());
+ }
+
+ @Override
+ public UnsafeStateException[] newArray(int size) {
+ return new UnsafeStateException[size];
+ }
+ };
+}
diff --git a/core/java/android/app/backup/OWNERS b/core/java/android/app/backup/OWNERS
index 7e7710b4d550..0f888113d730 100644
--- a/core/java/android/app/backup/OWNERS
+++ b/core/java/android/app/backup/OWNERS
@@ -1,4 +1,4 @@
# Bug component: 656484
-include platform/frameworks/base/services/backup:/OWNERS
+include platform/frameworks/base:/services/backup/OWNERS
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 8170bf92ae1e..57b0828b334c 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -16,8 +16,11 @@
package android.companion;
+import static com.android.internal.util.CollectionUtils.emptyIfNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringDef;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -25,7 +28,7 @@ import android.os.Parcelable;
import android.provider.OneTimeUseBuilder;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.DataClass;
import java.util.ArrayList;
import java.util.List;
@@ -43,23 +46,66 @@ import java.util.Objects;
* You can also set {@link Builder#setSingleDevice single device} to request a popup with single
* device to be shown instead of a list to choose from
*/
+@DataClass(
+ genToString = true,
+ genEqualsHashCode = true,
+ genHiddenGetters = true,
+ genParcelable = true,
+ genHiddenConstructor = true,
+ genBuilder = false)
public final class AssociationRequest implements Parcelable {
- private final boolean mSingleDevice;
- private final List<DeviceFilter<?>> mDeviceFilters;
- private String mCallingPackage;
+ /**
+ * Device profile: watch.
+ *
+ * @see AssociationRequest.Builder#setDeviceProfile
+ */
+ public static final String DEVICE_PROFILE_WATCH =
+ "android.app.role.COMPANION_DEVICE_WATCH";
- private AssociationRequest(
- boolean singleDevice, @Nullable List<DeviceFilter<?>> deviceFilters) {
- this.mSingleDevice = singleDevice;
- this.mDeviceFilters = CollectionUtils.emptyIfNull(deviceFilters);
+ /** @hide */
+ @StringDef(value = { DEVICE_PROFILE_WATCH })
+ public @interface DeviceProfile {}
+
+ /**
+ * Whether only a single device should match the provided filter.
+ *
+ * When scanning for a single device with a specifc {@link BluetoothDeviceFilter} mac
+ * address, bonded devices are also searched among. This allows to obtain the necessary app
+ * privileges even if the device is already paired.
+ */
+ private boolean mSingleDevice = false;
+
+ /**
+ * If set, only devices matching either of the given filters will be shown to the user
+ */
+ @DataClass.PluralOf("deviceFilter")
+ private @NonNull List<DeviceFilter<?>> mDeviceFilters = new ArrayList<>();
+
+ /**
+ * If set, association will be requested as a corresponding kind of device
+ */
+ private @Nullable @DeviceProfile String mDeviceProfile = null;
+
+ /**
+ * The app package making the request.
+ *
+ * Populated by the system.
+ *
+ * @hide
+ */
+ private @Nullable String mCallingPackage = null;
+
+ /** @hide */
+ public void setCallingPackage(@NonNull String pkg) {
+ mCallingPackage = pkg;
}
- private AssociationRequest(Parcel in) {
- this(
- in.readByte() != 0,
- in.readParcelableList(new ArrayList<>(), AssociationRequest.class.getClassLoader()));
- setCallingPackage(in.readString());
+ private void onConstructed() {
+ if (mDeviceProfile != null
+ && !Objects.equals(mDeviceProfile, DEVICE_PROFILE_WATCH)) {
+ throw new IllegalArgumentException("Invalid device profile: " + mDeviceProfile);
+ }
}
/** @hide */
@@ -75,70 +121,13 @@ public final class AssociationRequest implements Parcelable {
return mDeviceFilters;
}
- /** @hide */
- public String getCallingPackage() {
- return mCallingPackage;
- }
-
- /** @hide */
- public void setCallingPackage(String pkg) {
- mCallingPackage = pkg;
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- AssociationRequest that = (AssociationRequest) o;
- return mSingleDevice == that.mSingleDevice
- && Objects.equals(mDeviceFilters, that.mDeviceFilters)
- && Objects.equals(mCallingPackage, that.mCallingPackage);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mSingleDevice, mDeviceFilters, mCallingPackage);
- }
-
- @Override
- public String toString() {
- return "AssociationRequest{"
- + "mSingleDevice=" + mSingleDevice
- + ", mDeviceFilters=" + mDeviceFilters
- + ", mCallingPackage=" + mCallingPackage
- + '}';
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeByte((byte) (mSingleDevice ? 1 : 0));
- dest.writeParcelableList(mDeviceFilters, flags);
- dest.writeString(mCallingPackage);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Creator<AssociationRequest> CREATOR = new Creator<AssociationRequest>() {
- @Override
- public AssociationRequest createFromParcel(Parcel in) {
- return new AssociationRequest(in);
- }
-
- @Override
- public AssociationRequest[] newArray(int size) {
- return new AssociationRequest[size];
- }
- };
-
/**
* A builder for {@link AssociationRequest}
*/
public static final class Builder extends OneTimeUseBuilder<AssociationRequest> {
private boolean mSingleDevice = false;
@Nullable private ArrayList<DeviceFilter<?>> mDeviceFilters = null;
+ private @Nullable String mDeviceProfile = null;
public Builder() {}
@@ -172,12 +161,219 @@ public final class AssociationRequest implements Parcelable {
return this;
}
+ /**
+ * If set, association will be requested as a corresponding kind of device
+ */
+ @NonNull
+ public Builder setDeviceProfile(@NonNull @DeviceProfile String deviceProfile) {
+ checkNotUsed();
+ mDeviceProfile = deviceProfile;
+ return this;
+ }
+
/** @inheritDoc */
@NonNull
@Override
public AssociationRequest build() {
markUsed();
- return new AssociationRequest(mSingleDevice, mDeviceFilters);
+ return new AssociationRequest(
+ mSingleDevice, emptyIfNull(mDeviceFilters),
+ mDeviceProfile, null);
}
}
+
+
+
+
+ // Code below generated by codegen v1.0.20.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/companion/AssociationRequest.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new AssociationRequest.
+ *
+ * @param singleDevice
+ * Whether only a single device should match the provided filter.
+ *
+ * When scanning for a single device with a specifc {@link BluetoothDeviceFilter} mac
+ * address, bonded devices are also searched among. This allows to obtain the necessary app
+ * privileges even if the device is already paired.
+ * @param deviceFilters
+ * If set, only devices matching either of the given filters will be shown to the user
+ * @param deviceProfile
+ * If set, association will be requested as a corresponding kind of device
+ * @param callingPackage
+ * The app package making the request.
+ *
+ * Populated by the system.
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public AssociationRequest(
+ boolean singleDevice,
+ @NonNull List<DeviceFilter<?>> deviceFilters,
+ @Nullable @DeviceProfile String deviceProfile,
+ @Nullable String callingPackage) {
+ this.mSingleDevice = singleDevice;
+ this.mDeviceFilters = deviceFilters;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mDeviceFilters);
+ this.mDeviceProfile = deviceProfile;
+ com.android.internal.util.AnnotationValidations.validate(
+ DeviceProfile.class, null, mDeviceProfile);
+ this.mCallingPackage = callingPackage;
+
+ onConstructed();
+ }
+
+ /**
+ * If set, association will be requested as a corresponding kind of device
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public @Nullable @DeviceProfile String getDeviceProfile() {
+ return mDeviceProfile;
+ }
+
+ /**
+ * The app package making the request.
+ *
+ * Populated by the system.
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public @Nullable String getCallingPackage() {
+ return mCallingPackage;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "AssociationRequest { " +
+ "singleDevice = " + mSingleDevice + ", " +
+ "deviceFilters = " + mDeviceFilters + ", " +
+ "deviceProfile = " + mDeviceProfile + ", " +
+ "callingPackage = " + mCallingPackage +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(AssociationRequest other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ AssociationRequest that = (AssociationRequest) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && mSingleDevice == that.mSingleDevice
+ && Objects.equals(mDeviceFilters, that.mDeviceFilters)
+ && Objects.equals(mDeviceProfile, that.mDeviceProfile)
+ && Objects.equals(mCallingPackage, that.mCallingPackage);
+ }
+
+ @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 + Boolean.hashCode(mSingleDevice);
+ _hash = 31 * _hash + Objects.hashCode(mDeviceFilters);
+ _hash = 31 * _hash + Objects.hashCode(mDeviceProfile);
+ _hash = 31 * _hash + Objects.hashCode(mCallingPackage);
+ return _hash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ byte flg = 0;
+ if (mSingleDevice) flg |= 0x1;
+ if (mDeviceProfile != null) flg |= 0x4;
+ if (mCallingPackage != null) flg |= 0x8;
+ dest.writeByte(flg);
+ dest.writeParcelableList(mDeviceFilters, flags);
+ if (mDeviceProfile != null) dest.writeString(mDeviceProfile);
+ if (mCallingPackage != null) dest.writeString(mCallingPackage);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ AssociationRequest(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ byte flg = in.readByte();
+ boolean singleDevice = (flg & 0x1) != 0;
+ List<DeviceFilter<?>> deviceFilters = new ArrayList<>();
+ in.readParcelableList(deviceFilters, DeviceFilter.class.getClassLoader());
+ String deviceProfile = (flg & 0x4) == 0 ? null : in.readString();
+ String callingPackage = (flg & 0x8) == 0 ? null : in.readString();
+
+ this.mSingleDevice = singleDevice;
+ this.mDeviceFilters = deviceFilters;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mDeviceFilters);
+ this.mDeviceProfile = deviceProfile;
+ com.android.internal.util.AnnotationValidations.validate(
+ DeviceProfile.class, null, mDeviceProfile);
+ this.mCallingPackage = callingPackage;
+
+ onConstructed();
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<AssociationRequest> CREATOR
+ = new Parcelable.Creator<AssociationRequest>() {
+ @Override
+ public AssociationRequest[] newArray(int size) {
+ return new AssociationRequest[size];
+ }
+
+ @Override
+ public AssociationRequest createFromParcel(@NonNull Parcel in) {
+ return new AssociationRequest(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1604534468409L,
+ codegenVersion = "1.0.20",
+ sourceFile = "frameworks/base/core/java/android/companion/AssociationRequest.java",
+ inputSignatures = "public static final java.lang.String DEVICE_PROFILE_WATCH\nprivate boolean mSingleDevice\nprivate @com.android.internal.util.DataClass.PluralOf(\"deviceFilter\") @android.annotation.NonNull java.util.List<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable @android.companion.AssociationRequest.DeviceProfile java.lang.String mDeviceProfile\nprivate @android.annotation.Nullable java.lang.String mCallingPackage\npublic void setCallingPackage(java.lang.String)\nprivate void onConstructed()\npublic @android.compat.annotation.UnsupportedAppUsage boolean isSingleDevice()\npublic @android.annotation.NonNull @android.compat.annotation.UnsupportedAppUsage java.util.List<android.companion.DeviceFilter<?>> getDeviceFilters()\nclass AssociationRequest extends java.lang.Object implements [android.os.Parcelable]\nprivate boolean mSingleDevice\nprivate @android.annotation.Nullable java.util.ArrayList<android.companion.DeviceFilter<?>> mDeviceFilters\nprivate @android.annotation.Nullable java.lang.String mDeviceProfile\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setSingleDevice(boolean)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder addDeviceFilter(android.companion.DeviceFilter<?>)\npublic @android.annotation.NonNull android.companion.AssociationRequest.Builder setDeviceProfile(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override android.companion.AssociationRequest build()\nclass Builder extends android.provider.OneTimeUseBuilder<android.companion.AssociationRequest> implements []\n@com.android.internal.util.DataClass(genToString=true, genEqualsHashCode=true, genHiddenGetters=true, genParcelable=true, genHiddenConstructor=true, genBuilder=false)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
}
diff --git a/core/java/android/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java
new file mode 100644
index 000000000000..56639ea36bf6
--- /dev/null
+++ b/core/java/android/companion/CompanionDeviceService.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.companion;
+
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.internal.util.function.pooled.PooledLambda;
+
+import java.util.Objects;
+
+/**
+ * Service to be implemented by apps that manage a companion device.
+ *
+ * System will keep this service bound whenever an associated device is nearby,
+ * ensuring app stays alive.
+ *
+ * An app must be {@link CompanionDeviceManager#associate associated} with at leas one device,
+ * before it can take advantage of this service.
+ *
+ * You must declare this service in your manifest with an
+ * intent-filter action of {@link #SERVICE_INTERFACE} and
+ * permission of {@link android.Manifest.permission#BIND_COMPANION_DEVICE_SERVICE}
+ */
+public abstract class CompanionDeviceService extends Service {
+
+ private static final String LOG_TAG = "CompanionDeviceService";
+
+ /**
+ * An intent action for a service to be bound whenever this app's companion device(s)
+ * are nearby.
+ *
+ * <p>The app will be kept alive for as long as the device is nearby.
+ * If the app is not running at the time device gets connected, the app will be woken up.</p>
+ *
+ * <p>Shortly after the device goes out of range, the service will be unbound, and the
+ * app will be eligible for cleanup, unless any other user-visible components are running.</p>
+ *
+ * <p>An app shouldn't declare more than one of these services.
+ * If running in background is not essential for the devices that this app can manage,
+ * app should avoid declaring this service.</p>
+ *
+ * <p>The service must also require permission
+ * {@link android.Manifest.permission#BIND_COMPANION_DEVICE_SERVICE}</p>
+ */
+ public static final String SERVICE_INTERFACE = "android.companion.CompanionDeviceService";
+
+ private final Stub mRemote = new Stub();
+
+ /**
+ * Called by system whenever a device associated with this app is available.
+ *
+ * @param address the MAC address of the device
+ */
+ @MainThread
+ public abstract void onDeviceAppeared(@NonNull String address);
+
+ /**
+ * Called by system whenever a device associated with this app stops being available.
+ *
+ * Usually this means the device goes out of range or is turned off.
+ *
+ * @param address the MAC address of the device
+ */
+ @MainThread
+ public abstract void onDeviceDisappeared(@NonNull String address);
+
+ @Nullable
+ @Override
+ public final IBinder onBind(@NonNull Intent intent) {
+ if (Objects.equals(intent.getAction(), SERVICE_INTERFACE)) {
+ return mRemote;
+ }
+ Log.w(LOG_TAG,
+ "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + "): " + intent);
+ return null;
+ }
+
+ class Stub extends ICompanionDeviceService.Stub {
+
+ @Override
+ public void onDeviceAppeared(String address) {
+ Handler.getMain().sendMessage(PooledLambda.obtainMessage(
+ CompanionDeviceService::onDeviceAppeared,
+ CompanionDeviceService.this, address));
+ }
+
+ @Override
+ public void onDeviceDisappeared(String address) {
+ Handler.getMain().sendMessage(PooledLambda.obtainMessage(
+ CompanionDeviceService::onDeviceDisappeared,
+ CompanionDeviceService.this, address));
+ }
+ }
+}
diff --git a/core/java/android/companion/ICompanionDeviceService.aidl b/core/java/android/companion/ICompanionDeviceService.aidl
new file mode 100644
index 000000000000..f3977ca4af6f
--- /dev/null
+++ b/core/java/android/companion/ICompanionDeviceService.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion;
+
+import android.app.PendingIntent;
+import android.companion.IFindDeviceCallback;
+import android.companion.Association;
+import android.companion.AssociationRequest;
+import android.content.ComponentName;
+
+/** @hide */
+oneway interface ICompanionDeviceService {
+ void onDeviceAppeared(in String address);
+ void onDeviceDisappeared(in String address);
+}
diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java
index 73becb1c0f1c..e3395e20947d 100644
--- a/core/java/android/content/ClipDescription.java
+++ b/core/java/android/content/ClipDescription.java
@@ -74,8 +74,8 @@ public class ClipDescription implements Parcelable {
/**
* The MIME type for a shortcut. The ClipData must include intents with required extras
- * {@link #EXTRA_PENDING_INTENT} and {@link Intent#EXTRA_USER}, and an optional
- * {@link #EXTRA_ACTIVITY_OPTIONS}.
+ * {@link Intent#EXTRA_SHORTCUT_ID}, {@link Intent#EXTRA_PACKAGE_NAME} and
+ * {@link Intent#EXTRA_USER}, and an optional {@link #EXTRA_ACTIVITY_OPTIONS}.
* @hide
*/
public static final String MIMETYPE_APPLICATION_SHORTCUT = "application/vnd.android.shortcut";
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 422d3f7c6784..e35fb037582a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -839,6 +839,7 @@ public abstract class ContentResolver implements ContentInterface {
}
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
protected abstract IContentProvider acquireProvider(Context c, String name);
@@ -855,15 +856,19 @@ public abstract class ContentResolver implements ContentInterface {
}
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract boolean releaseProvider(IContentProvider icp);
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract boolean releaseUnstableProvider(IContentProvider icp);
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void unstableProviderDied(IContentProvider icp);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 46d4f222a6b4..fb1366d6d9ed 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -811,6 +811,7 @@ public abstract class Context {
* case {@link #getOpPackageName()} will be the name of the primary package in
* that process (so that app ops uid verification will work with the name).
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract String getBasePackageName();
@@ -927,6 +928,7 @@ public abstract class Context {
* @see #MODE_PRIVATE
* @removed
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract SharedPreferences getSharedPreferences(File file, @PreferencesMode int mode);
/**
@@ -957,6 +959,7 @@ public abstract class Context {
public abstract boolean deleteSharedPreferences(String name);
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void reloadSharedPreferences();
/**
@@ -1045,6 +1048,7 @@ public abstract class Context {
* @see #getSharedPreferences(String, int)
* @removed
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract File getSharedPreferencesPath(String name);
/**
@@ -1516,6 +1520,7 @@ public abstract class Context {
* There is no guarantee when these files will be deleted.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@SystemApi
public abstract File getPreloadsFileCache();
@@ -2184,6 +2189,7 @@ public abstract class Context {
* @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
String[] receiverPermissions);
@@ -2214,6 +2220,7 @@ public abstract class Context {
* @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract void sendBroadcast(Intent intent,
@Nullable String receiverPermission,
@@ -2224,6 +2231,7 @@ public abstract class Context {
* of an associated app op as per {@link android.app.AppOpsManager}.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void sendBroadcast(Intent intent,
String receiverPermission, int appOp);
@@ -2339,6 +2347,7 @@ public abstract class Context {
* @see android.app.Activity#RESULT_OK
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract void sendOrderedBroadcast(@NonNull Intent intent,
@Nullable String receiverPermission, @Nullable Bundle options,
@@ -2351,6 +2360,7 @@ public abstract class Context {
* of an associated app op as per {@link android.app.AppOpsManager}.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void sendOrderedBroadcast(Intent intent,
String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
@@ -2404,6 +2414,7 @@ public abstract class Context {
* @see #sendBroadcast(Intent, String, Bundle)
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract void sendBroadcastAsUser(@RequiresPermission Intent intent,
@@ -2426,6 +2437,7 @@ public abstract class Context {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public abstract void sendBroadcastAsUser(@RequiresPermission Intent intent,
@@ -2472,6 +2484,7 @@ public abstract class Context {
* BroadcastReceiver, Handler, int, String, Bundle)
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
@@ -2485,6 +2498,7 @@ public abstract class Context {
* BroadcastReceiver, Handler, int, String, Bundle)
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
@UnsupportedAppUsage
public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
@@ -2699,6 +2713,7 @@ public abstract class Context {
* @hide
* This is just here for sending CONNECTIVITY_ACTION.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Deprecated
@RequiresPermission(allOf = {
android.Manifest.permission.INTERACT_ACROSS_USERS,
@@ -2989,6 +3004,7 @@ public abstract class Context {
* @see #sendBroadcast
* @see #unregisterReceiver
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@UnsupportedAppUsage
@@ -3099,6 +3115,7 @@ public abstract class Context {
/**
* @hide like {@link #startForegroundService(Intent)} but for a specific user.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract ComponentName startForegroundServiceAsUser(Intent service, UserHandle user);
@@ -3137,6 +3154,7 @@ public abstract class Context {
/**
* @hide like {@link #startService(Intent)} but for a specific user.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
@UnsupportedAppUsage
@@ -3145,6 +3163,7 @@ public abstract class Context {
/**
* @hide like {@link #stopService(Intent)} but for a specific user.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
public abstract boolean stopServiceAsUser(Intent service, UserHandle user);
@@ -5282,6 +5301,7 @@ public abstract class Context {
public abstract int checkPermission(@NonNull String permission, int pid, int uid);
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
@PackageManager.PermissionResult
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public abstract int checkPermission(@NonNull String permission, int pid, int uid,
@@ -5509,6 +5529,7 @@ public abstract class Context {
@Intent.AccessUriMode int modeFlags);
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
@PackageManager.PermissionResult
public abstract int checkUriPermission(Uri uri, int pid, int uid,
@Intent.AccessUriMode int modeFlags, IBinder callerToken);
@@ -5793,6 +5814,7 @@ public abstract class Context {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract Context createApplicationContext(ApplicationInfo application,
@CreatePackageOptions int flags) throws PackageManager.NameNotFoundException;
@@ -6024,6 +6046,7 @@ public abstract class Context {
* @see #isCredentialProtectedStorage()
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract Context createCredentialProtectedStorageContext();
@@ -6036,6 +6059,7 @@ public abstract class Context {
* @return The compatibility info holder, or null if not required by the application.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract DisplayAdjustments getDisplayAdjustments(int displayId);
/**
@@ -6070,12 +6094,14 @@ public abstract class Context {
* @see #getDisplay()
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@TestApi
public abstract int getDisplayId();
/**
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void updateDisplay(int displayId);
/**
@@ -6104,6 +6130,7 @@ public abstract class Context {
* @see #createCredentialProtectedStorageContext()
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract boolean isCredentialProtectedStorage();
@@ -6111,6 +6138,7 @@ public abstract class Context {
* Returns true if the context can load unsafe resources, e.g. fonts.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract boolean canLoadUnsafeResources();
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 782f0cd04dfc..a03bdf2da2be 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2740,6 +2740,7 @@ public class Intent implements Parcelable, Cloneable {
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
+ * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
@@ -2757,6 +2758,7 @@ public class Intent implements Parcelable, Cloneable {
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
+ * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_UNSTARTABLE =
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 1cca53f369fa..81d9b11bc644 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -2101,6 +2101,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
/** @hide */
+ @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public boolean isOem() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
}
@@ -2148,11 +2149,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
/** @hide */
+ @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public boolean isVendor() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
}
/** @hide */
+ @SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public boolean isProduct() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
}
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index fd96e85db3de..82d7b6361738 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.annotation.FloatRange;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -84,16 +85,9 @@ public class LauncherActivityInfo {
}
/**
- * @return whether the package is startable.
- */
- public boolean isStartable() {
- return mInternal.getIncrementalStatesInfo().isStartable();
- }
-
- /**
* @return Package loading progress, range between [0, 1].
*/
- public float getLoadingProgress() {
+ public @FloatRange(from = 0.0, to = 1.0) float getLoadingProgress() {
return mInternal.getIncrementalStatesInfo().getProgress();
}
@@ -136,6 +130,16 @@ public class LauncherActivityInfo {
}
/**
+ * Returns the ActivityInfo of the activity.
+ *
+ * @return Activity Info
+ * @hide
+ */
+ public ActivityInfo getActivityInfo() {
+ return mInternal.getActivityInfo();
+ }
+
+ /**
* Returns the application info for the appliction this activity belongs to.
* @return
*/
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 946c634e3b41..cc484deeee49 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -40,7 +40,7 @@ import android.app.PropertyInvalidatedCache;
import android.app.admin.DevicePolicyManager;
import android.app.usage.StorageStatsManager;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -3765,7 +3765,7 @@ public abstract class PackageManager {
* @hide
*/
@ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.R)
public static final long FILTER_APPLICATION_QUERY = 135549675L;
/** {@hide} */
@@ -3824,18 +3824,21 @@ public abstract class PackageManager {
* Unstartable state with no root cause specified. E.g., data loader seeing missing pages but
* unclear about the cause. This corresponds to a generic alert window shown to the user when
* the user attempts to launch the app.
+ * @hide
*/
public static final int UNSTARTABLE_REASON_UNKNOWN = 0;
/**
* Unstartable state due to connection issues that interrupt package loading.
* This corresponds to an alert window shown to the user indicating connection errors.
+ * @hide
*/
public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1;
/**
* Unstartable state after encountering storage limitations.
* This corresponds to an alert window indicating limited storage.
+ * @hide
*/
public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2;
@@ -3916,6 +3919,7 @@ public abstract class PackageManager {
* found on the system.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
@UnsupportedAppUsage
public abstract PackageInfo getPackageInfoAsUser(@NonNull String packageName,
@@ -3982,6 +3986,7 @@ public abstract class PackageManager {
* does not contain such an activity.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract @Nullable Intent getCarLaunchIntentForPackage(@NonNull String packageName);
/**
@@ -4047,6 +4052,7 @@ public abstract class PackageManager {
* found on the system.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract int getPackageUidAsUser(@NonNull String packageName, @UserIdInt int userId)
throws NameNotFoundException;
@@ -4065,6 +4071,7 @@ public abstract class PackageManager {
* found on the system.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract int getPackageUidAsUser(@NonNull String packageName,
@PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
@@ -4107,6 +4114,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract boolean arePermissionsIndividuallyControlled();
@@ -4115,6 +4123,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract boolean isWirelessConsentModeEnabled();
/**
@@ -4167,6 +4176,7 @@ public abstract class PackageManager {
@ApplicationInfoFlags int flags) throws NameNotFoundException;
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@UnsupportedAppUsage
public abstract ApplicationInfo getApplicationInfoAsUser(@NonNull String packageName,
@@ -4357,6 +4367,7 @@ public abstract class PackageManager {
* deleted with {@code DELETE_KEEP_DATA} flag set).
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@SystemApi
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@@ -4405,6 +4416,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
@NonNull
@TestApi
@@ -4518,6 +4530,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
public abstract void grantRuntimePermission(@NonNull String packageName,
@@ -4544,6 +4557,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
public abstract void revokeRuntimePermission(@NonNull String packageName,
@@ -4588,6 +4602,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
@@ -4610,6 +4625,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
@@ -4885,6 +4901,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract boolean shouldShowRequestPermissionRationale(@NonNull String permName);
@@ -5000,6 +5017,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@TestApi
public abstract @Nullable String[] getNamesForUids(int[] uids);
@@ -5016,6 +5034,7 @@ public abstract class PackageManager {
* found on the system.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract int getUidForSharedUser(@NonNull String sharedUserName)
throws NameNotFoundException;
@@ -5059,6 +5078,7 @@ public abstract class PackageManager {
* deleted with {@code DELETE_KEEP_DATA} flag set).
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@TestApi
public abstract List<ApplicationInfo> getInstalledApplicationsAsUser(
@@ -5071,6 +5091,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(Manifest.permission.ACCESS_INSTANT_APPS)
public abstract @NonNull List<InstantAppInfo> getInstantApps();
@@ -5082,6 +5103,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(Manifest.permission.ACCESS_INSTANT_APPS)
public abstract @Nullable Drawable getInstantAppIcon(String packageName);
@@ -5130,6 +5152,7 @@ public abstract class PackageManager {
* deprecated
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract int getInstantAppCookieMaxSize();
/**
@@ -5187,6 +5210,7 @@ public abstract class PackageManager {
/**
* @removed
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract boolean setInstantAppCookie(@Nullable byte[] cookie);
/**
@@ -5225,6 +5249,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract @NonNull List<SharedLibraryInfo> getSharedLibrariesAsUser(
@InstallFlags int flags, @UserIdInt int userId);
@@ -5237,6 +5262,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@RequiresPermission(Manifest.permission.ACCESS_SHARED_LIBRARIES)
@SystemApi
@@ -5256,6 +5282,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
@TestApi
public abstract @NonNull String getServicesSystemSharedLibraryPackageName();
@@ -5267,6 +5294,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
@TestApi
public abstract @NonNull String getSharedSystemSharedLibraryPackageName();
@@ -5373,6 +5401,7 @@ public abstract class PackageManager {
* containing something else, such as the activity resolver.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@UnsupportedAppUsage
public abstract ResolveInfo resolveActivityAsUser(@NonNull Intent intent,
@@ -5414,6 +5443,7 @@ public abstract class PackageManager {
* empty list is returned.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@UnsupportedAppUsage
public abstract List<ResolveInfo> queryIntentActivitiesAsUser(@NonNull Intent intent,
@@ -5437,6 +5467,7 @@ public abstract class PackageManager {
* empty list is returned.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
@SystemApi
@@ -5499,6 +5530,7 @@ public abstract class PackageManager {
* no matching receivers, an empty list or null is returned.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@SystemApi
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
@@ -5510,6 +5542,7 @@ public abstract class PackageManager {
/**
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@UnsupportedAppUsage
public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(@NonNull Intent intent,
@@ -5548,6 +5581,7 @@ public abstract class PackageManager {
/**
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
public abstract ResolveInfo resolveServiceAsUser(@NonNull Intent intent,
@ResolveInfoFlags int flags, @UserIdInt int userId);
@@ -5580,6 +5614,7 @@ public abstract class PackageManager {
* empty list or null is returned.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@UnsupportedAppUsage
public abstract List<ResolveInfo> queryIntentServicesAsUser(@NonNull Intent intent,
@@ -5618,6 +5653,7 @@ public abstract class PackageManager {
* no matching services, an empty list or null is returned.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@UnsupportedAppUsage
public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
@@ -5685,6 +5721,7 @@ public abstract class PackageManager {
* provider. If a provider was not found, returns null.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@UnsupportedAppUsage
public abstract ProviderInfo resolveContentProviderAsUser(@NonNull String providerName,
@@ -6069,6 +6106,7 @@ public abstract class PackageManager {
* @return the drawable or null if no drawable is required.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@UnsupportedAppUsage
public abstract Drawable getUserBadgeForDensity(@NonNull UserHandle user, int density);
@@ -6087,6 +6125,7 @@ public abstract class PackageManager {
* @return the drawable or null if no drawable is required.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@UnsupportedAppUsage
public abstract Drawable getUserBadgeForDensityNoBackground(@NonNull UserHandle user,
@@ -6225,6 +6264,7 @@ public abstract class PackageManager {
* TODO(b/170852794): mark maxTargetSdk as {@code Build.VERSION_CODES.S}
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170928809,
publicAlternatives = "Use {@code Context#createContextAsUser(UserHandle, int)}"
@@ -6277,6 +6317,7 @@ public abstract class PackageManager {
*
* @deprecated use {@link PackageInstaller#installExistingPackage()} instead.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Deprecated
@SystemApi
public abstract int installExistingPackage(@NonNull String packageName)
@@ -6289,6 +6330,7 @@ public abstract class PackageManager {
*
* @deprecated use {@link PackageInstaller#installExistingPackage()} instead.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Deprecated
@SystemApi
public abstract int installExistingPackage(@NonNull String packageName,
@@ -6301,6 +6343,7 @@ public abstract class PackageManager {
*
* @deprecated use {@link PackageInstaller#installExistingPackage()} instead.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Deprecated
@RequiresPermission(anyOf = {
Manifest.permission.INSTALL_EXISTING_PACKAGES,
@@ -6381,6 +6424,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT)
public abstract void verifyIntentFilter(int verificationId, int verificationCode,
@@ -6406,6 +6450,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
public abstract int getIntentVerificationStatusAsUser(@NonNull String packageName,
@@ -6431,6 +6476,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
public abstract boolean updateIntentVerificationStatusAsUser(@NonNull String packageName,
@@ -6448,6 +6494,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@SystemApi
public abstract List<IntentFilterVerificationInfo> getIntentFilterVerifications(
@@ -6464,6 +6511,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@SystemApi
public abstract List<IntentFilter> getAllIntentFilters(@NonNull String packageName);
@@ -6478,6 +6526,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@SystemApi
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@@ -6495,6 +6544,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(allOf = {
Manifest.permission.SET_PREFERRED_APPLICATIONS,
@@ -6521,6 +6571,7 @@ public abstract class PackageManager {
@Nullable String installerPackageName);
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
public abstract void setUpdateAvailable(@NonNull String packageName, boolean updateAvaialble);
@@ -6541,6 +6592,7 @@ public abstract class PackageManager {
* indicate that no callback is desired.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@RequiresPermission(Manifest.permission.DELETE_PACKAGES)
@UnsupportedAppUsage
public abstract void deletePackage(@NonNull String packageName,
@@ -6561,6 +6613,7 @@ public abstract class PackageManager {
* @param userId The user Id
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@RequiresPermission(anyOf = {
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.INTERACT_ACROSS_USERS_FULL})
@@ -6578,6 +6631,7 @@ public abstract class PackageManager {
*
* @deprecated use {@link #getInstallSourceInfo(String)} instead
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Deprecated
@Nullable
public abstract String getInstallerPackageName(@NonNull String packageName);
@@ -6617,6 +6671,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void clearApplicationUserData(@NonNull String packageName,
@Nullable IPackageDataObserver observer);
@@ -6636,6 +6691,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void deleteApplicationCacheFiles(@NonNull String packageName,
@Nullable IPackageDataObserver observer);
@@ -6658,6 +6714,7 @@ public abstract class PackageManager {
* callback is desired.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void deleteApplicationCacheFilesAsUser(@NonNull String packageName,
@UserIdInt int userId, @Nullable IPackageDataObserver observer);
@@ -6691,6 +6748,7 @@ public abstract class PackageManager {
}
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void freeStorageAndNotify(@Nullable String volumeUuid, long freeStorageSize,
@Nullable IPackageDataObserver observer);
@@ -6724,6 +6782,7 @@ public abstract class PackageManager {
}
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void freeStorage(@Nullable String volumeUuid, long freeStorageSize,
@Nullable IntentSender pi);
@@ -6747,6 +6806,7 @@ public abstract class PackageManager {
* @deprecated use {@link StorageStatsManager} instead.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Deprecated
@UnsupportedAppUsage
public abstract void getPackageSizeInfoAsUser(@NonNull String packageName,
@@ -6878,6 +6938,7 @@ public abstract class PackageManager {
* an app to be responsible for a particular role and to check current role
* holders, see {@link android.app.role.RoleManager}.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Deprecated
@UnsupportedAppUsage
public abstract void replacePreferredActivity(@NonNull IntentFilter filter, int match,
@@ -6985,6 +7046,7 @@ public abstract class PackageManager {
* default, if any.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@UnsupportedAppUsage
public abstract ComponentName getHomeActivities(@NonNull List<ResolveInfo> outActivities);
@@ -7086,6 +7148,7 @@ public abstract class PackageManager {
* @param userId Ther userId of the user whose restrictions are to be flushed.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void flushPackageRestrictionsAsUser(@UserIdInt int userId);
@@ -7096,6 +7159,7 @@ public abstract class PackageManager {
* or by installing it, such as with {@link #installExistingPackage(String)}
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract boolean setApplicationHiddenSettingAsUser(@NonNull String packageName,
boolean hidden, @NonNull UserHandle userHandle);
@@ -7105,6 +7169,7 @@ public abstract class PackageManager {
* @see #setApplicationHiddenSettingAsUser(String, boolean, UserHandle)
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
@NonNull UserHandle userHandle);
@@ -7138,6 +7203,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
public abstract void addOnPermissionsChangeListener(
@@ -7150,6 +7216,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
public abstract void removeOnPermissionsChangeListener(
@@ -7163,6 +7230,7 @@ public abstract class PackageManager {
* application's AndroidManifest.xml.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@UnsupportedAppUsage
public abstract KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias);
@@ -7170,6 +7238,7 @@ public abstract class PackageManager {
/** Return the signing {@link KeySet} for this application.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@UnsupportedAppUsage
public abstract KeySet getSigningKeySet(@NonNull String packageName);
@@ -7181,6 +7250,7 @@ public abstract class PackageManager {
* Compare to {@link #isSignedByExactly(String packageName, KeySet ks)}.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract boolean isSignedBy(@NonNull String packageName, @NonNull KeySet ks);
@@ -7190,6 +7260,7 @@ public abstract class PackageManager {
* {@link #isSignedBy(String packageName, KeySet ks)}.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract boolean isSignedByExactly(@NonNull String packageName, @NonNull KeySet ks);
@@ -7407,6 +7478,7 @@ public abstract class PackageManager {
* @throws IllegalArgumentException if the package was not found.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract boolean isPackageSuspendedForUser(@NonNull String packageName, int userId);
@@ -7482,6 +7554,7 @@ public abstract class PackageManager {
* @param packageName the package to change the category hint for.
* @param categoryHint the category hint to set.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void setApplicationCategoryHint(@NonNull String packageName,
@ApplicationInfo.Category int categoryHint);
@@ -7497,34 +7570,43 @@ public abstract class PackageManager {
}
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract int getMoveStatus(int moveId);
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void registerMoveCallback(@NonNull MoveCallback callback,
@NonNull Handler handler);
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void unregisterMoveCallback(@NonNull MoveCallback callback);
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public abstract int movePackage(@NonNull String packageName, @NonNull VolumeInfo vol);
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public abstract @Nullable VolumeInfo getPackageCurrentVolume(@NonNull ApplicationInfo app);
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public abstract List<VolumeInfo> getPackageCandidateVolumes(
@NonNull ApplicationInfo app);
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract int movePrimaryStorage(@NonNull VolumeInfo vol);
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract @Nullable VolumeInfo getPrimaryStorageCurrentVolume();
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract @NonNull List<VolumeInfo> getPrimaryStorageCandidateVolumes();
/**
@@ -7534,6 +7616,7 @@ public abstract class PackageManager {
* @return identity that uniquely identifies current device
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
public abstract VerifierDeviceIdentity getVerifierDeviceIdentity();
@@ -7542,6 +7625,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract boolean isUpgrade();
@@ -7571,6 +7655,7 @@ public abstract class PackageManager {
* {@link #ONLY_IF_NO_MATCH_FOUND}.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void addCrossProfileIntentFilter(@NonNull IntentFilter filter,
@UserIdInt int sourceUserId, @UserIdInt int targetUserId, int flags);
@@ -7582,12 +7667,14 @@ public abstract class PackageManager {
* @param sourceUserId The source user id.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void clearCrossProfileIntentFilters(@UserIdInt int sourceUserId);
/**
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@UnsupportedAppUsage
public abstract Drawable loadItemIcon(@NonNull PackageItemInfo itemInfo,
@@ -7596,12 +7683,14 @@ public abstract class PackageManager {
/**
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@NonNull
@UnsupportedAppUsage
public abstract Drawable loadUnbadgedItemIcon(@NonNull PackageItemInfo itemInfo,
@Nullable ApplicationInfo appInfo);
/** {@hide} */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract boolean isPackageAvailable(@NonNull String packageName);
@@ -7822,6 +7911,7 @@ public abstract class PackageManager {
* user, {@code INSTALL_REASON_UNKNOWN} is returned.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@TestApi
@InstallReason
public abstract int getInstallReason(@NonNull String packageName, @NonNull UserHandle user);
@@ -7850,6 +7940,7 @@ public abstract class PackageManager {
* @see {@link android.content.Intent#ACTION_INSTANT_APP_RESOLVER_SETTINGS}
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@SystemApi
public abstract ComponentName getInstantAppResolverSettingsComponent();
@@ -7861,6 +7952,7 @@ public abstract class PackageManager {
* @see {@link android.content.Intent#ACTION_INSTALL_INSTANT_APP_PACKAGE}
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
@SystemApi
public abstract ComponentName getInstantAppInstallerComponent();
@@ -7871,6 +7963,7 @@ public abstract class PackageManager {
* @see {@link android.provider.Settings.Secure#ANDROID_ID}
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@Nullable
public abstract String getInstantAppAndroidId(@NonNull String packageName,
@NonNull UserHandle user);
@@ -7915,6 +8008,7 @@ public abstract class PackageManager {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract void registerDexModule(@NonNull String dexModulePath,
@Nullable DexModuleRegisterCallback callback);
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 6a6be75c4606..da75fba18f82 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1319,8 +1319,8 @@ public final class ShortcutInfo implements Parcelable {
* system services even after it has been unpublished as a dynamic shortcut.
*/
@NonNull
- public Builder setLongLived(boolean londLived) {
- mIsLongLived = londLived;
+ public Builder setLongLived(boolean longLived) {
+ mIsLongLived = longLived;
return this;
}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 6d92d3e0d219..72a66ed4d9fe 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -18,6 +18,7 @@ package android.content.pm.parsing;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+import static android.content.pm.parsing.ParsingPackageUtils.validateName;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.content.pm.PackageInfo;
@@ -501,10 +502,10 @@ public class ApkLiteParseUtils {
final String packageName = attrs.getAttributeValue(null, "package");
if (!"android".equals(packageName)) {
- final String error = PackageParser.validateName(packageName, true, true);
- if (error != null) {
+ final ParseResult<?> nameResult = validateName(input, packageName, true, true);
+ if (nameResult.isError()) {
return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
- "Invalid manifest package: " + error);
+ "Invalid manifest package: " + nameResult.getErrorMessage());
}
}
@@ -513,10 +514,10 @@ public class ApkLiteParseUtils {
if (splitName.length() == 0) {
splitName = null;
} else {
- final String error = PackageParser.validateName(splitName, false, false);
- if (error != null) {
+ final ParseResult<?> nameResult = validateName(input, splitName, false, false);
+ if (nameResult.isError()) {
return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
- "Invalid manifest split: " + error);
+ "Invalid manifest split: " + nameResult.getErrorMessage());
}
}
}
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index c5240c2814e8..ddf3d901c29a 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -419,7 +419,7 @@ public class PackageInfoWithoutStateUtils {
return null;
}
- return generateActivityInfoUnchecked(a, applicationInfo);
+ return generateActivityInfoUnchecked(a, flags, applicationInfo);
}
/**
@@ -431,6 +431,7 @@ public class PackageInfoWithoutStateUtils {
*/
@NonNull
public static ActivityInfo generateActivityInfoUnchecked(@NonNull ParsedActivity a,
+ @PackageManager.ComponentInfoFlags int flags,
@NonNull ApplicationInfo applicationInfo) {
// Make shallow copies so we can store the metadata safely
ActivityInfo ai = new ActivityInfo();
@@ -463,7 +464,9 @@ public class PackageInfoWithoutStateUtils {
ai.rotationAnimation = a.getRotationAnimation();
ai.colorMode = a.getColorMode();
ai.windowLayout = a.getWindowLayout();
- ai.metaData = a.getMetaData();
+ if ((flags & PackageManager.GET_META_DATA) != 0) {
+ ai.metaData = a.getMetaData();
+ }
ai.applicationInfo = applicationInfo;
return ai;
}
@@ -489,7 +492,7 @@ public class PackageInfoWithoutStateUtils {
return null;
}
- return generateServiceInfoUnchecked(s, applicationInfo);
+ return generateServiceInfoUnchecked(s, flags, applicationInfo);
}
/**
@@ -501,17 +504,20 @@ public class PackageInfoWithoutStateUtils {
*/
@NonNull
public static ServiceInfo generateServiceInfoUnchecked(@NonNull ParsedService s,
+ @PackageManager.ComponentInfoFlags int flags,
@NonNull ApplicationInfo applicationInfo) {
// Make shallow copies so we can store the metadata safely
ServiceInfo si = new ServiceInfo();
assignSharedFieldsForComponentInfo(si, s);
si.exported = s.isExported();
si.flags = s.getFlags();
- si.metaData = s.getMetaData();
si.permission = s.getPermission();
si.processName = s.getProcessName();
si.mForegroundServiceType = s.getForegroundServiceType();
si.applicationInfo = applicationInfo;
+ if ((flags & PackageManager.GET_META_DATA) != 0) {
+ si.metaData = s.getMetaData();
+ }
return si;
}
@@ -566,10 +572,12 @@ public class PackageInfoWithoutStateUtils {
pi.initOrder = p.getInitOrder();
pi.uriPermissionPatterns = p.getUriPermissionPatterns();
pi.pathPermissions = p.getPathPermissions();
- pi.metaData = p.getMetaData();
if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
pi.uriPermissionPatterns = null;
}
+ if ((flags & PackageManager.GET_META_DATA) != 0) {
+ pi.metaData = p.getMetaData();
+ }
pi.applicationInfo = applicationInfo;
return pi;
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index b936c6323a80..6196854526e0 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -130,6 +130,12 @@ public class ParsingPackageUtils {
private static final String TAG = ParsingUtils.TAG;
/**
+ * For those names would be used as a part of the file name. Limits size to 223 and reserves 32
+ * for the OS.
+ */
+ private static final int MAX_FILE_NAME_SIZE = 223;
+
+ /**
* @see #parseDefault(ParseInput, File, int, boolean)
*/
@NonNull
@@ -2686,7 +2692,16 @@ public class ParsingPackageUtils {
}
}
- private static ParseResult validateName(ParseInput input, String name, boolean requireSeparator,
+ /**
+ * Check if the given name is valid.
+ *
+ * @param name The name to check.
+ * @param requireSeparator {@code true} if the name requires containing a separator at least.
+ * @param requireFilename {@code true} to apply file name validation to the given name. It also
+ * limits length of the name to the {@link #MAX_FILE_NAME_SIZE}.
+ * @return Success if it's valid.
+ */
+ public static ParseResult validateName(ParseInput input, String name, boolean requireSeparator,
boolean requireFilename) {
final int N = name.length();
boolean hasSep = false;
@@ -2709,8 +2724,12 @@ public class ParsingPackageUtils {
}
return input.error("bad character '" + c + "'");
}
- if (requireFilename && !FileUtils.isValidExtFilename(name)) {
- return input.error("Invalid filename");
+ if (requireFilename) {
+ if (!FileUtils.isValidExtFilename(name)) {
+ return input.error("Invalid filename");
+ } else if (N > MAX_FILE_NAME_SIZE) {
+ return input.error("the length of the name is greater than " + MAX_FILE_NAME_SIZE);
+ }
}
return hasSep || !requireSeparator
? input.success(null)
diff --git a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
index cfefc016d4a4..d65f8ffc989a 100644
--- a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
@@ -16,6 +16,8 @@
package android.content.pm.parsing.component;
+import static android.content.pm.parsing.ParsingPackageUtils.validateName;
+
import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -118,17 +120,19 @@ public class ComponentParseUtils {
+ ": must be at least two characters");
}
String subName = proc.substring(1);
- String nameError = PackageParser.validateName(subName, false, false);
- if (nameError != null) {
+ final ParseResult<?> nameResult = validateName(input, subName, false, false);
+ if (nameResult.isError()) {
return input.error("Invalid " + type + " name " + proc + " in package " + pkg
- + ": " + nameError);
+ + ": " + nameResult.getErrorMessage());
}
return input.success(pkg + proc);
}
- String nameError = PackageParser.validateName(proc, true, false);
- if (nameError != null && !"system".equals(proc)) {
- return input.error("Invalid " + type + " name " + proc + " in package " + pkg
- + ": " + nameError);
+ if (!"system".equals(proc)) {
+ final ParseResult<?> nameResult = validateName(input, proc, true, false);
+ if (nameResult.isError()) {
+ return input.error("Invalid " + type + " name " + proc + " in package " + pkg
+ + ": " + nameResult.getErrorMessage());
+ }
}
return input.success(proc);
}
diff --git a/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java b/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java
index e7a554ae5726..aea69ad5b885 100644
--- a/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java
+++ b/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java
@@ -59,14 +59,18 @@ public class SplitPermissionInfoParcelable implements Parcelable {
- // Code below generated by codegen v1.0.0.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java
//
- // CHECKSTYLE:OFF Generated code
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
/**
* Creates a new SplitPermissionInfoParcelable.
@@ -154,7 +158,7 @@ public class SplitPermissionInfoParcelable implements Parcelable {
@Override
@DataClass.Generated.Member
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
@@ -167,6 +171,32 @@ public class SplitPermissionInfoParcelable implements Parcelable {
@DataClass.Generated.Member
public int describeContents() { return 0; }
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected SplitPermissionInfoParcelable(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ String splitPermission = in.readString();
+ List<String> newPermissions = new java.util.ArrayList<>();
+ in.readStringList(newPermissions);
+ int targetSdk = in.readInt();
+
+ this.mSplitPermission = splitPermission;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mSplitPermission);
+ this.mNewPermissions = newPermissions;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mNewPermissions);
+ this.mTargetSdk = targetSdk;
+ com.android.internal.util.AnnotationValidations.validate(
+ IntRange.class, null, mTargetSdk,
+ "from", 0);
+
+ onConstructed();
+ }
+
@DataClass.Generated.Member
public static final @NonNull Parcelable.Creator<SplitPermissionInfoParcelable> CREATOR
= new Parcelable.Creator<SplitPermissionInfoParcelable>() {
@@ -176,28 +206,21 @@ public class SplitPermissionInfoParcelable implements Parcelable {
}
@Override
- @SuppressWarnings({"unchecked", "RedundantCast"})
- public SplitPermissionInfoParcelable createFromParcel(Parcel in) {
- // You can override field unparcelling by defining methods like:
- // static FieldType unparcelFieldName(Parcel in) { ... }
-
- String splitPermission = in.readString();
- List<String> newPermissions = new java.util.ArrayList<>();
- in.readStringList(newPermissions);
- int targetSdk = in.readInt();
- return new SplitPermissionInfoParcelable(
- splitPermission,
- newPermissions,
- targetSdk);
+ public SplitPermissionInfoParcelable createFromParcel(@NonNull Parcel in) {
+ return new SplitPermissionInfoParcelable(in);
}
};
@DataClass.Generated(
- time = 1567634390477L,
- codegenVersion = "1.0.0",
+ time = 1604456266666L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mSplitPermission\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mNewPermissions\nprivate final @android.annotation.IntRange(from=0L) int mTargetSdk\nprivate void onConstructed()\nclass SplitPermissionInfoParcelable extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mSplitPermission\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mNewPermissions\nprivate final @android.annotation.IntRange int mTargetSdk\nprivate void onConstructed()\nclass SplitPermissionInfoParcelable extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
+
+ //@formatter:on
+ // End of generated code
+
}
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index 3effc5ae5f42..cf25c3c56208 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -24,6 +24,8 @@ import android.os.Build;
import android.os.Bundle;
import android.util.Log;
+import dalvik.system.CloseGuard;
+
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashMap;
@@ -86,6 +88,9 @@ public abstract class AbstractCursor implements CrossProcessCursor {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private Bundle mExtras = Bundle.EMPTY;
+ /** CloseGuard to detect leaked cursor **/
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
/* -------------------------------------------------------- */
/* These need to be implemented by subclasses */
@Override
@@ -179,6 +184,7 @@ public abstract class AbstractCursor implements CrossProcessCursor {
mClosed = true;
mContentObservable.unregisterAll();
onDeactivateOrClose();
+ mCloseGuard.close();
}
/**
@@ -218,6 +224,7 @@ public abstract class AbstractCursor implements CrossProcessCursor {
/* Implementation */
public AbstractCursor() {
mPos = -1;
+ mCloseGuard.open("close");
}
@Override
@@ -521,6 +528,7 @@ public abstract class AbstractCursor implements CrossProcessCursor {
mContentResolver.unregisterContentObserver(mSelfObserver);
}
try {
+ if (mCloseGuard != null) mCloseGuard.warnIfOpen();
if (!mClosed) close();
} catch(Exception e) { }
}
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 3bfbe7e7b93b..7ba63e6462f1 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -62,9 +62,6 @@ public class SQLiteCursor extends AbstractWindowedCursor {
/** A mapping of column names to column indices, to speed up lookups */
private Map<String, Integer> mColumnNameMap;
- /** Used to find out where a cursor was allocated in case it never got released. */
- private final Throwable mStackTrace;
-
/** Controls fetching of rows relative to requested position **/
private boolean mFillWindowForwardOnly;
@@ -102,11 +99,6 @@ public class SQLiteCursor extends AbstractWindowedCursor {
if (query == null) {
throw new IllegalArgumentException("query object cannot be null");
}
- if (StrictMode.vmSqliteObjectLeaksEnabled()) {
- mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
- } else {
- mStackTrace = null;
- }
mDriver = driver;
mEditTable = editTable;
mColumnNameMap = null;
@@ -283,17 +275,17 @@ public class SQLiteCursor extends AbstractWindowedCursor {
try {
// if the cursor hasn't been closed yet, close it first
if (mWindow != null) {
- if (mStackTrace != null) {
+ // Report original sql statement
+ if (StrictMode.vmSqliteObjectLeaksEnabled()) {
String sql = mQuery.getSql();
int len = sql.length();
StrictMode.onSqliteObjectLeaked(
- "Finalizing a Cursor that has not been deactivated or closed. " +
- "database = " + mQuery.getDatabase().getLabel() +
- ", table = " + mEditTable +
- ", query = " + sql.substring(0, (len > 1000) ? 1000 : len),
- mStackTrace);
+ "Finalizing a Cursor that has not been deactivated or closed. "
+ + "database = " + mQuery.getDatabase().getLabel()
+ + ", table = " + mEditTable
+ + ", query = " + sql.substring(0, (len > 1000) ? 1000 : len),
+ null);
}
- close();
}
} finally {
super.finalize();
diff --git a/core/java/android/hardware/biometrics/IBiometricSysuiReceiver.aidl b/core/java/android/hardware/biometrics/IBiometricSysuiReceiver.aidl
index 7a006c34e1e1..492ceebe4d06 100644
--- a/core/java/android/hardware/biometrics/IBiometricSysuiReceiver.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricSysuiReceiver.aidl
@@ -28,4 +28,6 @@ oneway interface IBiometricSysuiReceiver {
void onDeviceCredentialPressed();
// Notifies the client that an internal event, e.g. back button has occurred.
void onSystemEvent(int event);
+ // Notifies that the dialog has finished animating in.
+ void onDialogAnimatedIn();
}
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index f0a83f0b00b0..e8581595ad91 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -188,6 +188,7 @@ public abstract class CameraCaptureSession implements AutoCloseable {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void prepare(int maxCount, @NonNull Surface surface)
throws CameraAccessException;
@@ -227,6 +228,7 @@ public abstract class CameraCaptureSession implements AutoCloseable {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void tearDown(@NonNull Surface surface) throws CameraAccessException;
/**
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
index a52f983ff2a7..29a6ee278d9c 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManager.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -16,9 +16,12 @@
package android.hardware.devicestate;
+import android.annotation.NonNull;
import android.annotation.SystemService;
import android.content.Context;
+import java.util.concurrent.Executor;
+
/**
* Manages the state of the system for devices with user-configurable hardware like a foldable
* phone.
@@ -33,6 +36,47 @@ public final class DeviceStateManager {
private DeviceStateManagerGlobal mGlobal;
public DeviceStateManager() {
- mGlobal = DeviceStateManagerGlobal.getInstance();
+ DeviceStateManagerGlobal global = DeviceStateManagerGlobal.getInstance();
+ if (global == null) {
+ throw new IllegalStateException(
+ "Failed to get instance of global device state manager.");
+ }
+ mGlobal = global;
+ }
+
+ /**
+ * Registers a listener to receive notifications about changes in device state.
+ *
+ * @param listener the listener to register.
+ * @param executor the executor to process notifications.
+ *
+ * @see DeviceStateListener
+ */
+ public void registerDeviceStateListener(@NonNull DeviceStateListener listener,
+ @NonNull Executor executor) {
+ mGlobal.registerDeviceStateListener(listener, executor);
+ }
+
+ /**
+ * Unregisters a listener previously registered with
+ * {@link #registerDeviceStateListener(DeviceStateListener, Executor)}.
+ */
+ public void unregisterDeviceStateListener(@NonNull DeviceStateListener listener) {
+ mGlobal.unregisterDeviceStateListener(listener);
+ }
+
+ /**
+ * Listens for changes in device states.
+ */
+ public interface DeviceStateListener {
+ /**
+ * Called in response to device state changes.
+ * <p>
+ * Guaranteed to be called once on registration of the listener with the
+ * initial value and then on every subsequent change in device state.
+ *
+ * @param deviceState the new device state.
+ */
+ void onDeviceStateChanged(int deviceState);
}
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
index 4e7cf4af118d..c8905038d056 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -19,16 +19,26 @@ package android.hardware.devicestate;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager.DeviceStateListener;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.ServiceManager;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
+
/**
* Provides communication with the device state system service on behalf of applications.
*
* @see DeviceStateManager
* @hide
*/
-final class DeviceStateManagerGlobal {
+@VisibleForTesting(visibility = Visibility.PACKAGE)
+public final class DeviceStateManagerGlobal {
private static DeviceStateManagerGlobal sInstance;
/**
@@ -49,10 +59,121 @@ final class DeviceStateManagerGlobal {
}
}
+ private final Object mLock = new Object();
@NonNull
private final IDeviceStateManager mDeviceStateManager;
+ @Nullable
+ private DeviceStateManagerCallback mCallback;
- private DeviceStateManagerGlobal(@NonNull IDeviceStateManager deviceStateManager) {
+ @GuardedBy("mLock")
+ private final ArrayList<DeviceStateListenerWrapper> mListeners = new ArrayList<>();
+ @Nullable
+ @GuardedBy("mLock")
+ private Integer mLastReceivedState;
+
+ @VisibleForTesting
+ public DeviceStateManagerGlobal(@NonNull IDeviceStateManager deviceStateManager) {
mDeviceStateManager = deviceStateManager;
}
+
+ /**
+ * Registers a listener to receive notifications about changes in device state.
+ *
+ * @see DeviceStateManager#registerDeviceStateListener(DeviceStateListener, Executor)
+ */
+ @VisibleForTesting(visibility = Visibility.PACKAGE)
+ public void registerDeviceStateListener(@NonNull DeviceStateListener listener,
+ @NonNull Executor executor) {
+ Integer stateToReport;
+ DeviceStateListenerWrapper wrapper;
+ synchronized (mLock) {
+ registerCallbackIfNeededLocked();
+
+ int index = findListenerLocked(listener);
+ if (index != -1) {
+ // This listener is already registered.
+ return;
+ }
+
+ wrapper = new DeviceStateListenerWrapper(listener, executor);
+ mListeners.add(wrapper);
+ stateToReport = mLastReceivedState;
+ }
+
+ if (stateToReport != null) {
+ // Notify the listener with the most recent device state from the server. If the state
+ // to report is null this is likely the first listener added and we're still waiting
+ // from the callback from the server.
+ wrapper.notifyDeviceStateChanged(stateToReport);
+ }
+ }
+
+ /**
+ * Unregisters a listener previously registered with
+ * {@link #registerDeviceStateListener(DeviceStateListener, Executor)}.
+ *
+ * @see DeviceStateManager#registerDeviceStateListener(DeviceStateListener, Executor)
+ */
+ @VisibleForTesting(visibility = Visibility.PACKAGE)
+ public void unregisterDeviceStateListener(DeviceStateListener listener) {
+ synchronized (mLock) {
+ int indexToRemove = findListenerLocked(listener);
+ if (indexToRemove != -1) {
+ mListeners.remove(indexToRemove);
+ }
+ }
+ }
+
+ private void registerCallbackIfNeededLocked() {
+ if (mCallback == null) {
+ mCallback = new DeviceStateManagerCallback();
+ try {
+ mDeviceStateManager.registerCallback(mCallback);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ private int findListenerLocked(DeviceStateListener listener) {
+ for (int i = 0; i < mListeners.size(); i++) {
+ if (mListeners.get(i).mDeviceStateListener.equals(listener)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private void handleDeviceStateChanged(int newDeviceState) {
+ ArrayList<DeviceStateListenerWrapper> listeners;
+ synchronized (mLock) {
+ mLastReceivedState = newDeviceState;
+ listeners = new ArrayList<>(mListeners);
+ }
+
+ for (int i = 0; i < listeners.size(); i++) {
+ listeners.get(i).notifyDeviceStateChanged(newDeviceState);
+ }
+ }
+
+ private final class DeviceStateManagerCallback extends IDeviceStateManagerCallback.Stub {
+ @Override
+ public void onDeviceStateChanged(int deviceState) {
+ handleDeviceStateChanged(deviceState);
+ }
+ }
+
+ private static final class DeviceStateListenerWrapper {
+ private final DeviceStateListener mDeviceStateListener;
+ private final Executor mExecutor;
+
+ DeviceStateListenerWrapper(DeviceStateListener listener, Executor executor) {
+ mDeviceStateListener = listener;
+ mExecutor = executor;
+ }
+
+ void notifyDeviceStateChanged(int newDeviceState) {
+ mExecutor.execute(() -> mDeviceStateListener.onDeviceStateChanged(newDeviceState));
+ }
+ }
}
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
index 24913e9b2d23..a157b3311ca5 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
@@ -16,5 +16,9 @@
package android.hardware.devicestate;
+import android.hardware.devicestate.IDeviceStateManagerCallback;
+
/** @hide */
-interface IDeviceStateManager {}
+interface IDeviceStateManager {
+ void registerCallback(in IDeviceStateManagerCallback callback);
+}
diff --git a/packages/CarSystemUI/res/values/themes.xml b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
index f82be3c0e529..d1c581361b62 100644
--- a/packages/CarSystemUI/res/values/themes.xml
+++ b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
@@ -1,7 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
/**
- * Copyright (c) 2018, The Android Open Source Project
+ * Copyright (c) 2020, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
--->
-<resources>
- <style name="Theme.Notification" parent="Theme.DeviceDefault.NoActionBar.Notification">
- </style>
-</resources>
+package android.hardware.devicestate;
+
+/** @hide */
+interface IDeviceStateManagerCallback {
+ oneway void onDeviceStateChanged(int deviceState);
+}
diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java
index 10e1c7c2e0df..71688c7cc7e8 100644
--- a/core/java/android/hardware/display/VirtualDisplayConfig.java
+++ b/core/java/android/hardware/display/VirtualDisplayConfig.java
@@ -93,7 +93,7 @@ public final class VirtualDisplayConfig implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -477,10 +477,10 @@ public final class VirtualDisplayConfig implements Parcelable {
}
@DataClass.Generated(
- time = 1585179350902L,
- codegenVersion = "1.0.15",
+ time = 1604456298440L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java",
- inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange(from=1L) int mWidth\nprivate @android.annotation.IntRange(from=1L) int mHeight\nprivate @android.annotation.IntRange(from=1L) int mDensityDpi\nprivate int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
+ inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate int mDisplayIdToMirror\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 9f322fbad51d..75893d978749 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -577,9 +577,17 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
*/
@RequiresPermission(MANAGE_BIOMETRIC)
public List<Face> getEnrolledFaces(int userId) {
+ final List<FaceSensorPropertiesInternal> faceSensorProperties =
+ getSensorPropertiesInternal();
+ if (faceSensorProperties.isEmpty()) {
+ Slog.e(TAG, "No sensors");
+ return new ArrayList<>();
+ }
+
if (mService != null) {
try {
- return mService.getEnrolledFaces(userId, mContext.getOpPackageName());
+ return mService.getEnrolledFaces(faceSensorProperties.get(0).sensorId, userId,
+ mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -606,15 +614,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public boolean hasEnrolledTemplates() {
- if (mService != null) {
- try {
- return mService.hasEnrolledFaces(
- UserHandle.myUserId(), mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- return false;
+ return hasEnrolledTemplates(UserHandle.myUserId());
}
/**
@@ -624,9 +624,17 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
USE_BIOMETRIC_INTERNAL,
INTERACT_ACROSS_USERS})
public boolean hasEnrolledTemplates(int userId) {
+ final List<FaceSensorPropertiesInternal> faceSensorProperties =
+ getSensorPropertiesInternal();
+ if (faceSensorProperties.isEmpty()) {
+ Slog.e(TAG, "No sensors");
+ return false;
+ }
+
if (mService != null) {
try {
- return mService.hasEnrolledFaces(userId, mContext.getOpPackageName());
+ return mService.hasEnrolledFaces(faceSensorProperties.get(0).sensorId, userId,
+ mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -642,9 +650,17 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
public boolean isHardwareDetected() {
+ final List<FaceSensorPropertiesInternal> faceSensorProperties =
+ getSensorPropertiesInternal();
+ if (faceSensorProperties.isEmpty()) {
+ Slog.e(TAG, "No sensors");
+ return false;
+ }
+
if (mService != null) {
try {
- return mService.isHardwareDetected(mContext.getOpPackageName());
+ return mService.isHardwareDetected(faceSensorProperties.get(0).sensorId,
+ mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -677,7 +693,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
@NonNull
public List<FaceSensorPropertiesInternal> getSensorPropertiesInternal() {
try {
- if (mService == null || !mService.isHardwareDetected(mContext.getOpPackageName())) {
+ if (mService == null) {
return new ArrayList<>();
}
return mService.getSensorPropertiesInternal(mContext.getOpPackageName());
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 490c95bfe1bb..27cdda7b0723 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -44,12 +44,12 @@ interface IFaceService {
// called from BiometricService. The additional uid, pid, userId arguments should be determined
// by BiometricService. To start authentication after the clients are ready, use
// startPreparedClient().
- void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,
+ void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
int cookie, int callingUid, int callingPid, int callingUserId);
// Starts authentication with the previously prepared client.
- void startPreparedClient(int cookie);
+ void startPreparedClient(int sensorId, int cookie);
// Cancel authentication for the given sessionId
void cancelAuthentication(IBinder token, String opPackageName);
@@ -58,7 +58,7 @@ interface IFaceService {
void cancelFaceDetect(IBinder token, String opPackageName);
// Same as above, with extra arguments.
- void cancelAuthenticationFromService(IBinder token, String opPackageName,
+ void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName,
int callingUid, int callingPid, int callingUserId);
// Start face enrollment
@@ -77,10 +77,10 @@ interface IFaceService {
String opPackageName);
// Get the enrolled face for user.
- List<Face> getEnrolledFaces(int userId, String opPackageName);
+ List<Face> getEnrolledFaces(int sensorId, int userId, String opPackageName);
// Determine if HAL is loaded and ready
- boolean isHardwareDetected(String opPackageName);
+ boolean isHardwareDetected(int sensorId, String opPackageName);
// Get a pre-enrollment authentication token
void generateChallenge(IBinder token, int sensorId, int userId, IFaceServiceReceiver receiver, String opPackageName);
@@ -89,13 +89,13 @@ interface IFaceService {
void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName, long challenge);
// Determine if a user has at least one enrolled face
- boolean hasEnrolledFaces(int userId, String opPackageName);
+ boolean hasEnrolledFaces(int sensorId, int userId, String opPackageName);
// Return the LockoutTracker status for the specified user
- int getLockoutModeForUser(int userId);
+ int getLockoutModeForUser(int sensorId, int userId);
// Gets the authenticator ID for face
- long getAuthenticatorId(int callingUserId);
+ long getAuthenticatorId(int sensorId, int callingUserId);
// Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetLockout(IBinder token, int sensorId, int userId, in byte [] hardwareAuthToken, String opPackageName);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 4afe4b3d126b..51e0eba1ec23 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -846,13 +846,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
@Deprecated
@RequiresPermission(USE_FINGERPRINT)
public boolean hasEnrolledFingerprints() {
- if (mService != null) try {
- return mService.hasEnrolledFingerprints(
- mContext.getUserId(), mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- return false;
+ return hasEnrolledFingerprints(UserHandle.myUserId());
}
/**
@@ -863,7 +857,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
INTERACT_ACROSS_USERS})
public boolean hasEnrolledFingerprints(int userId) {
if (mService != null) try {
- return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());
+ return mService.hasEnrolledFingerprintsDeprecated(userId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -882,7 +876,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
public boolean isHardwareDetected() {
if (mService != null) {
try {
- return mService.isHardwareDetected(mContext.getOpPackageName());
+ return mService.isHardwareDetectedDeprecated(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -900,7 +894,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
@NonNull
public List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal() {
try {
- if (mService == null || !mService.isHardwareDetected(mContext.getOpPackageName())) {
+ if (mService == null) {
return new ArrayList<>();
}
return mService.getSensorPropertiesInternal(mContext.getOpPackageName());
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
index 9a9e47868b85..3a9d14342545 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
@@ -43,24 +43,36 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
* The location of the center of the sensor if applicable. For example, sensors of type
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
* distance in pixels, measured from the left edge of the screen.
- * TODO: Value should be provided from the HAL
*/
- public final int sensorLocationX = 540;
+ public final int sensorLocationX;
/**
* The location of the center of the sensor if applicable. For example, sensors of type
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
* distance in pixels, measured from the top edge of the screen.
- * TODO: Value should be provided from the HAL
+ *
*/
- public final int sensorLocationY = 1636;
+ public final int sensorLocationY;
/**
* The radius of the sensor if applicable. For example, sensors of type
* {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the radius
* of the sensor, in pixels.
*/
- public final int sensorRadius = 130;
+ public final int sensorRadius;
+
+ public FingerprintSensorPropertiesInternal(int sensorId,
+ @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
+ @FingerprintSensorProperties.SensorType int sensorType,
+ boolean resetLockoutRequiresHardwareAuthToken, int sensorLocationX, int sensorLocationY,
+ int sensorRadius) {
+ super(sensorId, strength, maxEnrollmentsPerUser);
+ this.sensorType = sensorType;
+ this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
+ this.sensorLocationX = sensorLocationX;
+ this.sensorLocationY = sensorLocationY;
+ this.sensorRadius = sensorRadius;
+ }
/**
* Initializes SensorProperties with specified values
@@ -69,15 +81,19 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
@SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
@FingerprintSensorProperties.SensorType int sensorType,
boolean resetLockoutRequiresHardwareAuthToken) {
- super(sensorId, strength, maxEnrollmentsPerUser);
- this.sensorType = sensorType;
- this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
+ // TODO: Value should be provided from the HAL
+ this(sensorId, strength, maxEnrollmentsPerUser, sensorType,
+ resetLockoutRequiresHardwareAuthToken, 540 /* sensorLocationX */,
+ 1636 /* sensorLocationY */, 130 /* sensorRadius */);
}
protected FingerprintSensorPropertiesInternal(Parcel in) {
super(in);
sensorType = in.readInt();
resetLockoutRequiresHardwareAuthToken = in.readBoolean();
+ sensorLocationX = in.readInt();
+ sensorLocationY = in.readInt();
+ sensorRadius = in.readInt();
}
public static final Creator<FingerprintSensorPropertiesInternal> CREATOR =
@@ -103,6 +119,9 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
super.writeToParcel(dest, flags);
dest.writeInt(sensorType);
dest.writeBoolean(resetLockoutRequiresHardwareAuthToken);
+ dest.writeInt(sensorLocationX);
+ dest.writeInt(sensorLocationY);
+ dest.writeInt(sensorRadius);
}
public boolean isAnyUdfpsType() {
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 5b14ef796616..2128d67f80ae 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -53,12 +53,12 @@ interface IFingerprintService {
// called from BiometricService. The additional uid, pid, userId arguments should be determined
// by BiometricService. To start authentication after the clients are ready, use
// startPreparedClient().
- void prepareForAuthentication(IBinder token, long operationId, int userId,
+ void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId,
IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
int callingUid, int callingPid, int callingUserId);
// Starts authentication with the previously prepared client.
- void startPreparedClient(int cookie);
+ void startPreparedClient(int sensorId, int cookie);
// Cancel authentication for the given sessionId
void cancelAuthentication(IBinder token, String opPackageName);
@@ -68,7 +68,7 @@ interface IFingerprintService {
// Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
// an additional uid, pid, userid.
- void cancelAuthenticationFromService(IBinder token, String opPackageName,
+ void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName,
int callingUid, int callingPid, int callingUserId);
// Start fingerprint enrollment
@@ -88,8 +88,11 @@ interface IFingerprintService {
// Get a list of enrolled fingerprints in the given userId.
List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName);
- // Determine if HAL is loaded and ready
- boolean isHardwareDetected(String opPackageName);
+ // Determine if the HAL is loaded and ready. Meant to support the deprecated FingerprintManager APIs
+ boolean isHardwareDetectedDeprecated(String opPackageName);
+
+ // Determine if the specified HAL is loaded and ready
+ boolean isHardwareDetected(int sensorId, String opPackageName);
// Get a pre-enrollment authentication token
void generateChallenge(IBinder token, int sensorId, int userId, IFingerprintServiceReceiver receiver, String opPackageName);
@@ -97,17 +100,20 @@ interface IFingerprintService {
// Finish an enrollment sequence and invalidate the authentication token
void revokeChallenge(IBinder token, int sensorId, int userId, String opPackageName, long challenge);
- // Determine if a user has at least one enrolled fingerprint
- boolean hasEnrolledFingerprints(int userId, String opPackageName);
+ // Determine if a user has at least one enrolled fingerprint. Meant to support the deprecated FingerprintManager APIs
+ boolean hasEnrolledFingerprintsDeprecated(int userId, String opPackageName);
+
+ // Determine if a user has at least one enrolled fingerprint.
+ boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName);
// Determine if a user has at least one enrolled fingerprint in any of the specified sensors
boolean hasEnrolledTemplatesForAnySensor(int userId, in List<FingerprintSensorPropertiesInternal> sensors, String opPackageName);
// Return the LockoutTracker status for the specified user
- int getLockoutModeForUser(int userId);
+ int getLockoutModeForUser(int sensorId, int userId);
// Gets the authenticator ID for fingerprint
- long getAuthenticatorId(int callingUserId);
+ long getAuthenticatorId(int sensorId, int callingUserId);
// Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetLockout(IBinder token, int sensorId, int userId, in byte[] hardwareAuthToken, String opPackageNAame);
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 401bb9d32492..f1534d95a16c 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -42,9 +42,11 @@ import com.android.internal.util.ConcurrentUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
/**
* The {@link HdmiControlManager} class is used to send HDMI control messages
@@ -325,23 +327,46 @@ public final class HdmiControlManager {
*
* @hide
*/
- public static final String HDMI_CEC_CONTROL_ENABLED = "1";
+ public static final int HDMI_CEC_CONTROL_ENABLED = 1;
/**
* HDMI CEC disabled.
*
* @hide
*/
- public static final String HDMI_CEC_CONTROL_DISABLED = "0";
+ public static final int HDMI_CEC_CONTROL_DISABLED = 0;
/**
* @hide
*/
- @StringDef({
+ @IntDef({
HDMI_CEC_CONTROL_ENABLED,
HDMI_CEC_CONTROL_DISABLED
})
@Retention(RetentionPolicy.SOURCE)
public @interface HdmiCecControl {}
+ // -- Supported HDM-CEC versions.
+ /**
+ * Version constant for HDMI-CEC v1.4b.
+ *
+ * @hide
+ */
+ public static final int HDMI_CEC_VERSION_1_4_b = 0x05;
+ /**
+ * Version constant for HDMI-CEC v2.0.
+ *
+ * @hide
+ */
+ public static final int HDMI_CEC_VERSION_2_0 = 0x06;
+ /**
+ * @hide
+ */
+ @IntDef({
+ HDMI_CEC_VERSION_1_4_b,
+ HDMI_CEC_VERSION_2_0
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface HdmiCecVersion {}
+
// -- Which devices the playback device can send a <Standby> message to upon going to sleep.
/**
* Send <Standby> to TV only.
@@ -401,17 +426,17 @@ public final class HdmiControlManager {
*
* @hide
*/
- public static final String SYSTEM_AUDIO_MODE_MUTING_ENABLED = "1";
+ public static final int SYSTEM_AUDIO_MODE_MUTING_ENABLED = 1;
/**
* System Audio Mode muting disabled.
*
* @hide
*/
- public static final String SYSTEM_AUDIO_MODE_MUTING_DISABLED = "0";
+ public static final int SYSTEM_AUDIO_MODE_MUTING_DISABLED = 0;
/**
* @hide
*/
- @StringDef({
+ @IntDef({
SYSTEM_AUDIO_MODE_MUTING_ENABLED,
SYSTEM_AUDIO_MODE_MUTING_DISABLED
})
@@ -426,6 +451,12 @@ public final class HdmiControlManager {
*/
public static final String CEC_SETTING_NAME_HDMI_CEC_ENABLED = "hdmi_cec_enabled";
/**
+ * Name of a setting controlling the version of HDMI-CEC used.
+ *
+ * @hide
+ */
+ public static final String CEC_SETTING_NAME_HDMI_CEC_VERSION = "hdmi_cec_version";
+ /**
* Name of a setting deciding on the Standby message behaviour on sleep.
*
* @hide
@@ -450,6 +481,7 @@ public final class HdmiControlManager {
*/
@StringDef({
CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ CEC_SETTING_NAME_HDMI_CEC_VERSION,
CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
@@ -545,7 +577,7 @@ public final class HdmiControlManager {
*/
@Nullable
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public HdmiClient getClient(int type) {
if (mService == null) {
return null;
@@ -578,7 +610,7 @@ public final class HdmiControlManager {
*/
@Nullable
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public HdmiPlaybackClient getPlaybackClient() {
return (HdmiPlaybackClient) getClient(HdmiDeviceInfo.DEVICE_PLAYBACK);
}
@@ -596,7 +628,7 @@ public final class HdmiControlManager {
*/
@Nullable
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public HdmiTvClient getTvClient() {
return (HdmiTvClient) getClient(HdmiDeviceInfo.DEVICE_TV);
}
@@ -614,7 +646,7 @@ public final class HdmiControlManager {
* @hide
*/
@Nullable
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public HdmiAudioSystemClient getAudioSystemClient() {
return (HdmiAudioSystemClient) getClient(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
}
@@ -629,7 +661,7 @@ public final class HdmiControlManager {
* @return {@link HdmiSwitchClient} instance. {@code null} on failure.
*/
@Nullable
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public HdmiSwitchClient getSwitchClient() {
return (HdmiSwitchClient) getClient(HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
}
@@ -1317,24 +1349,51 @@ public final class HdmiControlManager {
}
/**
- * Get a set of allowed values for a settings.
+ * Get a set of allowed values for a setting (string value-type).
+ *
+ * @param name name of the setting
+ * @return a set of allowed values for a settings. {@code null} on failure.
+ * @throws IllegalArgumentException when setting {@code name} does not exist.
+ * @throws IllegalArgumentException when setting {@code name} value type is invalid.
+ * @throws RuntimeException when the HdmiControlService is not available.
+ *
+ * @hide
+ */
+ @NonNull
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+ public List<String> getAllowedCecSettingStringValues(@NonNull @CecSettingName String name) {
+ if (mService == null) {
+ Log.e(TAG, "HdmiControlService is not available");
+ throw new RuntimeException("HdmiControlService is not available");
+ }
+ try {
+ return mService.getAllowedCecSettingStringValues(name);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get a set of allowed values for a setting (int value-type).
*
* @param name name of the setting
* @return a set of allowed values for a settings. {@code null} on failure.
* @throws IllegalArgumentException when setting {@code name} does not exist.
+ * @throws IllegalArgumentException when setting {@code name} value type is invalid.
* @throws RuntimeException when the HdmiControlService is not available.
*
* @hide
*/
@NonNull
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
- public List<String> getAllowedCecSettingValues(@NonNull @CecSettingName String name) {
+ public List<Integer> getAllowedCecSettingIntValues(@NonNull @CecSettingName String name) {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
throw new RuntimeException("HdmiControlService is not available");
}
try {
- return mService.getAllowedCecSettingValues(name);
+ int[] allowedValues = mService.getAllowedCecSettingIntValues(name);
+ return Arrays.stream(allowedValues).boxed().collect(Collectors.toList());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1350,13 +1409,13 @@ public final class HdmiControlManager {
* @hide
*/
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
- public void setHdmiCecEnabled(@NonNull @HdmiCecControl String value) {
+ public void setHdmiCecEnabled(@NonNull @HdmiCecControl int value) {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
throw new RuntimeException("HdmiControlService is not available");
}
try {
- mService.setCecSettingValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED, value);
+ mService.setCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED, value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1373,13 +1432,58 @@ public final class HdmiControlManager {
@NonNull
@HdmiCecControl
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
- public String getHdmiCecEnabled() {
+ public int getHdmiCecEnabled() {
+ if (mService == null) {
+ Log.e(TAG, "HdmiControlService is not available");
+ throw new RuntimeException("HdmiControlService is not available");
+ }
+ try {
+ return mService.getCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set the 'hdmi_cec_version' option.
+ *
+ * @param value the desired value
+ * @throws IllegalArgumentException when the new value is not allowed.
+ * @throws RuntimeException when the HdmiControlService is not available.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+ public void setHdmiCecVersion(@NonNull @HdmiCecVersion int value) {
+ if (mService == null) {
+ Log.e(TAG, "HdmiControlService is not available");
+ throw new RuntimeException("HdmiControlService is not available");
+ }
+ try {
+ mService.setCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_VERSION, value);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the value of 'hdmi_cec_enabled' option.
+ *
+ * @return the current value.
+ * @throws RuntimeException when the HdmiControlService is not available.
+ *
+ * @hide
+ */
+ @NonNull
+ @HdmiCecVersion
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+ public int getHdmiCecVersion() {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
throw new RuntimeException("HdmiControlService is not available");
}
try {
- return mService.getCecSettingValue(CEC_SETTING_NAME_HDMI_CEC_ENABLED);
+ return mService.getCecSettingIntValue(CEC_SETTING_NAME_HDMI_CEC_VERSION);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1401,7 +1505,7 @@ public final class HdmiControlManager {
throw new RuntimeException("HdmiControlService is not available");
}
try {
- mService.setCecSettingValue(CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP, value);
+ mService.setCecSettingStringValue(CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP, value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1424,7 +1528,7 @@ public final class HdmiControlManager {
throw new RuntimeException("HdmiControlService is not available");
}
try {
- return mService.getCecSettingValue(CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
+ return mService.getCecSettingStringValue(CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1447,7 +1551,7 @@ public final class HdmiControlManager {
throw new RuntimeException("HdmiControlService is not available");
}
try {
- mService.setCecSettingValue(
+ mService.setCecSettingStringValue(
CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1471,7 +1575,7 @@ public final class HdmiControlManager {
throw new RuntimeException("HdmiControlService is not available");
}
try {
- return mService.getCecSettingValue(
+ return mService.getCecSettingStringValue(
CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1488,13 +1592,13 @@ public final class HdmiControlManager {
* @hide
*/
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
- public void setSystemAudioModeMuting(@NonNull @SystemAudioModeMuting String value) {
+ public void setSystemAudioModeMuting(@NonNull @SystemAudioModeMuting int value) {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
throw new RuntimeException("HdmiControlService is not available");
}
try {
- mService.setCecSettingValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, value);
+ mService.setCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1511,13 +1615,13 @@ public final class HdmiControlManager {
@NonNull
@SystemAudioModeMuting
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
- public String getSystemAudioModeMuting() {
+ public int getSystemAudioModeMuting() {
if (mService == null) {
Log.e(TAG, "HdmiControlService is not available");
throw new RuntimeException("HdmiControlService is not available");
}
try {
- return mService.getCecSettingValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING);
+ return mService.getCecSettingIntValue(CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
index 22d4640be493..fab56b8cea49 100644
--- a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
+++ b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
@@ -301,18 +301,33 @@ public final class HdmiControlServiceWrapper {
}
@Override
- public List<String> getAllowedCecSettingValues(String name) {
- return HdmiControlServiceWrapper.this.getAllowedCecSettingValues(name);
+ public List<String> getAllowedCecSettingStringValues(String name) {
+ return HdmiControlServiceWrapper.this.getAllowedCecSettingStringValues(name);
}
@Override
- public String getCecSettingValue(String name) {
- return HdmiControlServiceWrapper.this.getCecSettingValue(name);
+ public int[] getAllowedCecSettingIntValues(String name) {
+ return HdmiControlServiceWrapper.this.getAllowedCecSettingIntValues(name);
}
@Override
- public void setCecSettingValue(String name, String value) {
- HdmiControlServiceWrapper.this.setCecSettingValue(name, value);
+ public String getCecSettingStringValue(String name) {
+ return HdmiControlServiceWrapper.this.getCecSettingStringValue(name);
+ }
+
+ @Override
+ public void setCecSettingStringValue(String name, String value) {
+ HdmiControlServiceWrapper.this.setCecSettingStringValue(name, value);
+ }
+
+ @Override
+ public int getCecSettingIntValue(String name) {
+ return HdmiControlServiceWrapper.this.getCecSettingIntValue(name);
+ }
+
+ @Override
+ public void setCecSettingIntValue(String name, int value) {
+ HdmiControlServiceWrapper.this.setCecSettingIntValue(name, value);
}
};
@@ -494,15 +509,30 @@ public final class HdmiControlServiceWrapper {
}
/** @hide */
- public List<String> getAllowedCecSettingValues(String name) {
+ public List<String> getAllowedCecSettingStringValues(String name) {
return new ArrayList<>();
}
/** @hide */
- public String getCecSettingValue(String name) {
+ public int[] getAllowedCecSettingIntValues(String name) {
+ return new int[0];
+ }
+
+ /** @hide */
+ public String getCecSettingStringValue(String name) {
return "";
}
/** @hide */
- public void setCecSettingValue(String name, String value) {}
+ public void setCecSettingStringValue(String name, String value) {
+ }
+
+ /** @hide */
+ public int getCecSettingIntValue(String name) {
+ return 0;
+ }
+
+ /** @hide */
+ public void setCecSettingIntValue(String name, int value) {
+ }
}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 6df164bb71dc..af9d3accd00e 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -88,7 +88,10 @@ interface IHdmiControlService {
void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute);
void setSystemAudioModeOnForAudioOnlySource();
List<String> getUserCecSettings();
- List<String> getAllowedCecSettingValues(String name);
- String getCecSettingValue(String name);
- void setCecSettingValue(String name, String value);
+ List<String> getAllowedCecSettingStringValues(String name);
+ int[] getAllowedCecSettingIntValues(String name);
+ String getCecSettingStringValue(String name);
+ void setCecSettingStringValue(String name, String value);
+ int getCecSettingIntValue(String name);
+ void setCecSettingIntValue(String name, int value);
}
diff --git a/core/java/android/hardware/iris/IIrisService.aidl b/core/java/android/hardware/iris/IIrisService.aidl
index b9eca3b5ddc5..3d26318343be 100644
--- a/core/java/android/hardware/iris/IIrisService.aidl
+++ b/core/java/android/hardware/iris/IIrisService.aidl
@@ -22,5 +22,5 @@ package android.hardware.iris;
*/
interface IIrisService {
// Give IrisService its ID. See AuthService.java
- void initializeConfiguration(int sensorId);
+ void initializeConfiguration(int sensorId, int strength);
}
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 1ed791d66f74..d44480796d75 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -654,7 +654,7 @@ public final class ContextHubManager {
* register a {@link android.hardware.location.ContextHubClientCallback}.
*/
@Deprecated
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public int registerCallback(@NonNull Callback callback) {
return registerCallback(callback, null);
}
@@ -688,7 +688,7 @@ public final class ContextHubManager {
* register a {@link android.hardware.location.ContextHubClientCallback}.
*/
@Deprecated
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public int registerCallback(Callback callback, Handler handler) {
synchronized(this) {
if (mCallback != null) {
@@ -892,7 +892,7 @@ public final class ContextHubManager {
* @deprecated Use {@link android.hardware.location.ContextHubClient#close()} to unregister
* a {@link android.hardware.location.ContextHubClientCallback}.
*/
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
@Deprecated
public int unregisterCallback(@NonNull Callback callback) {
synchronized(this) {
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index 0edd05533dd3..969db96561d7 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -257,6 +257,7 @@ public abstract class RadioTuner {
* @throws IllegalArgumentException if id==0
* @hide This API is not thoroughly elaborated yet
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract @Nullable Bitmap getMetadataImage(int id);
/**
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 21634cc544e7..1c35cb66ada8 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -299,7 +299,7 @@ public class UsbDeviceConnection {
* @hide
*/
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public boolean resetDevice() {
return native_reset_device();
}
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 3ca5207d867c..cd436374b489 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -202,6 +202,7 @@ public abstract class AbstractInputMethodService extends Service
* @param args The arguments passed to the dump method.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
abstract void dumpProtoInternal(FileDescriptor fd, String[] args);
/**
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 32a8c0af0c01..44640c44332e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -46,6 +46,7 @@ import static android.inputmethodservice.InputMethodServiceProto.STATUS_ICON;
import static android.inputmethodservice.InputMethodServiceProto.TOKEN;
import static android.inputmethodservice.InputMethodServiceProto.VIEWS_CREATED;
import static android.inputmethodservice.InputMethodServiceProto.WINDOW_VISIBLE;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowInsets.Type.navigationBars;
@@ -80,6 +81,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.os.SystemClock;
+import android.os.Trace;
import android.provider.Settings;
import android.text.InputType;
import android.text.Layout;
@@ -645,7 +647,9 @@ public class InputMethodService extends AbstractInputMethodService {
@Override
public void startInput(InputConnection ic, EditorInfo attribute) {
if (DEBUG) Log.v(TAG, "startInput(): editor=" + attribute);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.startInput");
doStartInput(ic, attribute, false);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
@@ -705,6 +709,8 @@ public class InputMethodService extends AbstractInputMethodService {
return;
}
final boolean wasVisible = isInputViewShown();
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
+
applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */);
mShowInputFlags = 0;
mShowInputRequested = false;
@@ -717,6 +723,7 @@ public class InputMethodService extends AbstractInputMethodService {
: (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
: InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
@@ -748,6 +755,13 @@ public class InputMethodService extends AbstractInputMethodService {
+ " Use requestShowSelf(int) itself");
return;
}
+
+ if (Trace.isEnabled()) {
+ Binder.enableTracing();
+ } else {
+ Binder.disableTracing();
+ }
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput");
final boolean wasVisible = isInputViewShown();
if (dispatchOnShowInputRequested(flags, false)) {
@@ -764,6 +778,7 @@ public class InputMethodService extends AbstractInputMethodService {
: (wasVisible ? InputMethodManager.RESULT_UNCHANGED_SHOWN
: InputMethodManager.RESULT_UNCHANGED_HIDDEN), null);
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/**
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 224113fc29cb..4b38d6377f37 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -4816,4 +4816,9 @@ public class ConnectivityManager {
e.rethrowFromSystemServer();
}
}
+
+ private void setOemNetworkPreference(@NonNull OemNetworkPreferences preference) {
+ Log.d(TAG, "setOemNetworkPreference called with preference: "
+ + preference.toString());
+ }
}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 209a3fa839c0..923b9b76a1a5 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -20,12 +20,13 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.LinkPropertiesUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.net.module.util.LinkPropertiesUtils;
+
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 049e9bcc2509..c83c23a4b66e 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -20,13 +20,13 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.MacAddressUtils;
import android.net.wifi.WifiInfo;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
+import com.android.net.module.util.MacAddressUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/net/OemNetworkPreferences.aidl b/core/java/android/net/OemNetworkPreferences.aidl
new file mode 100644
index 000000000000..2b6a4ceef592
--- /dev/null
+++ b/core/java/android/net/OemNetworkPreferences.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.net;
+
+parcelable OemNetworkPreferences;
diff --git a/core/java/android/net/OemNetworkPreferences.java b/core/java/android/net/OemNetworkPreferences.java
new file mode 100644
index 000000000000..6a8e3f9c01f2
--- /dev/null
+++ b/core/java/android/net/OemNetworkPreferences.java
@@ -0,0 +1,193 @@
+/*
+ * 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.net;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/** @hide */
+public final class OemNetworkPreferences implements Parcelable {
+ /**
+ * Use default behavior requesting networks. Equivalent to not setting any preference at all.
+ */
+ public static final int OEM_NETWORK_PREFERENCE_DEFAULT = 0;
+
+ /**
+ * If an unmetered network is available, use it.
+ * Otherwise, if a network with the OEM_PAID capability is available, use it.
+ * Otherwise, use the general default network.
+ */
+ public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1;
+
+ /**
+ * If an unmetered network is available, use it.
+ * Otherwise, if a network with the OEM_PAID capability is available, use it.
+ * Otherwise, the app doesn't get a network.
+ */
+ public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2;
+
+ /**
+ * Prefer only NET_CAPABILITY_OEM_PAID networks.
+ */
+ public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3;
+
+ /**
+ * Prefer only NET_CAPABILITY_OEM_PRIVATE networks.
+ */
+ public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4;
+
+ @NonNull
+ private final SparseArray<List<String>> mNetworkMappings;
+
+ @NonNull
+ public SparseArray<List<String>> getNetworkPreferences() {
+ return mNetworkMappings.clone();
+ }
+
+ private OemNetworkPreferences(@NonNull SparseArray<List<String>> networkMappings) {
+ Objects.requireNonNull(networkMappings);
+ mNetworkMappings = networkMappings.clone();
+ }
+
+ @Override
+ public String toString() {
+ return "OemNetworkPreferences{" + "mNetworkMappings=" + mNetworkMappings + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ OemNetworkPreferences that = (OemNetworkPreferences) o;
+
+ return mNetworkMappings.size() == that.mNetworkMappings.size()
+ && mNetworkMappings.toString().equals(that.mNetworkMappings.toString());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNetworkMappings);
+ }
+
+ /**
+ * Builder used to create {@link OemNetworkPreferences} objects. Specify the preferred Network
+ * to package name mappings.
+ *
+ * @hide
+ */
+ public static final class Builder {
+ private final SparseArray<List<String>> mNetworkMappings;
+
+ public Builder() {
+ mNetworkMappings = new SparseArray<>();
+ }
+
+ /**
+ * Add a network preference for a list of packages.
+ *
+ * @param preference the desired network preference to use
+ * @param packages full package names (e.g.: "com.google.apps.contacts") for apps to use
+ * the given preference
+ * @return The builder to facilitate chaining.
+ */
+ @NonNull
+ public Builder addNetworkPreference(@OemNetworkPreference final int preference,
+ @NonNull List<String> packages) {
+ Objects.requireNonNull(packages);
+ mNetworkMappings.put(preference,
+ Collections.unmodifiableList(new ArrayList<>(packages)));
+ return this;
+ }
+
+ /**
+ * Build {@link OemNetworkPreferences} return the current OEM network preferences.
+ */
+ @NonNull
+ public OemNetworkPreferences build() {
+ return new OemNetworkPreferences(mNetworkMappings);
+ }
+ }
+
+ /** @hide */
+ @IntDef(prefix = "OEM_NETWORK_PREFERENCE_", value = {
+ OEM_NETWORK_PREFERENCE_DEFAULT,
+ OEM_NETWORK_PREFERENCE_OEM_PAID,
+ OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK,
+ OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY,
+ OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface OemNetworkPreference {}
+
+ /**
+ * Return the string value for OemNetworkPreference
+ *
+ * @param value int value of OemNetworkPreference
+ * @return string version of OemNetworkPreference
+ */
+ @NonNull
+ public static String oemNetworkPreferenceToString(@OemNetworkPreference int value) {
+ switch (value) {
+ case OEM_NETWORK_PREFERENCE_DEFAULT:
+ return "OEM_NETWORK_PREFERENCE_DEFAULT";
+ case OEM_NETWORK_PREFERENCE_OEM_PAID:
+ return "OEM_NETWORK_PREFERENCE_OEM_PAID";
+ case OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK:
+ return "OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK";
+ case OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY:
+ return "OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY";
+ case OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY:
+ return "OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY";
+ default:
+ return Integer.toHexString(value);
+ }
+ }
+
+ @Override
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ dest.writeSparseArray(mNetworkMappings);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<OemNetworkPreferences> CREATOR =
+ new Parcelable.Creator<OemNetworkPreferences>() {
+ @Override
+ public OemNetworkPreferences[] newArray(int size) {
+ return new OemNetworkPreferences[size];
+ }
+
+ @Override
+ public OemNetworkPreferences createFromParcel(@NonNull android.os.Parcel in) {
+ return new OemNetworkPreferences(
+ in.readSparseArray(getClass().getClassLoader()));
+ }
+ };
+}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 2543aa3ab48a..5b6684ace052 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -21,11 +21,12 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.NetUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.net.module.util.NetUtils;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.Inet4Address;
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index a985e934ed3c..4e019cf0732e 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -301,7 +301,7 @@ public class TrafficStats {
* Changes only take effect during subsequent calls to
* {@link #tagSocket(Socket)}.
*/
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public static void setThreadStatsUid(int uid) {
NetworkManagementSocketTagger.setThreadSocketStatsUid(uid);
}
@@ -339,7 +339,7 @@ public class TrafficStats {
*
* @see #setThreadStatsUid(int)
*/
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public static void clearThreadStatsUid() {
NetworkManagementSocketTagger.setThreadSocketStatsUid(-1);
}
@@ -976,11 +976,17 @@ public class TrafficStats {
}
}
- // NOTE: keep these in sync with android_net_TrafficStats.cpp
- private static final int TYPE_RX_BYTES = 0;
- private static final int TYPE_RX_PACKETS = 1;
- private static final int TYPE_TX_BYTES = 2;
- private static final int TYPE_TX_PACKETS = 3;
- private static final int TYPE_TCP_RX_PACKETS = 4;
- private static final int TYPE_TCP_TX_PACKETS = 5;
+ // NOTE: keep these in sync with {@code com_android_server_net_NetworkStatsService.cpp}.
+ /** {@hide} */
+ public static final int TYPE_RX_BYTES = 0;
+ /** {@hide} */
+ public static final int TYPE_RX_PACKETS = 1;
+ /** {@hide} */
+ public static final int TYPE_TX_BYTES = 2;
+ /** {@hide} */
+ public static final int TYPE_TX_PACKETS = 3;
+ /** {@hide} */
+ public static final int TYPE_TCP_RX_PACKETS = 4;
+ /** {@hide} */
+ public static final int TYPE_TCP_TX_PACKETS = 5;
}
diff --git a/core/java/android/os/CombinedVibrationEffect.java b/core/java/android/os/CombinedVibrationEffect.java
index 77bfa577babd..c9ebc1b7a3c5 100644
--- a/core/java/android/os/CombinedVibrationEffect.java
+++ b/core/java/android/os/CombinedVibrationEffect.java
@@ -17,7 +17,12 @@
package android.os;
import android.annotation.NonNull;
+import android.util.SparseArray;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
@@ -29,11 +34,14 @@ import java.util.Objects;
* @hide
* @see VibrationEffect
*/
+@SuppressWarnings({"ParcelNotFinal", "ParcelCreator"}) // Parcel only extended here.
public abstract class CombinedVibrationEffect implements Parcelable {
private static final int PARCEL_TOKEN_MONO = 1;
+ private static final int PARCEL_TOKEN_STEREO = 2;
+ private static final int PARCEL_TOKEN_SEQUENTIAL = 3;
- /** @hide to prevent subclassing from outside of the framework */
- public CombinedVibrationEffect() {
+ /** Prevent subclassing from outside of the framework. */
+ CombinedVibrationEffect() {
}
/**
@@ -41,8 +49,8 @@ public abstract class CombinedVibrationEffect implements Parcelable {
*
* A synced vibration effect should be performed by multiple vibrators at the same time.
*
- * @param effect The {@link VibrationEffect} to perform
- * @return The desired combined effect.
+ * @param effect The {@link VibrationEffect} to perform.
+ * @return The synced effect.
*/
@NonNull
public static CombinedVibrationEffect createSynced(@NonNull VibrationEffect effect) {
@@ -51,6 +59,30 @@ public abstract class CombinedVibrationEffect implements Parcelable {
return combined;
}
+ /**
+ * Start creating a synced vibration effect.
+ *
+ * A synced vibration effect should be performed by multiple vibrators at the same time.
+ *
+ * @see CombinedVibrationEffect.SyncedCombination
+ */
+ @NonNull
+ public static SyncedCombination startSynced() {
+ return new SyncedCombination();
+ }
+
+ /**
+ * Start creating a sequential vibration effect.
+ *
+ * A sequential vibration effect should be performed by multiple vibrators in order.
+ *
+ * @see CombinedVibrationEffect.SequentialCombination
+ */
+ @NonNull
+ public static SequentialCombination startSequential() {
+ return new SequentialCombination();
+ }
+
@Override
public int describeContents() {
return 0;
@@ -60,6 +92,164 @@ public abstract class CombinedVibrationEffect implements Parcelable {
public abstract void validate();
/**
+ * A combination of haptic effects that should be played in multiple vibrators in sync.
+ *
+ * @hide
+ * @see CombinedVibrationEffect#startSynced()
+ */
+ public static final class SyncedCombination {
+
+ private final SparseArray<VibrationEffect> mEffects = new SparseArray<>();
+
+ SyncedCombination() {
+ }
+
+ /**
+ * Add or replace a one shot vibration effect to be performed by the specified vibrator.
+ *
+ * @param vibratorId The id of the vibrator that should perform this effect.
+ * @param effect The effect this vibrator should play.
+ * @return The {@link CombinedVibrationEffect.SyncedCombination} object to enable adding
+ * multiple effects in one chain.
+ * @see VibrationEffect#createOneShot(long, int)
+ */
+ @NonNull
+ public SyncedCombination addVibrator(int vibratorId, @NonNull VibrationEffect effect) {
+ mEffects.put(vibratorId, effect);
+ return this;
+ }
+
+ /**
+ * Combine all of the added effects into a combined effect.
+ *
+ * The {@link CombinedVibrationEffect.SyncedCombination} object is still valid after this
+ * call, so you can continue adding more effects to it and generating more
+ * {@link CombinedVibrationEffect}s by calling this method again.
+ *
+ * @return The {@link CombinedVibrationEffect} resulting from combining the added effects to
+ * be played in sync.
+ */
+ @NonNull
+ public CombinedVibrationEffect combine() {
+ if (mEffects.size() == 0) {
+ throw new IllegalStateException(
+ "Combination must have at least one element to combine.");
+ }
+ CombinedVibrationEffect combined = new Stereo(mEffects);
+ combined.validate();
+ return combined;
+ }
+ }
+
+ /**
+ * A combination of haptic effects that should be played in multiple vibrators in sequence.
+ *
+ * @hide
+ * @see CombinedVibrationEffect#startSequential()
+ */
+ public static final class SequentialCombination {
+
+ private final ArrayList<CombinedVibrationEffect> mEffects = new ArrayList<>();
+ private final ArrayList<Integer> mDelays = new ArrayList<>();
+
+ SequentialCombination() {
+ }
+
+ /**
+ * Add a single vibration effect to be performed next.
+ *
+ * Similar to {@link #addNext(int, VibrationEffect, int)}, but with no delay.
+ *
+ * @param vibratorId The id of the vibrator that should perform this effect.
+ * @param effect The effect this vibrator should play.
+ * @return The {@link CombinedVibrationEffect.SequentialCombination} object to enable adding
+ * multiple effects in one chain.
+ */
+ @NonNull
+ public SequentialCombination addNext(int vibratorId, @NonNull VibrationEffect effect) {
+ return addNext(vibratorId, effect, /* delay= */ 0);
+ }
+
+ /**
+ * Add a single vibration effect to be performed next.
+ *
+ * @param vibratorId The id of the vibrator that should perform this effect.
+ * @param effect The effect this vibrator should play.
+ * @param delay The amount of time, in milliseconds, to wait between playing the prior
+ * effect and this one.
+ * @return The {@link CombinedVibrationEffect.SequentialCombination} object to enable adding
+ * multiple effects in one chain.
+ */
+ @NonNull
+ public SequentialCombination addNext(int vibratorId, @NonNull VibrationEffect effect,
+ int delay) {
+ return addNext(
+ CombinedVibrationEffect.startSynced().addVibrator(vibratorId, effect).combine(),
+ delay);
+ }
+
+ /**
+ * Add a combined vibration effect to be performed next.
+ *
+ * Similar to {@link #addNext(CombinedVibrationEffect, int)}, but with no delay.
+ *
+ * @param effect The combined effect to be performed next.
+ * @return The {@link CombinedVibrationEffect.SequentialCombination} object to enable adding
+ * multiple effects in one chain.
+ * @see VibrationEffect#createOneShot(long, int)
+ */
+ @NonNull
+ public SequentialCombination addNext(@NonNull CombinedVibrationEffect effect) {
+ return addNext(effect, /* delay= */ 0);
+ }
+
+ /**
+ * Add a one shot vibration effect to be performed by the specified vibrator.
+ *
+ * @param effect The combined effect to be performed next.
+ * @param delay The amount of time, in milliseconds, to wait between playing the prior
+ * effect and this one.
+ * @return The {@link CombinedVibrationEffect.SequentialCombination} object to enable adding
+ * multiple effects in one chain.
+ */
+ @NonNull
+ public SequentialCombination addNext(@NonNull CombinedVibrationEffect effect, int delay) {
+ if (effect instanceof Sequential) {
+ Sequential sequentialEffect = (Sequential) effect;
+ int firstEffectIndex = mDelays.size();
+ mEffects.addAll(sequentialEffect.getEffects());
+ mDelays.addAll(sequentialEffect.getDelays());
+ mDelays.set(firstEffectIndex, delay + mDelays.get(firstEffectIndex));
+ } else {
+ mEffects.add(effect);
+ mDelays.add(delay);
+ }
+ return this;
+ }
+
+ /**
+ * Combine all of the added effects in sequence.
+ *
+ * The {@link CombinedVibrationEffect.SequentialCombination} object is still valid after
+ * this call, so you can continue adding more effects to it and generating more {@link
+ * CombinedVibrationEffect}s by calling this method again.
+ *
+ * @return The {@link CombinedVibrationEffect} resulting from combining the added effects to
+ * be played in sequence.
+ */
+ @NonNull
+ public CombinedVibrationEffect combine() {
+ if (mEffects.size() == 0) {
+ throw new IllegalStateException(
+ "Combination must have at least one element to combine.");
+ }
+ CombinedVibrationEffect combined = new Sequential(mEffects, mDelays);
+ combined.validate();
+ return combined;
+ }
+ }
+
+ /**
* Represents a single {@link VibrationEffect} that should be executed in all vibrators in sync.
*
* @hide
@@ -67,11 +257,11 @@ public abstract class CombinedVibrationEffect implements Parcelable {
public static final class Mono extends CombinedVibrationEffect {
private final VibrationEffect mEffect;
- public Mono(Parcel in) {
+ Mono(Parcel in) {
mEffect = VibrationEffect.CREATOR.createFromParcel(in);
}
- public Mono(@NonNull VibrationEffect effect) {
+ Mono(@NonNull VibrationEffect effect) {
mEffect = effect;
}
@@ -87,10 +277,10 @@ public abstract class CombinedVibrationEffect implements Parcelable {
@Override
public boolean equals(Object o) {
- if (!(o instanceof CombinedVibrationEffect.Mono)) {
+ if (!(o instanceof Mono)) {
return false;
}
- CombinedVibrationEffect.Mono other = (CombinedVibrationEffect.Mono) o;
+ Mono other = (Mono) o;
return other.mEffect.equals(other.mEffect);
}
@@ -128,6 +318,206 @@ public abstract class CombinedVibrationEffect implements Parcelable {
};
}
+ /**
+ * Represents a list of {@link VibrationEffect}s that should be executed in sync.
+ *
+ * @hide
+ */
+ public static final class Stereo extends CombinedVibrationEffect {
+
+ /** Mapping vibrator ids to effects. */
+ private final SparseArray<VibrationEffect> mEffects;
+
+ Stereo(Parcel in) {
+ int size = in.readInt();
+ mEffects = new SparseArray<>(size);
+ for (int i = 0; i < size; i++) {
+ int vibratorId = in.readInt();
+ mEffects.put(vibratorId, VibrationEffect.CREATOR.createFromParcel(in));
+ }
+ }
+
+ Stereo(@NonNull SparseArray<VibrationEffect> effects) {
+ mEffects = new SparseArray<>(effects.size());
+ for (int i = 0; i < effects.size(); i++) {
+ mEffects.put(effects.keyAt(i), effects.valueAt(i));
+ }
+ }
+
+ /** Effects to be performed in sync, where each key represents the vibrator id. */
+ public SparseArray<VibrationEffect> getEffects() {
+ return mEffects;
+ }
+
+ /** @hide */
+ @Override
+ public void validate() {
+ Preconditions.checkArgument(mEffects.size() > 0,
+ "There should be at least one effect set for a combined effect");
+ for (int i = 0; i < mEffects.size(); i++) {
+ mEffects.valueAt(i).validate();
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Stereo)) {
+ return false;
+ }
+ Stereo other = (Stereo) o;
+ if (mEffects.size() != other.mEffects.size()) {
+ return false;
+ }
+ for (int i = 0; i < mEffects.size(); i++) {
+ if (!mEffects.valueAt(i).equals(other.mEffects.get(mEffects.keyAt(i)))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mEffects);
+ }
+
+ @Override
+ public String toString() {
+ return "Stereo{mEffects=" + mEffects + '}';
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(PARCEL_TOKEN_STEREO);
+ out.writeInt(mEffects.size());
+ for (int i = 0; i < mEffects.size(); i++) {
+ out.writeInt(mEffects.keyAt(i));
+ mEffects.valueAt(i).writeToParcel(out, flags);
+ }
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<Stereo> CREATOR =
+ new Parcelable.Creator<Stereo>() {
+ @Override
+ public Stereo createFromParcel(@NonNull Parcel in) {
+ // Skip the type token
+ in.readInt();
+ return new Stereo(in);
+ }
+
+ @Override
+ @NonNull
+ public Stereo[] newArray(int size) {
+ return new Stereo[size];
+ }
+ };
+ }
+
+ /**
+ * Represents a list of {@link VibrationEffect}s that should be executed in sequence.
+ *
+ * @hide
+ */
+ public static final class Sequential extends CombinedVibrationEffect {
+ private final List<CombinedVibrationEffect> mEffects;
+ private final List<Integer> mDelays;
+
+ Sequential(Parcel in) {
+ int size = in.readInt();
+ mEffects = new ArrayList<>(size);
+ mDelays = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ mDelays.add(in.readInt());
+ mEffects.add(CombinedVibrationEffect.CREATOR.createFromParcel(in));
+ }
+ }
+
+ Sequential(@NonNull List<CombinedVibrationEffect> effects,
+ @NonNull List<Integer> delays) {
+ mEffects = new ArrayList<>(effects);
+ mDelays = new ArrayList<>(delays);
+ }
+
+ /** Effects to be performed in sequence. */
+ public List<CombinedVibrationEffect> getEffects() {
+ return mEffects;
+ }
+
+ /** Delay to be applied before each effect in {@link #getEffects()}. */
+ public List<Integer> getDelays() {
+ return mDelays;
+ }
+
+ /** @hide */
+ @Override
+ public void validate() {
+ Preconditions.checkArgument(mEffects.size() > 0,
+ "There should be at least one effect set for a combined effect");
+ Preconditions.checkArgument(mEffects.size() == mDelays.size(),
+ "Effect and delays should have equal length");
+ for (long delay : mDelays) {
+ if (delay < 0) {
+ throw new IllegalArgumentException("Delays must all be >= 0"
+ + " (delays=" + mDelays + ")");
+ }
+ }
+ for (CombinedVibrationEffect effect : mEffects) {
+ if (effect instanceof Sequential) {
+ throw new IllegalArgumentException(
+ "There should be no nested sequential effects in a combined effect");
+ }
+ effect.validate();
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Sequential)) {
+ return false;
+ }
+ Sequential other = (Sequential) o;
+ return mDelays.equals(other.mDelays) && mEffects.equals(other.mEffects);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mEffects);
+ }
+
+ @Override
+ public String toString() {
+ return "Sequential{mEffects=" + mEffects + ", mDelays=" + mDelays + '}';
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(PARCEL_TOKEN_SEQUENTIAL);
+ out.writeInt(mEffects.size());
+ for (int i = 0; i < mEffects.size(); i++) {
+ out.writeInt(mDelays.get(i));
+ mEffects.get(i).writeToParcel(out, flags);
+ }
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<Sequential> CREATOR =
+ new Parcelable.Creator<Sequential>() {
+ @Override
+ public Sequential createFromParcel(@NonNull Parcel in) {
+ // Skip the type token
+ in.readInt();
+ return new Sequential(in);
+ }
+
+ @Override
+ @NonNull
+ public Sequential[] newArray(int size) {
+ return new Sequential[size];
+ }
+ };
+ }
+
@NonNull
public static final Parcelable.Creator<CombinedVibrationEffect> CREATOR =
new Parcelable.Creator<CombinedVibrationEffect>() {
@@ -135,7 +525,11 @@ public abstract class CombinedVibrationEffect implements Parcelable {
public CombinedVibrationEffect createFromParcel(Parcel in) {
int token = in.readInt();
if (token == PARCEL_TOKEN_MONO) {
- return new CombinedVibrationEffect.Mono(in);
+ return new Mono(in);
+ } else if (token == PARCEL_TOKEN_STEREO) {
+ return new Stereo(in);
+ } else if (token == PARCEL_TOKEN_SEQUENTIAL) {
+ return new Sequential(in);
} else {
throw new IllegalStateException(
"Unexpected combined vibration event type token in parcel.");
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index d151c16061d9..5db4107f02f1 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1436,7 +1436,10 @@ public final class FileUtils {
public static FileDescriptor convertToModernFd(FileDescriptor fd) {
try {
Context context = AppGlobals.getInitialApplication();
- if (UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
+ if (!SystemProperties.getBoolean("persist.sys.fuse.transcode", false)
+ || !SystemProperties.getBoolean("persist.sys.fuse.transcode_optimize", true)
+ || UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
+ // If transcode is enabled we optimize by default, unless explicitly disabled.
// Never convert modern fd for MediaProvider, because this requires
// MediaStore#scanFile and can cause infinite loops when MediaProvider scans
return null;
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index d91c458a474b..010459d06e8d 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -170,6 +170,15 @@ public interface IBinder {
int FLAG_ONEWAY = 0x00000001;
/**
+ * Flag to {@link #transact}: request binder driver to clear transaction data.
+ *
+ * Be very careful when using this flag in Java, since Java objects read from a Java
+ * Parcel may be non-trivial to clear.
+ * @hide
+ */
+ int FLAG_CLEAR_BUF = 0x00000020;
+
+ /**
* @hide
*/
int FLAG_COLLECT_NOTED_APP_OPS = 0x00000002;
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index a04fcb580e63..52427506b3ef 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -300,6 +300,8 @@ public final class Parcel {
private static final int EX_TRANSACTION_FAILED = -129;
@CriticalNative
+ private static native void nativeMarkSensitive(long nativePtr);
+ @CriticalNative
private static native int nativeDataSize(long nativePtr);
@CriticalNative
private static native int nativeDataAvail(long nativePtr);
@@ -522,6 +524,14 @@ public final class Parcel {
public static native long getGlobalAllocCount();
/**
+ * Parcel data should be zero'd before realloc'd or deleted.
+ * @hide
+ */
+ public final void markSensitive() {
+ nativeMarkSensitive(mNativePtr);
+ }
+
+ /**
* Returns the total amount of data contained in the parcel.
*/
public final int dataSize() {
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 13b30f43ff7a..72cd8ba204fd 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -422,7 +422,7 @@ public class RecoverySystem {
* {@hide}
*/
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public static boolean verifyPackageCompatibility(File compatibilityFile) throws IOException {
try (InputStream inputStream = new FileInputStream(compatibilityFile)) {
return verifyPackageCompatibility(inputStream);
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index ded9be5eb74a..ab741990430f 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -60,7 +60,7 @@ public class SystemProperties {
* uses reflection to read this whenever text is selected (http://b/36095274).
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @UnsupportedAppUsage(trackingBug = 172649311)
public static final int PROP_NAME_MAX = Integer.MAX_VALUE;
/** @hide */
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 2edd3227cf36..aba1f281c583 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4033,7 +4033,8 @@ public class UserManager {
* @return the {@link RemoveResult} code
* @hide
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
+ Manifest.permission.CREATE_USERS})
public @RemoveResult int removeUserOrSetEphemeral(@UserIdInt int userId) {
try {
return mService.removeUserOrSetEphemeral(userId);
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index e0927ebd261a..6588b5748d09 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -435,6 +435,7 @@ public class WorkSource implements Parcelable {
for (WorkChain wc : other.mChains) {
if (!mChains.contains(wc)) {
mChains.add(new WorkChain(wc));
+ chainAdded = true;
}
}
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 5d3c66cc3f34..cfc3e01c23c5 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -2215,7 +2215,7 @@ public class StorageManager {
/** @hide */
@SystemApi
@WorkerThread
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public long getAllocatableBytes(@NonNull UUID storageUuid,
@RequiresPermission @AllocateFlags int flags) throws IOException {
try {
@@ -2264,7 +2264,7 @@ public class StorageManager {
/** @hide */
@SystemApi
@WorkerThread
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
try {
@@ -2314,7 +2314,7 @@ public class StorageManager {
/** @hide */
@SystemApi
@WorkerThread
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
final File file = ParcelFileDescriptor.getFile(fd);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cc3d92da7352..8093ff50bccf 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7761,6 +7761,21 @@ public final class Settings {
"minimal_post_processing_allowed";
/**
+ * User's preference for refresh rate switching.
+ *
+ * <p>Values:
+ * 0 - Never switch refresh rates.
+ * 1 - Switch refresh rates only when it can be done seamlessly. (Default behaviour)
+ * 2 - Always prefer refresh rate switching even if it's going to have visual interruptions
+ * for the user.
+ *
+ * @see android.view.Surface#setFrameRate
+ * @hide
+ */
+ public static final String MATCH_CONTENT_FRAME_RATE =
+ "match_content_frame_rate";
+
+ /**
* INCALL_POWER_BUTTON_BEHAVIOR value for "turn off screen".
* @hide
*/
@@ -9773,6 +9788,14 @@ public final class Settings {
public static final String DEVELOPMENT_USE_BLAST_ADAPTER_SV =
"use_blast_adapter_sv";
+ /**
+ * If {@code true}, vendor provided window manager display settings will be ignored.
+ * (0 = false, 1 = true)
+ * @hide
+ */
+ public static final String DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS =
+ "ignore_vendor_display_settings";
+
/**
* Whether user has enabled development settings.
*/
@@ -10700,7 +10723,7 @@ public final class Settings {
* 0 = Disabled
* 1 = Enabled
*
- * Most readers of this setting should simply check if value == 1 to determined the
+ * Most readers of this setting should simply check if value == 1 to determine the
* enabled state.
* @hide
* @deprecated To be removed.
@@ -14283,18 +14306,17 @@ public final class Settings {
"backup_agent_timeout_parameters";
/**
- * Blacklist of GNSS satellites.
+ * Blocklist of GNSS satellites.
*
* This is a list of integers separated by commas to represent pairs of (constellation,
* svid). Thus, the number of integers should be even.
*
* E.g.: "3,0,5,24" denotes (constellation=3, svid=0) and (constellation=5, svid=24) are
- * blacklisted. Note that svid=0 denotes all svids in the
- * constellation are blacklisted.
+ * blocklisted. Note that svid=0 denotes all svids in the constellation are blocklisted.
*
* @hide
*/
- public static final String GNSS_SATELLITE_BLACKLIST = "gnss_satellite_blacklist";
+ public static final String GNSS_SATELLITE_BLOCKLIST = "gnss_satellite_blocklist";
/**
* Duration of updates in millisecond for GNSS location request from HAL to framework.
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index f08756a015b2..e32ffa6e9d05 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -157,6 +157,11 @@ public final class KeymasterDefs {
public static final int HW_AUTH_PASSWORD = 1 << 0;
public static final int HW_AUTH_BIOMETRIC = 1 << 1;
+ // Security Levels.
+ public static final int KM_SECURITY_LEVEL_SOFTWARE = 0;
+ public static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1;
+ public static final int KM_SECURITY_LEVEL_STRONGBOX = 2;
+
// Error codes.
public static final int KM_ERROR_OK = 0;
public static final int KM_ERROR_ROOT_OF_TRUST_ALREADY_SET = -1;
diff --git a/core/java/android/service/attestation/IImpressionAttestationService.aidl b/core/java/android/service/attestation/IImpressionAttestationService.aidl
new file mode 100644
index 000000000000..8e858b8aea77
--- /dev/null
+++ b/core/java/android/service/attestation/IImpressionAttestationService.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.attestation;
+
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.service.attestation.ImpressionToken;
+import android.os.RemoteCallback;
+
+/**
+ * Service used to handle impression attestation requests.
+ *
+ * @hide
+ */
+oneway interface IImpressionAttestationService {
+ /**
+ * Generates the impression token that can be used to validate that the system generated the
+ * token.
+ *
+ * @param screenshot The token for the window where the view is shown.
+ * @param bounds The size and position of the content being attested in the window.
+ * @param hashAlgorithm The String for the hashing algorithm to use based on values in
+ * {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS}.
+ * @param Callback The callback invoked to send back the impression token.
+ */
+ void generateImpressionToken(in HardwareBuffer screenshot, in Rect bounds,
+ in String hashAlgorithm, in RemoteCallback callback);
+
+ /**
+ * Call to verify that the impressionToken passed in was generated by the system. The result
+ * will be sent in the callback as an integer with the key {@link #EXTRA_VERIFICATION_STATUS}
+ * and will be one of the values in {@link VerificationStatus}.
+ *
+ * @param impressionToken The token to verify that it was generated by the system.
+ * @param callback The callback invoked to send back the verification status.
+ */
+ void verifyImpressionToken(in ImpressionToken impressionToken, in RemoteCallback callback);
+}
diff --git a/core/java/android/service/attestation/ImpressionAttestationService.java b/core/java/android/service/attestation/ImpressionAttestationService.java
new file mode 100644
index 000000000000..4919f5d8856f
--- /dev/null
+++ b/core/java/android/service/attestation/ImpressionAttestationService.java
@@ -0,0 +1,152 @@
+/*
+ * 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.attestation;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteCallback;
+
+/**
+ * A service that handles generating and verify ImpressionTokens.
+ *
+ * The service will generate an ImpressionToken based on arguments passed in. Then later that same
+ * ImpressionToken can be verified to determine that it was created by the system.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class ImpressionAttestationService extends Service {
+ /** @hide **/
+ public static final String EXTRA_IMPRESSION_TOKEN =
+ "android.service.attestation.extra.IMPRESSION_TOKEN";
+
+ /** @hide **/
+ public static final String EXTRA_VERIFICATION_STATUS =
+ "android.service.attestation.extra.VERIFICATION_STATUS";
+
+ /** @hide */
+ @IntDef(prefix = {"VERIFICATION_STATUS_"}, value = {
+ VERIFICATION_STATUS_UNKNOWN,
+ VERIFICATION_STATUS_OS_VERIFIED,
+ VERIFICATION_STATUS_APP_DECLARED
+ })
+ public @interface VerificationStatus {
+ }
+
+ public static final int VERIFICATION_STATUS_UNKNOWN = 0;
+ public static final int VERIFICATION_STATUS_OS_VERIFIED = 1;
+ public static final int VERIFICATION_STATUS_APP_DECLARED = 2;
+
+ /**
+ * Manifest metadata key for the resource string array containing the names of all impression
+ * attestation algorithms provided by the service.
+ * @hide
+ */
+ public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS =
+ "android.attestation.available_algorithms";
+
+ private ImpressionAttestationServiceWrapper mWrapper;
+ private Handler mHandler;
+
+ public ImpressionAttestationService() {
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mWrapper = new ImpressionAttestationServiceWrapper();
+ mHandler = new Handler(Looper.getMainLooper(), null, true);
+ }
+
+ @NonNull
+ @Override
+ public final IBinder onBind(@NonNull Intent intent) {
+ return mWrapper;
+ }
+
+ /**
+ * Generates the impression token that can be used to validate that the system
+ * generated the token.
+ *
+ * @param screenshot The screenshot buffer for the content to attest.
+ * @param bounds The size and position of the content being attested in the window.
+ * @param hashAlgorithm The String for the hashing algorithm to use based values in
+ * {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS)}.
+ * @return An impression token that can be used to validate information about the content.
+ * Returns null when the arguments sent are invalid.
+ */
+ @Nullable
+ public abstract ImpressionToken onGenerateImpressionToken(@NonNull HardwareBuffer screenshot,
+ @NonNull Rect bounds, @NonNull String hashAlgorithm);
+
+ /**
+ * Call to verify that the impressionToken passed in was generated by the system.
+ *
+ * @param impressionToken The token to verify that it was generated by the system.
+ * @return A {@link VerificationStatus} about whether the token was generated by the system.
+ */
+ public abstract @VerificationStatus int onVerifyImpressionToken(
+ @NonNull ImpressionToken impressionToken);
+
+ private void generateImpressionToken(HardwareBuffer screenshot, Rect bounds,
+ String hashAlgorithm, RemoteCallback callback) {
+ ImpressionToken impressionToken = onGenerateImpressionToken(screenshot, bounds,
+ hashAlgorithm);
+ final Bundle data = new Bundle();
+ data.putParcelable(EXTRA_IMPRESSION_TOKEN, impressionToken);
+ callback.sendResult(data);
+ }
+
+ private void verifyImpressionToken(ImpressionToken impressionToken,
+ RemoteCallback callback) {
+ @VerificationStatus int verificationStatus = onVerifyImpressionToken(impressionToken);
+ final Bundle data = new Bundle();
+ data.putInt(EXTRA_VERIFICATION_STATUS, verificationStatus);
+ callback.sendResult(data);
+ }
+
+ private final class ImpressionAttestationServiceWrapper extends
+ IImpressionAttestationService.Stub {
+ @Override
+ public void generateImpressionToken(HardwareBuffer screenshot, Rect bounds,
+ String hashAlgorithm, RemoteCallback callback) {
+ mHandler.sendMessage(
+ obtainMessage(ImpressionAttestationService::generateImpressionToken,
+ ImpressionAttestationService.this, screenshot, bounds, hashAlgorithm,
+ callback));
+ }
+
+ @Override
+ public void verifyImpressionToken(ImpressionToken impressionToken,
+ RemoteCallback callback) {
+ mHandler.sendMessage(obtainMessage(ImpressionAttestationService::verifyImpressionToken,
+ ImpressionAttestationService.this, impressionToken, callback));
+ }
+ }
+}
diff --git a/core/java/android/service/attestation/ImpressionToken.aidl b/core/java/android/service/attestation/ImpressionToken.aidl
new file mode 100644
index 000000000000..284a4ba68a06
--- /dev/null
+++ b/core/java/android/service/attestation/ImpressionToken.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.attestation;
+
+parcelable ImpressionToken; \ No newline at end of file
diff --git a/core/java/android/service/attestation/ImpressionToken.java b/core/java/android/service/attestation/ImpressionToken.java
new file mode 100644
index 000000000000..4355dc04462a
--- /dev/null
+++ b/core/java/android/service/attestation/ImpressionToken.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 android.service.attestation;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.graphics.Rect;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * The ads impression token used to validate information about what was present on screen.
+ * @hide
+ *
+ * TODO: Remove hide and SystemAPI since this will be a public class
+ */
+@SystemApi
+@DataClass(genToString = true, genAidl = true)
+public final class ImpressionToken implements Parcelable {
+ /**
+ * The timestamp when the screenshot was generated.
+ */
+ private final long mScreenshotTimeMillis;
+
+ /**
+ * The bounds of the requested area to take the screenshot. This is in window space passed in
+ * by the client.
+ */
+ private @NonNull final Rect mBoundsInWindow;
+
+ /**
+ * The selected hashing algorithm that generated the image hash.
+ */
+ private @NonNull final String mHashingAlgorithm;
+
+ /**
+ * The image hash generated when creating the impression token from the screenshot taken.
+ */
+ private @NonNull final byte[] mImageHash;
+
+ /**
+ * The hmac generated by the system and used to verify whether this token was generated by
+ * the system. This should only be accessed by a system process.
+ */
+ private @NonNull final byte[] mHmac;
+
+ /**
+ * The hmac generated by the system and used to verify whether this token was generated by
+ * the system. This should only be accessed by a system process.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull byte[] getHmac() {
+ return mHmac;
+ }
+
+
+
+ // Code below generated by codegen v1.0.18.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/attestation/ImpressionToken.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new ImpressionToken.
+ *
+ * @param screenshotTimeMillis
+ * The timestamp when the screenshot was generated.
+ * @param boundsInWindow
+ * The bounds of the requested area to take the screenshot. This is in window space passed in
+ * by the client.
+ * @param hashingAlgorithm
+ * The selected hashing algorithm that generated the image hash.
+ * @param imageHash
+ * The image hash generated when creating the impression token from the screenshot taken.
+ * @param hmac
+ * The hmac generated by the system and used to verify whether this token was generated by
+ * the system. This should only be accessed by a system process.
+ */
+ @DataClass.Generated.Member
+ public ImpressionToken(
+ long screenshotTimeMillis,
+ @NonNull Rect boundsInWindow,
+ @NonNull String hashingAlgorithm,
+ @NonNull byte[] imageHash,
+ @NonNull byte[] hmac) {
+ this.mScreenshotTimeMillis = screenshotTimeMillis;
+ this.mBoundsInWindow = boundsInWindow;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mBoundsInWindow);
+ this.mHashingAlgorithm = hashingAlgorithm;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mHashingAlgorithm);
+ this.mImageHash = imageHash;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mImageHash);
+ this.mHmac = hmac;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mHmac);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * The timestamp when the screenshot was generated.
+ */
+ @DataClass.Generated.Member
+ public long getScreenshotTimeMillis() {
+ return mScreenshotTimeMillis;
+ }
+
+ /**
+ * The bounds of the requested area to take the screenshot. This is in window space passed in
+ * by the client.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Rect getBoundsInWindow() {
+ return mBoundsInWindow;
+ }
+
+ /**
+ * The selected hashing algorithm that generated the image hash.
+ */
+ @DataClass.Generated.Member
+ public @NonNull String getHashingAlgorithm() {
+ return mHashingAlgorithm;
+ }
+
+ /**
+ * The image hash generated when creating the impression token from the screenshot taken.
+ */
+ @DataClass.Generated.Member
+ public @NonNull byte[] getImageHash() {
+ return mImageHash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "ImpressionToken { " +
+ "screenshotTimeMillis = " + mScreenshotTimeMillis + ", " +
+ "boundsInWindow = " + mBoundsInWindow + ", " +
+ "hashingAlgorithm = " + mHashingAlgorithm + ", " +
+ "imageHash = " + java.util.Arrays.toString(mImageHash) + ", " +
+ "hmac = " + java.util.Arrays.toString(mHmac) +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeLong(mScreenshotTimeMillis);
+ dest.writeTypedObject(mBoundsInWindow, flags);
+ dest.writeString(mHashingAlgorithm);
+ dest.writeByteArray(mImageHash);
+ dest.writeByteArray(mHmac);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ ImpressionToken(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ long screenshotTimeMillis = in.readLong();
+ Rect boundsInWindow = (Rect) in.readTypedObject(Rect.CREATOR);
+ String hashingAlgorithm = in.readString();
+ byte[] imageHash = in.createByteArray();
+ byte[] hmac = in.createByteArray();
+
+ this.mScreenshotTimeMillis = screenshotTimeMillis;
+ this.mBoundsInWindow = boundsInWindow;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mBoundsInWindow);
+ this.mHashingAlgorithm = hashingAlgorithm;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mHashingAlgorithm);
+ this.mImageHash = imageHash;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mImageHash);
+ this.mHmac = hmac;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mHmac);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<ImpressionToken> CREATOR
+ = new Parcelable.Creator<ImpressionToken>() {
+ @Override
+ public ImpressionToken[] newArray(int size) {
+ return new ImpressionToken[size];
+ }
+
+ @Override
+ public ImpressionToken createFromParcel(@NonNull Parcel in) {
+ return new ImpressionToken(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1604539951959L,
+ codegenVersion = "1.0.18",
+ sourceFile = "frameworks/base/core/java/android/service/attestation/ImpressionToken.java",
+ inputSignatures = "private final long mScreenshotTimeMillis\nprivate final @android.annotation.NonNull android.graphics.Rect mBoundsInWindow\nprivate final @android.annotation.NonNull java.lang.String mHashingAlgorithm\nprivate final @android.annotation.NonNull byte[] mImageHash\nprivate final @android.annotation.NonNull byte[] mHmac\npublic @android.annotation.SystemApi @android.annotation.NonNull byte[] getHmac()\nclass ImpressionToken extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genAidl=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/service/autofill/InlinePresentation.java b/core/java/android/service/autofill/InlinePresentation.java
index 6eb2a15eec44..fbf23b69addf 100644
--- a/core/java/android/service/autofill/InlinePresentation.java
+++ b/core/java/android/service/autofill/InlinePresentation.java
@@ -77,7 +77,7 @@ public final class InlinePresentation implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -259,10 +259,10 @@ public final class InlinePresentation implements Parcelable {
};
@DataClass.Generated(
- time = 1596484869201L,
- codegenVersion = "1.0.15",
+ time = 1604456277638L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/service/autofill/InlinePresentation.java",
- inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final boolean mPinned\npublic @android.annotation.NonNull @android.annotation.Size(min=0L) java.lang.String[] getAutofillHints()\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
+ inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final boolean mPinned\npublic @android.annotation.NonNull @android.annotation.Size java.lang.String[] getAutofillHints()\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/autofill/InternalTransformation.java b/core/java/android/service/autofill/InternalTransformation.java
index 0dba2b9bb9a6..d31ea99470cf 100644
--- a/core/java/android/service/autofill/InternalTransformation.java
+++ b/core/java/android/service/autofill/InternalTransformation.java
@@ -45,6 +45,7 @@ public abstract class InternalTransformation implements Transformation, Parcelab
* @param template the {@link RemoteViews presentation template}.
* @param childViewId resource id of the child view inside the template.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
abstract void apply(@NonNull ValueFinder finder, @NonNull RemoteViews template,
int childViewId) throws Exception;
diff --git a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
index 2a809b1f099b..4ffffc6870cb 100644
--- a/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
+++ b/core/java/android/service/carrier/CarrierMessagingServiceWrapper.java
@@ -46,12 +46,13 @@ import java.util.List;
* CarrierMessagingService.
* @hide
*/
-public abstract class CarrierMessagingServiceWrapper {
+public final class CarrierMessagingServiceWrapper {
// Populated by bindToCarrierMessagingService. bindToCarrierMessagingService must complete
// prior to calling disposeConnection so that mCarrierMessagingServiceConnection is initialized.
private volatile CarrierMessagingServiceConnection mCarrierMessagingServiceConnection;
private volatile ICarrierMessagingService mICarrierMessagingService;
+ private Runnable mOnServiceReadyCallback;
/**
* Binds to the carrier messaging service under package {@code carrierPackageName}. This method
@@ -63,12 +64,14 @@ public abstract class CarrierMessagingServiceWrapper {
* @hide
*/
public boolean bindToCarrierMessagingService(@NonNull Context context,
- @NonNull String carrierPackageName) {
+ @NonNull String carrierPackageName,
+ @NonNull Runnable onServiceReadyCallback) {
Preconditions.checkState(mCarrierMessagingServiceConnection == null);
Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
intent.setPackage(carrierPackageName);
mCarrierMessagingServiceConnection = new CarrierMessagingServiceConnection();
+ mOnServiceReadyCallback = onServiceReadyCallback;
return context.bindService(intent, mCarrierMessagingServiceConnection,
Context.BIND_AUTO_CREATE);
}
@@ -83,22 +86,17 @@ public abstract class CarrierMessagingServiceWrapper {
Preconditions.checkNotNull(mCarrierMessagingServiceConnection);
context.unbindService(mCarrierMessagingServiceConnection);
mCarrierMessagingServiceConnection = null;
+ mOnServiceReadyCallback = null;
}
/**
- * Implemented by subclasses to use the carrier messaging service once it is ready.
- * @hide
- */
- public abstract void onServiceReady();
-
- /**
* Called when connection with service is established.
*
* @param carrierMessagingService the carrier messaing service interface
*/
private void onServiceReady(ICarrierMessagingService carrierMessagingService) {
mICarrierMessagingService = carrierMessagingService;
- onServiceReady();
+ if (mOnServiceReadyCallback != null) mOnServiceReadyCallback.run();
}
/**
@@ -113,11 +111,11 @@ public abstract class CarrierMessagingServiceWrapper {
* @hide
*/
public void filterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort,
- int subId, @NonNull final CarrierMessagingCallbackWrapper callback) {
+ int subId, @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.filterSms(pdu, format, destPort, subId,
- new CarrierMessagingCallbackWrapperInternal(callback));
+ new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -137,11 +135,11 @@ public abstract class CarrierMessagingServiceWrapper {
* @hide
*/
public void sendTextSms(@NonNull String text, int subId, @NonNull String destAddress,
- int sendSmsFlag, @NonNull final CarrierMessagingCallbackWrapper callback) {
+ int sendSmsFlag, @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.sendTextSms(text, subId, destAddress, sendSmsFlag,
- new CarrierMessagingCallbackWrapperInternal(callback));
+ new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -163,11 +161,11 @@ public abstract class CarrierMessagingServiceWrapper {
*/
public void sendDataSms(@NonNull byte[] data, int subId, @NonNull String destAddress,
int destPort, int sendSmsFlag,
- @NonNull final CarrierMessagingCallbackWrapper callback) {
+ @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.sendDataSms(data, subId, destAddress, destPort,
- sendSmsFlag, new CarrierMessagingCallbackWrapperInternal(callback));
+ sendSmsFlag, new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -188,11 +186,11 @@ public abstract class CarrierMessagingServiceWrapper {
*/
public void sendMultipartTextSms(@NonNull List<String> parts, int subId,
@NonNull String destAddress, int sendSmsFlag,
- @NonNull final CarrierMessagingCallbackWrapper callback) {
+ @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.sendMultipartTextSms(parts, subId, destAddress,
- sendSmsFlag, new CarrierMessagingCallbackWrapperInternal(callback));
+ sendSmsFlag, new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -212,11 +210,11 @@ public abstract class CarrierMessagingServiceWrapper {
* @hide
*/
public void sendMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
- @NonNull final CarrierMessagingCallbackWrapper callback) {
+ @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.sendMms(pduUri, subId, location,
- new CarrierMessagingCallbackWrapperInternal(callback));
+ new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -235,11 +233,11 @@ public abstract class CarrierMessagingServiceWrapper {
* @hide
*/
public void downloadMms(@NonNull Uri pduUri, int subId, @NonNull Uri location,
- @NonNull final CarrierMessagingCallbackWrapper callback) {
+ @NonNull final CarrierMessagingCallback callback) {
if (mICarrierMessagingService != null) {
try {
mICarrierMessagingService.downloadMms(pduUri, subId, location,
- new CarrierMessagingCallbackWrapperInternal(callback));
+ new CarrierMessagingCallbackInternal(callback));
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -265,7 +263,7 @@ public abstract class CarrierMessagingServiceWrapper {
* {@link CarrierMessagingServiceWrapper}.
* @hide
*/
- public abstract static class CarrierMessagingCallbackWrapper {
+ public interface CarrierMessagingCallback {
/**
* Response callback for {@link CarrierMessagingServiceWrapper#filterSms}.
@@ -277,7 +275,7 @@ public abstract class CarrierMessagingServiceWrapper {
* {@see CarrierMessagingService#onReceiveTextSms}.
* @hide
*/
- public void onFilterComplete(int result) {
+ default void onFilterComplete(int result) {
}
@@ -291,7 +289,7 @@ public abstract class CarrierMessagingServiceWrapper {
* only if result is {@link CarrierMessagingService#SEND_STATUS_OK}.
* @hide
*/
- public void onSendSmsComplete(int result, int messageRef) {
+ default void onSendSmsComplete(int result, int messageRef) {
}
@@ -305,7 +303,7 @@ public abstract class CarrierMessagingServiceWrapper {
* {@link CarrierMessagingService#SEND_STATUS_OK}.
* @hide
*/
- public void onSendMultipartSmsComplete(int result, @Nullable int[] messageRefs) {
+ default void onSendMultipartSmsComplete(int result, @Nullable int[] messageRefs) {
}
@@ -319,7 +317,7 @@ public abstract class CarrierMessagingServiceWrapper {
* {@link CarrierMessagingService#SEND_STATUS_OK}.
* @hide
*/
- public void onSendMmsComplete(int result, @Nullable byte[] sendConfPdu) {
+ default void onSendMmsComplete(int result, @Nullable byte[] sendConfPdu) {
}
@@ -330,43 +328,43 @@ public abstract class CarrierMessagingServiceWrapper {
* and {@link CarrierMessagingService#SEND_STATUS_ERROR}.
* @hide
*/
- public void onDownloadMmsComplete(int result) {
+ default void onDownloadMmsComplete(int result) {
}
}
- private final class CarrierMessagingCallbackWrapperInternal
+ private final class CarrierMessagingCallbackInternal
extends ICarrierMessagingCallback.Stub {
- CarrierMessagingCallbackWrapper mCarrierMessagingCallbackWrapper;
+ CarrierMessagingCallback mCarrierMessagingCallback;
- CarrierMessagingCallbackWrapperInternal(CarrierMessagingCallbackWrapper callback) {
- mCarrierMessagingCallbackWrapper = callback;
+ CarrierMessagingCallbackInternal(CarrierMessagingCallback callback) {
+ mCarrierMessagingCallback = callback;
}
@Override
public void onFilterComplete(int result) throws RemoteException {
- mCarrierMessagingCallbackWrapper.onFilterComplete(result);
+ mCarrierMessagingCallback.onFilterComplete(result);
}
@Override
public void onSendSmsComplete(int result, int messageRef) throws RemoteException {
- mCarrierMessagingCallbackWrapper.onSendSmsComplete(result, messageRef);
+ mCarrierMessagingCallback.onSendSmsComplete(result, messageRef);
}
@Override
public void onSendMultipartSmsComplete(int result, int[] messageRefs)
throws RemoteException {
- mCarrierMessagingCallbackWrapper.onSendMultipartSmsComplete(result, messageRefs);
+ mCarrierMessagingCallback.onSendMultipartSmsComplete(result, messageRefs);
}
@Override
public void onSendMmsComplete(int result, byte[] sendConfPdu) throws RemoteException {
- mCarrierMessagingCallbackWrapper.onSendMmsComplete(result, sendConfPdu);
+ mCarrierMessagingCallback.onSendMmsComplete(result, sendConfPdu);
}
@Override
public void onDownloadMmsComplete(int result) throws RemoteException {
- mCarrierMessagingCallbackWrapper.onDownloadMmsComplete(result);
+ mCarrierMessagingCallback.onDownloadMmsComplete(result);
}
}
-}
+} \ No newline at end of file
diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
index 0bf68b734b8a..8242f4e2c9dc 100644
--- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java
+++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
@@ -90,7 +90,7 @@ public class PersistentDataBlockManager {
*
* @param data the data to write
*/
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public int write(byte[] data) {
try {
return sService.write(data);
@@ -102,7 +102,7 @@ public class PersistentDataBlockManager {
/**
* Returns the data block stored on the persistent partition.
*/
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public byte[] read() {
try {
return sService.read();
@@ -130,7 +130,7 @@ public class PersistentDataBlockManager {
*
* Returns -1 on error.
*/
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public long getMaximumDataBlockSize() {
try {
return sService.getMaximumDataBlockSize();
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index b94031a5374e..46a5caf176b7 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -40,7 +40,9 @@ import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.media.AudioFormat;
import android.media.permission.Identity;
import android.os.AsyncTask;
+import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Slog;
@@ -246,6 +248,7 @@ public class AlwaysOnHotwordDetector {
private final Callback mExternalCallback;
private final Object mLock = new Object();
private final Handler mHandler;
+ private final IBinder mBinder = new Binder();
private int mAvailability = STATE_NOT_READY;
@@ -450,7 +453,7 @@ public class AlwaysOnHotwordDetector {
Identity identity = new Identity();
identity.packageName = ActivityThread.currentOpPackageName();
mSoundTriggerSession = mModelManagementService.createSoundTriggerSessionAsOriginator(
- identity);
+ identity, mBinder);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 8e6c26ae9f93..84c209b2d063 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -19,7 +19,7 @@ package android.text.format;
import android.annotation.NonNull;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.icu.text.DateFormatSymbols;
@@ -170,7 +170,7 @@ public class DateFormat {
* mean using 12-hour in some locales and, in this case, is duplicated as the 'a' field.
*/
@ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT)
static final long DISALLOW_DUPLICATE_FIELD_IN_SKELETON = 170233598L;
/**
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index f19e7d2724d9..bac7c6cf87d3 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -18,6 +18,7 @@ package android.text.format;
import android.util.TimeFormatException;
+import com.android.i18n.timezone.WallTime;
import com.android.i18n.timezone.ZoneInfoData;
import com.android.i18n.timezone.ZoneInfoDb;
@@ -1070,7 +1071,7 @@ public class Time {
* to the enclosing object, but others do not: thus separate state is retained.
*/
private static class TimeCalculator {
- public final ZoneInfoData.WallTime wallTime;
+ public final WallTime wallTime;
public String timezone;
// Information about the current timezone.
@@ -1078,7 +1079,7 @@ public class Time {
public TimeCalculator(String timezoneId) {
this.mZoneInfoData = lookupZoneInfoData(timezoneId);
- this.wallTime = new ZoneInfoData.WallTime();
+ this.wallTime = new WallTime();
}
public long toMillis(boolean ignoreDst) {
diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java
index c71dfbbafd40..e42ad6334649 100644
--- a/core/java/android/text/format/TimeFormatter.java
+++ b/core/java/android/text/format/TimeFormatter.java
@@ -24,6 +24,7 @@ import android.content.res.Resources;
import android.icu.text.DateFormatSymbols;
import android.icu.text.DecimalFormatSymbols;
+import com.android.i18n.timezone.WallTime;
import com.android.i18n.timezone.ZoneInfoData;
import java.nio.CharBuffer;
@@ -149,7 +150,7 @@ class TimeFormatter {
/**
* Format the specified {@code wallTime} using {@code pattern}. The output is returned.
*/
- public String format(String pattern, ZoneInfoData.WallTime wallTime,
+ public String format(String pattern, WallTime wallTime,
ZoneInfoData zoneInfoData) {
try {
StringBuilder stringBuilder = new StringBuilder();
@@ -192,7 +193,7 @@ class TimeFormatter {
* Format the specified {@code wallTime} using {@code pattern}. The output is written to
* {@link #outputBuilder}.
*/
- private void formatInternal(String pattern, ZoneInfoData.WallTime wallTime,
+ private void formatInternal(String pattern, WallTime wallTime,
ZoneInfoData zoneInfoData) {
CharBuffer formatBuffer = CharBuffer.wrap(pattern);
while (formatBuffer.remaining() > 0) {
@@ -208,7 +209,7 @@ class TimeFormatter {
}
}
- private boolean handleToken(CharBuffer formatBuffer, ZoneInfoData.WallTime wallTime,
+ private boolean handleToken(CharBuffer formatBuffer, WallTime wallTime,
ZoneInfoData zoneInfoData) {
// The char at formatBuffer.position() is expected to be '%' at this point.
diff --git a/core/java/android/timezone/TzDataSetVersion.java b/core/java/android/timezone/TzDataSetVersion.java
index edcbbb354089..4031ff8692de 100644
--- a/core/java/android/timezone/TzDataSetVersion.java
+++ b/core/java/android/timezone/TzDataSetVersion.java
@@ -19,6 +19,7 @@ package android.timezone;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import com.android.i18n.timezone.TimeZoneDataFiles;
import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
@@ -76,8 +77,7 @@ public final class TzDataSetVersion {
@NonNull
public static TzDataSetVersion read() throws IOException, TzDataSetException {
try {
- return new TzDataSetVersion(
- com.android.i18n.timezone.TzDataSetVersion.readTimeZoneModuleVersion());
+ return new TzDataSetVersion(TimeZoneDataFiles.readTimeZoneModuleVersion());
} catch (com.android.i18n.timezone.TzDataSetVersion.TzDataSetException e) {
throw new TzDataSetException(e.getMessage(), e);
}
diff --git a/core/java/android/util/CharsetUtils.java b/core/java/android/util/CharsetUtils.java
new file mode 100644
index 000000000000..fa146675b8d1
--- /dev/null
+++ b/core/java/android/util/CharsetUtils.java
@@ -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 android.util;
+
+import android.annotation.NonNull;
+
+import dalvik.annotation.optimization.FastNative;
+
+/**
+ * Specializations of {@code libcore.util.CharsetUtils} which enable efficient
+ * in-place encoding without making any new allocations.
+ * <p>
+ * These methods purposefully accept only non-movable byte array addresses to
+ * avoid extra JNI overhead.
+ *
+ * @hide
+ */
+public class CharsetUtils {
+ /**
+ * Attempt to encode the given string as modified UTF-8 into the destination
+ * byte array without making any new allocations.
+ *
+ * @param src string value to be encoded
+ * @param dest destination byte array to encode into
+ * @param destOff offset into destination where encoding should begin
+ * @param destLen length of destination
+ * @return positive value when encoding succeeded, or negative value when
+ * failed; the magnitude of the value is the number of bytes
+ * required to encode the string.
+ */
+ public static int toModifiedUtf8Bytes(@NonNull String src,
+ long dest, int destOff, int destLen) {
+ return toModifiedUtf8Bytes(src, src.length(), dest, destOff, destLen);
+ }
+
+ /**
+ * Attempt to encode the given string as modified UTF-8 into the destination
+ * byte array without making any new allocations.
+ *
+ * @param src string value to be encoded
+ * @param srcLen exact length of string to be encoded
+ * @param dest destination byte array to encode into
+ * @param destOff offset into destination where encoding should begin
+ * @param destLen length of destination
+ * @return positive value when encoding succeeded, or negative value when
+ * failed; the magnitude of the value is the number of bytes
+ * required to encode the string.
+ */
+ @FastNative
+ private static native int toModifiedUtf8Bytes(@NonNull String src, int srcLen,
+ long dest, int destOff, int destLen);
+
+ /**
+ * Attempt to decode a modified UTF-8 string from the source byte array.
+ *
+ * @param src source byte array to decode from
+ * @param srcOff offset into source where decoding should begin
+ * @param srcLen length of source that should be decoded
+ * @return the successfully decoded string
+ */
+ @FastNative
+ public static native @NonNull String fromModifiedUtf8Bytes(
+ long src, int srcOff, int srcLen);
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index c20b0639b1c4..a5ca9ef5b887 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -23,7 +23,9 @@ import android.provider.Settings;
import android.text.TextUtils;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
/**
* Util class to get feature flag information.
@@ -70,6 +72,12 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "false");
}
+ private static final Set<String> PERSISTENT_FLAGS;
+ static {
+ PERSISTENT_FLAGS = new HashSet<>();
+ PERSISTENT_FLAGS.add(SETTINGS_PROVIDER_MODEL);
+ }
+
/**
* Whether or not a flag is enabled.
*
@@ -89,8 +97,9 @@ public class FeatureFlagUtils {
}
}
- // Step 2: check if feature flag has any override. Flag name: sys.fflag.override.<feature>
- value = SystemProperties.get(FFLAG_OVERRIDE_PREFIX + feature);
+ // Step 2: check if feature flag has any override.
+ // Flag name: [persist.]sys.fflag.override.<feature>
+ value = SystemProperties.get(getSystemPropertyPrefix(feature) + feature);
if (!TextUtils.isEmpty(value)) {
return Boolean.parseBoolean(value);
}
@@ -103,7 +112,8 @@ public class FeatureFlagUtils {
* Override feature flag to new state.
*/
public static void setEnabled(Context context, String feature, boolean enabled) {
- SystemProperties.set(FFLAG_OVERRIDE_PREFIX + feature, enabled ? "true" : "false");
+ SystemProperties.set(getSystemPropertyPrefix(feature) + feature,
+ enabled ? "true" : "false");
}
/**
@@ -112,4 +122,8 @@ public class FeatureFlagUtils {
public static Map<String, String> getAllFeatureFlags() {
return DEFAULT_FLAGS;
}
+
+ private static String getSystemPropertyPrefix(String feature) {
+ return PERSISTENT_FLAGS.contains(feature) ? PERSIST_PREFIX : FFLAG_OVERRIDE_PREFIX;
+ }
}
diff --git a/core/java/android/util/TypedXmlPullParser.java b/core/java/android/util/TypedXmlPullParser.java
new file mode 100644
index 000000000000..5ff7e5dd022f
--- /dev/null
+++ b/core/java/android/util/TypedXmlPullParser.java
@@ -0,0 +1,186 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.IOException;
+
+/**
+ * Specialization of {@link XmlPullParser} which adds explicit methods to
+ * support consistent and efficient conversion of primitive data types.
+ *
+ * @hide
+ */
+public interface TypedXmlPullParser extends XmlPullParser {
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}, or
+ * {@code null} if malformed or undefined
+ */
+ @Nullable byte[] getAttributeBytesHex(@Nullable String namespace, @NonNull String name)
+ throws IOException;
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}, or
+ * {@code null} if malformed or undefined
+ */
+ @Nullable byte[] getAttributeBytesBase64(@Nullable String namespace, @NonNull String name)
+ throws IOException;
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}
+ * @throws IOException if the value is malformed or undefined
+ */
+ int getAttributeInt(@Nullable String namespace, @NonNull String name)
+ throws IOException;
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}
+ * @throws IOException if the value is malformed or undefined
+ */
+ int getAttributeIntHex(@Nullable String namespace, @NonNull String name)
+ throws IOException;
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}
+ * @throws IOException if the value is malformed or undefined
+ */
+ long getAttributeLong(@Nullable String namespace, @NonNull String name)
+ throws IOException;
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}
+ * @throws IOException if the value is malformed or undefined
+ */
+ long getAttributeLongHex(@Nullable String namespace, @NonNull String name)
+ throws IOException;
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}
+ * @throws IOException if the value is malformed or undefined
+ */
+ float getAttributeFloat(@Nullable String namespace, @NonNull String name)
+ throws IOException;
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}
+ * @throws IOException if the value is malformed or undefined
+ */
+ double getAttributeDouble(@Nullable String namespace, @NonNull String name)
+ throws IOException;
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}
+ * @throws IOException if the value is malformed or undefined
+ */
+ boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name)
+ throws IOException;
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+ * default value if the value is malformed or undefined
+ */
+ default int getAttributeInt(@Nullable String namespace, @NonNull String name,
+ int defaultValue) {
+ try {
+ return getAttributeInt(namespace, name);
+ } catch (Exception ignored) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+ * default value if the value is malformed or undefined
+ */
+ default int getAttributeIntHex(@Nullable String namespace, @NonNull String name,
+ int defaultValue) {
+ try {
+ return getAttributeIntHex(namespace, name);
+ } catch (Exception ignored) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+ * default value if the value is malformed or undefined
+ */
+ default long getAttributeLong(@Nullable String namespace, @NonNull String name,
+ long defaultValue) {
+ try {
+ return getAttributeLong(namespace, name);
+ } catch (Exception ignored) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+ * default value if the value is malformed or undefined
+ */
+ default long getAttributeLongHex(@Nullable String namespace, @NonNull String name,
+ long defaultValue) {
+ try {
+ return getAttributeLongHex(namespace, name);
+ } catch (Exception ignored) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+ * default value if the value is malformed or undefined
+ */
+ default float getAttributeFloat(@Nullable String namespace, @NonNull String name,
+ float defaultValue) {
+ try {
+ return getAttributeFloat(namespace, name);
+ } catch (Exception ignored) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+ * default value if the value is malformed or undefined
+ */
+ default double getAttributeDouble(@Nullable String namespace, @NonNull String name,
+ double defaultValue) {
+ try {
+ return getAttributeDouble(namespace, name);
+ } catch (Exception ignored) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * @return decoded strongly-typed {@link #getAttributeValue}, otherwise
+ * default value if the value is malformed or undefined
+ */
+ default boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name,
+ boolean defaultValue) {
+ try {
+ return getAttributeBoolean(namespace, name);
+ } catch (Exception ignored) {
+ return defaultValue;
+ }
+ }
+}
diff --git a/core/java/android/util/TypedXmlSerializer.java b/core/java/android/util/TypedXmlSerializer.java
new file mode 100644
index 000000000000..fe5e3e6e9a52
--- /dev/null
+++ b/core/java/android/util/TypedXmlSerializer.java
@@ -0,0 +1,103 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+
+/**
+ * Specialization of {@link XmlSerializer} which adds explicit methods to
+ * support consistent and efficient conversion of primitive data types.
+ *
+ * @hide
+ */
+public interface TypedXmlSerializer extends XmlSerializer {
+ /**
+ * Functionally equivalent to {@link #attribute(String, String, String)} but
+ * with the additional signal that the given value is a candidate for being
+ * canonicalized, similar to {@link String#intern()}.
+ */
+ @NonNull XmlSerializer attributeInterned(@Nullable String namespace, @NonNull String name,
+ @Nullable String value) throws IOException;
+
+ /**
+ * Encode the given strongly-typed value and serialize using
+ * {@link #attribute(String, String, String)}.
+ */
+ @NonNull XmlSerializer attributeBytesHex(@Nullable String namespace, @NonNull String name,
+ byte[] value) throws IOException;
+
+ /**
+ * Encode the given strongly-typed value and serialize using
+ * {@link #attribute(String, String, String)}.
+ */
+ @NonNull XmlSerializer attributeBytesBase64(@Nullable String namespace, @NonNull String name,
+ byte[] value) throws IOException;
+
+ /**
+ * Encode the given strongly-typed value and serialize using
+ * {@link #attribute(String, String, String)}.
+ */
+ @NonNull XmlSerializer attributeInt(@Nullable String namespace, @NonNull String name,
+ int value) throws IOException;
+
+ /**
+ * Encode the given strongly-typed value and serialize using
+ * {@link #attribute(String, String, String)}.
+ */
+ @NonNull XmlSerializer attributeIntHex(@Nullable String namespace, @NonNull String name,
+ int value) throws IOException;
+
+ /**
+ * Encode the given strongly-typed value and serialize using
+ * {@link #attribute(String, String, String)}.
+ */
+ @NonNull XmlSerializer attributeLong(@Nullable String namespace, @NonNull String name,
+ long value) throws IOException;
+
+ /**
+ * Encode the given strongly-typed value and serialize using
+ * {@link #attribute(String, String, String)}.
+ */
+ @NonNull XmlSerializer attributeLongHex(@Nullable String namespace, @NonNull String name,
+ long value) throws IOException;
+
+ /**
+ * Encode the given strongly-typed value and serialize using
+ * {@link #attribute(String, String, String)}.
+ */
+ @NonNull XmlSerializer attributeFloat(@Nullable String namespace, @NonNull String name,
+ float value) throws IOException;
+
+ /**
+ * Encode the given strongly-typed value and serialize using
+ * {@link #attribute(String, String, String)}.
+ */
+ @NonNull XmlSerializer attributeDouble(@Nullable String namespace, @NonNull String name,
+ double value) throws IOException;
+
+ /**
+ * Encode the given strongly-typed value and serialize using
+ * {@link #attribute(String, String, String)}.
+ */
+ @NonNull XmlSerializer attributeBoolean(@Nullable String namespace, @NonNull String name,
+ boolean value) throws IOException;
+}
diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java
index e3b8fec3559e..cc6ed2e4539e 100644
--- a/core/java/android/util/Xml.java
+++ b/core/java/android/util/Xml.java
@@ -16,6 +16,14 @@
package android.util;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.BinaryXmlPullParser;
+import com.android.internal.util.BinaryXmlSerializer;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
import libcore.util.XmlObjectFactory;
import org.xml.sax.ContentHandler;
@@ -26,11 +34,15 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
/**
* XML utility methods.
@@ -99,6 +111,57 @@ public class Xml {
}
/**
+ * Creates a new {@link TypedXmlPullParser} which is optimized for use
+ * inside the system, typically by supporting only a basic set of features.
+ * <p>
+ * In particular, the returned parser does not support namespaces, prefixes,
+ * properties, or options.
+ *
+ * @hide
+ */
+ public static @NonNull TypedXmlPullParser newFastPullParser() {
+ return XmlUtils.makeTyped(newPullParser());
+ }
+
+ /**
+ * Creates a new {@link XmlPullParser} that reads XML documents using a
+ * custom binary wire protocol which benchmarking has shown to be 8.5x
+ * faster than {@code Xml.newFastPullParser()} for a typical
+ * {@code packages.xml}.
+ *
+ * @hide
+ */
+ public static @NonNull TypedXmlPullParser newBinaryPullParser() {
+ return new BinaryXmlPullParser();
+ }
+
+ /**
+ * Creates a new {@link XmlPullParser} which is optimized for use inside the
+ * system, typically by supporting only a basic set of features.
+ * <p>
+ * This returned instance may be configured to read using an efficient
+ * binary format instead of a human-readable text format, depending on
+ * device feature flags.
+ * <p>
+ * To ensure that both formats are detected and transparently handled
+ * correctly, you must shift to using both {@link #resolveSerializer} and
+ * {@link #resolvePullParser}.
+ *
+ * @hide
+ */
+ public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in)
+ throws IOException {
+ // TODO: add support for binary format
+ final TypedXmlPullParser xml = newFastPullParser();
+ try {
+ xml.setInput(in, StandardCharsets.UTF_8.name());
+ } catch (XmlPullParserException e) {
+ throw new IOException(e);
+ }
+ return xml;
+ }
+
+ /**
* Creates a new xml serializer.
*/
public static XmlSerializer newSerializer() {
@@ -106,6 +169,129 @@ public class Xml {
}
/**
+ * Creates a new {@link XmlSerializer} which is optimized for use inside the
+ * system, typically by supporting only a basic set of features.
+ * <p>
+ * In particular, the returned parser does not support namespaces, prefixes,
+ * properties, or options.
+ *
+ * @hide
+ */
+ public static @NonNull TypedXmlSerializer newFastSerializer() {
+ return XmlUtils.makeTyped(new FastXmlSerializer());
+ }
+
+ /**
+ * Creates a new {@link XmlSerializer} that writes XML documents using a
+ * custom binary wire protocol which benchmarking has shown to be 4.4x
+ * faster and use 2.8x less disk space than {@code Xml.newFastSerializer()}
+ * for a typical {@code packages.xml}.
+ *
+ * @hide
+ */
+ public static @NonNull TypedXmlSerializer newBinarySerializer() {
+ return new BinaryXmlSerializer();
+ }
+
+ /**
+ * Creates a new {@link XmlSerializer} which is optimized for use inside the
+ * system, typically by supporting only a basic set of features.
+ * <p>
+ * This returned instance may be configured to write using an efficient
+ * binary format instead of a human-readable text format, depending on
+ * device feature flags.
+ * <p>
+ * To ensure that both formats are detected and transparently handled
+ * correctly, you must shift to using both {@link #resolveSerializer} and
+ * {@link #resolvePullParser}.
+ *
+ * @hide
+ */
+ public static @NonNull TypedXmlSerializer resolveSerializer(@NonNull OutputStream out)
+ throws IOException {
+ // TODO: add support for binary format
+ final TypedXmlSerializer xml = newFastSerializer();
+ xml.setOutput(out, StandardCharsets.UTF_8.name());
+ return xml;
+ }
+
+ /**
+ * Copy the first XML document into the second document.
+ * <p>
+ * Implemented by reading all events from the given {@link XmlPullParser}
+ * and writing them directly to the given {@link XmlSerializer}. This can be
+ * useful for transparently converting between underlying wire protocols.
+ *
+ * @hide
+ */
+ public static void copy(@NonNull XmlPullParser in, @NonNull XmlSerializer out)
+ throws XmlPullParserException, IOException {
+ // Some parsers may have already consumed the event that starts the
+ // document, so we manually emit that event here for consistency
+ if (in.getEventType() == XmlPullParser.START_DOCUMENT) {
+ out.startDocument(in.getInputEncoding(), true);
+ }
+
+ while (true) {
+ final int token = in.nextToken();
+ switch (token) {
+ case XmlPullParser.START_DOCUMENT:
+ out.startDocument(in.getInputEncoding(), true);
+ break;
+ case XmlPullParser.END_DOCUMENT:
+ out.endDocument();
+ return;
+ case XmlPullParser.START_TAG:
+ out.startTag(normalizeNamespace(in.getNamespace()), in.getName());
+ for (int i = 0; i < in.getAttributeCount(); i++) {
+ out.attribute(normalizeNamespace(in.getAttributeNamespace(i)),
+ in.getAttributeName(i), in.getAttributeValue(i));
+ }
+ break;
+ case XmlPullParser.END_TAG:
+ out.endTag(normalizeNamespace(in.getNamespace()), in.getName());
+ break;
+ case XmlPullParser.TEXT:
+ out.text(in.getText());
+ break;
+ case XmlPullParser.CDSECT:
+ out.cdsect(in.getText());
+ break;
+ case XmlPullParser.ENTITY_REF:
+ out.entityRef(in.getName());
+ break;
+ case XmlPullParser.IGNORABLE_WHITESPACE:
+ out.ignorableWhitespace(in.getText());
+ break;
+ case XmlPullParser.PROCESSING_INSTRUCTION:
+ out.processingInstruction(in.getText());
+ break;
+ case XmlPullParser.COMMENT:
+ out.comment(in.getText());
+ break;
+ case XmlPullParser.DOCDECL:
+ out.docdecl(in.getText());
+ break;
+ default:
+ throw new IllegalStateException("Unknown token " + token);
+ }
+ }
+ }
+
+ /**
+ * Some parsers may return an empty string {@code ""} when a namespace in
+ * unsupported, which can confuse serializers. This method normalizes empty
+ * strings to be {@code null}.
+ */
+ private static @Nullable String normalizeNamespace(@Nullable String namespace) {
+ if (namespace == null || namespace.isEmpty()) {
+ return null;
+ } else {
+ return namespace;
+ }
+ }
+
+ /**
* Supported character encodings.
*/
public enum Encoding {
diff --git a/core/java/android/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java
index c3e2ecc9e0f3..33bc121d8555 100644
--- a/core/java/android/uwb/AngleMeasurement.java
+++ b/core/java/android/uwb/AngleMeasurement.java
@@ -17,6 +17,10 @@
package android.uwb;
import android.annotation.FloatRange;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
/**
* Angle measurement
@@ -26,7 +30,7 @@ import android.annotation.FloatRange;
*
* @hide
*/
-public final class AngleMeasurement {
+public final class AngleMeasurement implements Parcelable {
private final double mRadians;
private final double mErrorRadians;
private final double mConfidenceLevel;
@@ -39,7 +43,7 @@ public final class AngleMeasurement {
/**
* Angle measurement in radians
- *
+ *
* @return angle in radians
*/
@FloatRange(from = -Math.PI, to = +Math.PI)
@@ -74,6 +78,61 @@ public final class AngleMeasurement {
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof AngleMeasurement) {
+ AngleMeasurement other = (AngleMeasurement) obj;
+ return mRadians == other.getRadians()
+ && mErrorRadians == other.getErrorRadians()
+ && mConfidenceLevel == other.getConfidenceLevel();
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRadians, mErrorRadians, mConfidenceLevel);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeDouble(mRadians);
+ dest.writeDouble(mErrorRadians);
+ dest.writeDouble(mConfidenceLevel);
+ }
+
+ public static final @android.annotation.NonNull Creator<AngleMeasurement> CREATOR =
+ new Creator<AngleMeasurement>() {
+ @Override
+ public AngleMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.setRadians(in.readDouble());
+ builder.setErrorRadians(in.readDouble());
+ builder.setConfidenceLevel(in.readDouble());
+ return builder.build();
+ }
+
+ @Override
+ public AngleMeasurement[] newArray(int size) {
+ return new AngleMeasurement[size];
+ }
+ };
+
+ /**
* Builder class for {@link AngleMeasurement}.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/AngleOfArrivalMeasurement.java b/core/java/android/uwb/AngleOfArrivalMeasurement.java
index a7b5eae728cb..cd5af691ed51 100644
--- a/core/java/android/uwb/AngleOfArrivalMeasurement.java
+++ b/core/java/android/uwb/AngleOfArrivalMeasurement.java
@@ -18,13 +18,17 @@ package android.uwb;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
/**
* Represents an angle of arrival measurement between two devices using Ultra Wideband
*
* @hide
*/
-public final class AngleOfArrivalMeasurement {
+public final class AngleOfArrivalMeasurement implements Parcelable {
private final AngleMeasurement mAzimuthAngleMeasurement;
private final AngleMeasurement mAltitudeAngleMeasurement;
@@ -71,6 +75,63 @@ public final class AngleOfArrivalMeasurement {
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof AngleOfArrivalMeasurement) {
+ AngleOfArrivalMeasurement other = (AngleOfArrivalMeasurement) obj;
+ return mAzimuthAngleMeasurement.equals(other.getAzimuth())
+ && mAltitudeAngleMeasurement.equals(other.getAltitude());
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAzimuthAngleMeasurement, mAltitudeAngleMeasurement);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mAzimuthAngleMeasurement, flags);
+ dest.writeParcelable(mAltitudeAngleMeasurement, flags);
+ }
+
+ public static final @android.annotation.NonNull Creator<AngleOfArrivalMeasurement> CREATOR =
+ new Creator<AngleOfArrivalMeasurement>() {
+ @Override
+ public AngleOfArrivalMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+
+ builder.setAzimuthAngleMeasurement(
+ in.readParcelable(AngleMeasurement.class.getClassLoader()));
+
+ builder.setAltitudeAngleMeasurement(
+ in.readParcelable(AngleMeasurement.class.getClassLoader()));
+
+ return builder.build();
+ }
+
+ @Override
+ public AngleOfArrivalMeasurement[] newArray(int size) {
+ return new AngleOfArrivalMeasurement[size];
+ }
+ };
+
+ /**
* Builder class for {@link AngleOfArrivalMeasurement}.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/DistanceMeasurement.java b/core/java/android/uwb/DistanceMeasurement.java
index 4cd5d83f4efc..c959840c51ba 100644
--- a/core/java/android/uwb/DistanceMeasurement.java
+++ b/core/java/android/uwb/DistanceMeasurement.java
@@ -17,6 +17,11 @@
package android.uwb;
import android.annotation.FloatRange;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
/**
* A data point for the distance measurement
@@ -26,7 +31,7 @@ import android.annotation.FloatRange;
*
* @hide
*/
-public final class DistanceMeasurement {
+public final class DistanceMeasurement implements Parcelable {
private final double mMeters;
private final double mErrorMeters;
private final double mConfidenceLevel;
@@ -70,6 +75,61 @@ public final class DistanceMeasurement {
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof DistanceMeasurement) {
+ DistanceMeasurement other = (DistanceMeasurement) obj;
+ return mMeters == other.getMeters()
+ && mErrorMeters == other.getErrorMeters()
+ && mConfidenceLevel == other.getConfidenceLevel();
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mMeters, mErrorMeters, mConfidenceLevel);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeDouble(mMeters);
+ dest.writeDouble(mErrorMeters);
+ dest.writeDouble(mConfidenceLevel);
+ }
+
+ public static final @android.annotation.NonNull Creator<DistanceMeasurement> CREATOR =
+ new Creator<DistanceMeasurement>() {
+ @Override
+ public DistanceMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.setMeters(in.readDouble());
+ builder.setErrorMeters(in.readDouble());
+ builder.setConfidenceLevel(in.readDouble());
+ return builder.build();
+ }
+
+ @Override
+ public DistanceMeasurement[] newArray(int size) {
+ return new DistanceMeasurement[size];
+ }
+ };
+
+ /**
* Builder to get a {@link DistanceMeasurement} object.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/RangingMeasurement.java b/core/java/android/uwb/RangingMeasurement.java
index 33a34e3954c2..f1c316289653 100644
--- a/core/java/android/uwb/RangingMeasurement.java
+++ b/core/java/android/uwb/RangingMeasurement.java
@@ -20,17 +20,20 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.SystemClock;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* Representation of a ranging measurement between the local device and a remote device
*
* @hide
*/
-public final class RangingMeasurement {
+public final class RangingMeasurement implements Parcelable {
private final UwbAddress mRemoteDeviceAddress;
private final @Status int mStatus;
private final long mElapsedRealtimeNanos;
@@ -128,6 +131,71 @@ public final class RangingMeasurement {
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof RangingMeasurement) {
+ RangingMeasurement other = (RangingMeasurement) obj;
+ return mRemoteDeviceAddress.equals(other.getRemoteDeviceAddress())
+ && mStatus == other.getStatus()
+ && mElapsedRealtimeNanos == other.getElapsedRealtimeNanos()
+ && mDistanceMeasurement.equals(other.getDistance())
+ && mAngleOfArrivalMeasurement.equals(other.getAngleOfArrival());
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRemoteDeviceAddress, mStatus, mElapsedRealtimeNanos,
+ mDistanceMeasurement, mAngleOfArrivalMeasurement);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mRemoteDeviceAddress, flags);
+ dest.writeInt(mStatus);
+ dest.writeLong(mElapsedRealtimeNanos);
+ dest.writeParcelable(mDistanceMeasurement, flags);
+ dest.writeParcelable(mAngleOfArrivalMeasurement, flags);
+ }
+
+ public static final @android.annotation.NonNull Creator<RangingMeasurement> CREATOR =
+ new Creator<RangingMeasurement>() {
+ @Override
+ public RangingMeasurement createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.setRemoteDeviceAddress(
+ in.readParcelable(UwbAddress.class.getClassLoader()));
+ builder.setStatus(in.readInt());
+ builder.setElapsedRealtimeNanos(in.readLong());
+ builder.setDistanceMeasurement(
+ in.readParcelable(DistanceMeasurement.class.getClassLoader()));
+ builder.setAngleOfArrivalMeasurement(
+ in.readParcelable(AngleOfArrivalMeasurement.class.getClassLoader()));
+ return builder.build();
+ }
+
+ @Override
+ public RangingMeasurement[] newArray(int size) {
+ return new RangingMeasurement[size];
+ }
+ };
+
+ /**
* Builder for a {@link RangingMeasurement} object.
*/
public static final class Builder {
diff --git a/core/java/android/uwb/RangingParams.java b/core/java/android/uwb/RangingParams.java
deleted file mode 100644
index a50de3e61425..000000000000
--- a/core/java/android/uwb/RangingParams.java
+++ /dev/null
@@ -1,381 +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.uwb;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.PersistableBundle;
-import android.util.Duration;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * An object used when requesting to open a new {@link RangingSession}.
- * <p>Use {@link RangingParams.Builder} to create an instance of this class.
- *
- * @hide
- */
-public final class RangingParams {
- private final boolean mIsInitiator;
- private final boolean mIsController;
- private final Duration mSamplePeriod;
- private final UwbAddress mLocalDeviceAddress;
- private final List<UwbAddress> mRemoteDeviceAddresses;
- private final int mChannelNumber;
- private final int mTransmitPreambleCodeIndex;
- private final int mReceivePreambleCodeIndex;
- private final int mStsPhyPacketType;
- private final PersistableBundle mSpecificationParameters;
-
- private RangingParams(boolean isInitiator, boolean isController,
- @NonNull Duration samplingPeriod, @NonNull UwbAddress localDeviceAddress,
- @NonNull List<UwbAddress> remoteDeviceAddresses, int channelNumber,
- int transmitPreambleCodeIndex, int receivePreambleCodeIndex,
- @StsPhyPacketType int stsPhyPacketType,
- @NonNull PersistableBundle specificationParameters) {
- mIsInitiator = isInitiator;
- mIsController = isController;
- mSamplePeriod = samplingPeriod;
- mLocalDeviceAddress = localDeviceAddress;
- mRemoteDeviceAddresses = remoteDeviceAddresses;
- mChannelNumber = channelNumber;
- mTransmitPreambleCodeIndex = transmitPreambleCodeIndex;
- mReceivePreambleCodeIndex = receivePreambleCodeIndex;
- mStsPhyPacketType = stsPhyPacketType;
- mSpecificationParameters = specificationParameters;
- }
-
- /**
- * Get if the local device is the initiator
- *
- * @return true if the device is the initiator
- */
- public boolean isInitiator() {
- return mIsInitiator;
- }
-
- /**
- * Get if the local device is the controller
- *
- * @return true if the device is the controller
- */
- public boolean isController() {
- return mIsController;
- }
-
- /**
- * The desired amount of time between two adjacent samples of measurement
- *
- * @return the ranging sample period
- */
- @NonNull
- public Duration getSamplingPeriod() {
- return mSamplePeriod;
- }
-
- /**
- * Local device's {@link UwbAddress}
- *
- * <p>Simultaneous {@link RangingSession}s on the same device can have different results for
- * {@link #getLocalDeviceAddress()}.
- *
- * @return the local device's {@link UwbAddress}
- */
- @NonNull
- public UwbAddress getLocalDeviceAddress() {
- return mLocalDeviceAddress;
- }
-
- /**
- * Gets a list of all remote device's {@link UwbAddress}
- *
- * @return a {@link List} of {@link UwbAddress} representing the remote devices
- */
- @NonNull
- public List<UwbAddress> getRemoteDeviceAddresses() {
- return mRemoteDeviceAddresses;
- }
-
- /**
- * Channel number used between this device pair as defined by 802.15.4z
- *
- * Range: -1, 0-15
- *
- * @return the channel to use
- */
- public int getChannelNumber() {
- return mChannelNumber;
- }
-
- /**
- * Preamble index used between this device pair as defined by 802.15.4z
- *
- * Range: 0, 0-32
- *
- * @return the preamble index to use for transmitting
- */
- public int getTxPreambleIndex() {
- return mTransmitPreambleCodeIndex;
- }
-
- /**
- * preamble index used between this device pair as defined by 802.15.4z
- *
- * Range: 0, 13-16, 21-32
- *
- * @return the preamble index to use for receiving
- */
- public int getRxPreambleIndex() {
- return mReceivePreambleCodeIndex;
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- STS_PHY_PACKET_TYPE_SP0,
- STS_PHY_PACKET_TYPE_SP1,
- STS_PHY_PACKET_TYPE_SP2,
- STS_PHY_PACKET_TYPE_SP3})
- public @interface StsPhyPacketType {}
-
- /**
- * PHY packet type SP0 when STS is used as defined by 802.15.4z
- */
- public static final int STS_PHY_PACKET_TYPE_SP0 = 0;
-
- /**
- * PHY packet type SP1 when STS is used as defined by 802.15.4z
- */
- public static final int STS_PHY_PACKET_TYPE_SP1 = 1;
-
- /**
- * PHY packet type SP2 when STS is used as defined by 802.15.4z
- */
- public static final int STS_PHY_PACKET_TYPE_SP2 = 2;
-
- /**
- * PHY packet type SP3 when STS is used as defined by 802.15.4z
- */
- public static final int STS_PHY_PACKET_TYPE_SP3 = 3;
-
- /**
- * Get the type of PHY packet when STS is used as defined by 802.15.4z
- *
- * @return the {@link StsPhyPacketType} to use
- */
- @StsPhyPacketType
- public int getStsPhyPacketType() {
- return mStsPhyPacketType;
- }
-
- /**
- * Parameters for a specific UWB protocol constructed using a support library.
- *
- * <p>Android reserves the '^android.*' namespace
- *
- * @return a {@link PersistableBundle} copy of protocol specific parameters
- */
- public @Nullable PersistableBundle getSpecificationParameters() {
- return new PersistableBundle(mSpecificationParameters);
- }
-
- /**
- * Builder class for {@link RangingParams}.
- */
- public static final class Builder {
- private boolean mIsInitiator = false;
- private boolean mIsController = false;
- private Duration mSamplePeriod = null;
- private UwbAddress mLocalDeviceAddress = null;
- private List<UwbAddress> mRemoteDeviceAddresses = new ArrayList<>();
- private int mChannelNumber = 0;
- private int mTransmitPreambleCodeIndex = 0;
- private int mReceivePreambleCodeIndex = 0;
- private int mStsPhyPacketType = STS_PHY_PACKET_TYPE_SP0;
- private PersistableBundle mSpecificationParameters = new PersistableBundle();
-
- /**
- * Set whether the device is the initiator or responder as defined by IEEE 802.15.4z
- *
- * @param isInitiator whether the device is the initiator (true) or responder (false)
- */
- public Builder setIsInitiator(boolean isInitiator) {
- mIsInitiator = isInitiator;
- return this;
- }
-
- /**
- * Set whether the local device is the controller or controlee as defined by IEEE 802.15.4z
- *
- * @param isController whether the device is the controller (true) or controlee (false)
- */
- public Builder setIsController(boolean isController) {
- mIsController = isController;
- return this;
- }
-
- /**
- * Set the time between ranging samples
- *
- * @param samplePeriod the time between ranging samples
- */
- public Builder setSamplePeriod(@NonNull Duration samplePeriod) {
- mSamplePeriod = samplePeriod;
- return this;
- }
-
- /**
- * Set the local device address
- *
- * @param localDeviceAddress the local device's address for the {@link RangingSession}
- */
- public Builder setLocalDeviceAddress(@NonNull UwbAddress localDeviceAddress) {
- mLocalDeviceAddress = localDeviceAddress;
- return this;
- }
-
- /**
- * Add a remote device's address to the ranging session
- *
- * @param remoteDeviceAddress a remote device's address for the {@link RangingSession}
- * @throws IllegalArgumentException if {@code remoteDeviceAddress} is already present.
- */
- public Builder addRemoteDeviceAddress(@NonNull UwbAddress remoteDeviceAddress) {
- if (mRemoteDeviceAddresses.contains(remoteDeviceAddress)) {
- throw new IllegalArgumentException(
- "Remote device address already added: " + remoteDeviceAddress.toString());
- }
- mRemoteDeviceAddresses.add(remoteDeviceAddress);
- return this;
- }
-
- /**
- * Set the IEEE 802.15.4z channel to use for the {@link RangingSession}
- * <p>Valid values are in the range [-1, 15]
- *
- * @param channelNumber the channel to use for the {@link RangingSession}
- * @throws IllegalArgumentException if {@code channelNumber} is invalid.
- */
- public Builder setChannelNumber(int channelNumber) {
- if (channelNumber < -1 || channelNumber > 15) {
- throw new IllegalArgumentException("Invalid channel number");
- }
- mChannelNumber = channelNumber;
- return this;
- }
-
- private static final Set<Integer> VALID_TX_PREAMBLE_CODES = new HashSet<Integer>(
- Arrays.asList(0, 13, 14, 15, 16, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32));
-
- /**
- * Set the IEEE 802.15.4z preamble code index to use when transmitting
- *
- * <p>Valid values are in the ranges: [0], [13-16], [21-32]
- *
- * @param transmitPreambleCodeIndex preamble code index to use for transmitting
- * @throws IllegalArgumentException if {@code transmitPreambleCodeIndex} is invalid.
- */
- public Builder setTransmitPreambleCodeIndex(int transmitPreambleCodeIndex) {
- if (!VALID_TX_PREAMBLE_CODES.contains(transmitPreambleCodeIndex)) {
- throw new IllegalArgumentException(
- "Invalid transmit preamble: " + transmitPreambleCodeIndex);
- }
- mTransmitPreambleCodeIndex = transmitPreambleCodeIndex;
- return this;
- }
-
- private static final Set<Integer> VALID_RX_PREAMBLE_CODES = new HashSet<Integer>(
- Arrays.asList(0, 16, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32));
-
- /**
- * Set the IEEE 802.15.4z preamble code index to use when receiving
- *
- * Valid values are in the ranges: [0], [16-32]
- *
- * @param receivePreambleCodeIndex preamble code index to use for receiving
- * @throws IllegalArgumentException if {@code receivePreambleCodeIndex} is invalid.
- */
- public Builder setReceivePreambleCodeIndex(int receivePreambleCodeIndex) {
- if (!VALID_RX_PREAMBLE_CODES.contains(receivePreambleCodeIndex)) {
- throw new IllegalArgumentException(
- "Invalid receive preamble: " + receivePreambleCodeIndex);
- }
- mReceivePreambleCodeIndex = receivePreambleCodeIndex;
- return this;
- }
-
- /**
- * Set the IEEE 802.15.4z PHY packet type when STS is used
- *
- * @param stsPhyPacketType PHY packet type when STS is used
- * @throws IllegalArgumentException if {@code stsPhyPacketType} is invalid.
- */
- public Builder setStsPhPacketType(@StsPhyPacketType int stsPhyPacketType) {
- if (stsPhyPacketType != STS_PHY_PACKET_TYPE_SP0
- && stsPhyPacketType != STS_PHY_PACKET_TYPE_SP1
- && stsPhyPacketType != STS_PHY_PACKET_TYPE_SP2
- && stsPhyPacketType != STS_PHY_PACKET_TYPE_SP3) {
- throw new IllegalArgumentException("unknown StsPhyPacketType: " + stsPhyPacketType);
- }
-
- mStsPhyPacketType = stsPhyPacketType;
- return this;
- }
-
- /**
- * Set the specification parameters
- *
- * <p>Creates a copy of the parameters
- *
- * @param parameters specification parameters built from support library
- */
- public Builder setSpecificationParameters(@NonNull PersistableBundle parameters) {
- mSpecificationParameters = new PersistableBundle(parameters);
- return this;
- }
-
- /**
- * Build the {@link RangingParams} object.
- *
- * @throws IllegalStateException if required parameters are missing
- */
- public RangingParams build() {
- if (mSamplePeriod == null) {
- throw new IllegalStateException("No sample period provided");
- }
-
- if (mLocalDeviceAddress == null) {
- throw new IllegalStateException("Local device address not provided");
- }
-
- if (mRemoteDeviceAddresses.size() == 0) {
- throw new IllegalStateException("No remote device address(es) provided");
- }
-
- return new RangingParams(mIsInitiator, mIsController, mSamplePeriod,
- mLocalDeviceAddress, mRemoteDeviceAddresses, mChannelNumber,
- mTransmitPreambleCodeIndex, mReceivePreambleCodeIndex, mStsPhyPacketType,
- mSpecificationParameters);
- }
- }
-}
diff --git a/core/java/android/uwb/RangingReport.java b/core/java/android/uwb/RangingReport.java
index 5aca12aaf2cf..45180bfa6981 100644
--- a/core/java/android/uwb/RangingReport.java
+++ b/core/java/android/uwb/RangingReport.java
@@ -17,16 +17,20 @@
package android.uwb;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* This class contains the UWB ranging data
*
* @hide
*/
-public final class RangingReport {
+public final class RangingReport implements Parcelable {
private final List<RangingMeasurement> mRangingMeasurements;
private RangingReport(@NonNull List<RangingMeasurement> rangingMeasurements) {
@@ -49,6 +53,56 @@ public final class RangingReport {
}
/**
+ * @hide
+ */
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj instanceof RangingReport) {
+ RangingReport other = (RangingReport) obj;
+ return mRangingMeasurements.equals(other.getMeasurements());
+ }
+
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRangingMeasurements);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeTypedList(mRangingMeasurements);
+ }
+
+ public static final @android.annotation.NonNull Creator<RangingReport> CREATOR =
+ new Creator<RangingReport>() {
+ @Override
+ public RangingReport createFromParcel(Parcel in) {
+ Builder builder = new Builder();
+ builder.addMeasurements(in.createTypedArrayList(RangingMeasurement.CREATOR));
+ return builder.build();
+ }
+
+ @Override
+ public RangingReport[] newArray(int size) {
+ return new RangingReport[size];
+ }
+ };
+
+ /**
* Builder for {@link RangingReport} object
*/
public static final class Builder {
diff --git a/core/java/android/uwb/RangingSession.java b/core/java/android/uwb/RangingSession.java
index f4033fe0d29e..863926924aad 100644
--- a/core/java/android/uwb/RangingSession.java
+++ b/core/java/android/uwb/RangingSession.java
@@ -30,7 +30,7 @@ import java.util.concurrent.Executor;
* {@link RangingSession}.
*
* <p>To get an instance of {@link RangingSession}, first use
- * {@link UwbManager#openRangingSession(RangingParams, Executor, Callback)} to request to open a
+ * {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)} to request to open a
* session. Once the session is opened, a {@link RangingSession} object is provided through
* {@link RangingSession.Callback#onOpenSuccess(RangingSession, PersistableBundle)}. If opening a
* session fails, the failure is reported through {@link RangingSession.Callback#onClosed(int)} with
@@ -44,7 +44,7 @@ public final class RangingSession implements AutoCloseable {
*/
public interface Callback {
/**
- * Invoked when {@link UwbManager#openRangingSession(RangingParams, Executor, Callback)}
+ * Invoked when {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}
* is successful
*
* @param session the newly opened {@link RangingSession}
@@ -77,7 +77,7 @@ public final class RangingSession implements AutoCloseable {
/**
* Indicates that the session failed to open due to erroneous parameters passed
- * to {@link UwbManager#openRangingSession(RangingParams, Executor, Callback)}
+ * to {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}
*/
int CLOSE_REASON_LOCAL_BAD_PARAMETERS = 2;
@@ -137,8 +137,8 @@ public final class RangingSession implements AutoCloseable {
* will still be invoked.
*
* <p>{@link Callback#onClosed(int)} will be invoked using the same callback
- * object given to {@link UwbManager#openRangingSession(RangingParams, Executor, Callback)} when
- * the {@link RangingSession} was opened. The callback will be invoked after each call to
+ * object given to {@link UwbManager#openRangingSession(PersistableBundle, Executor, Callback)}
+ * when the {@link RangingSession} was opened. The callback will be invoked after each call to
* {@link #close()}, even if the {@link RangingSession} is already closed.
*/
@Override
diff --git a/core/java/android/uwb/TEST_MAPPING b/core/java/android/uwb/TEST_MAPPING
new file mode 100644
index 000000000000..9e50bd64d089
--- /dev/null
+++ b/core/java/android/uwb/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "UwbManagerTests"
+ }
+ ]
+} \ No newline at end of file
diff --git a/core/java/android/uwb/UwbAddress.java b/core/java/android/uwb/UwbAddress.java
index 48fcb10e1a1a..828324c54c5a 100644
--- a/core/java/android/uwb/UwbAddress.java
+++ b/core/java/android/uwb/UwbAddress.java
@@ -18,16 +18,26 @@ package android.uwb;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
/**
* A class representing a UWB address
*
* @hide
*/
-public final class UwbAddress {
+public final class UwbAddress implements Parcelable {
public static final int SHORT_ADDRESS_BYTE_LENGTH = 2;
public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8;
+ private final byte[] mAddressBytes;
+
+ private UwbAddress(byte[] address) {
+ mAddressBytes = address;
+ }
+
/**
* Create a {@link UwbAddress} from a byte array.
*
@@ -37,12 +47,16 @@ public final class UwbAddress {
*
* @param address a byte array to convert to a {@link UwbAddress}
* @return a {@link UwbAddress} created from the input byte array
- * @throw IllegableArumentException when the length is not one of
+ * @throws IllegalArgumentException when the length is not one of
* {@link #SHORT_ADDRESS_BYTE_LENGTH} or {@link #EXTENDED_ADDRESS_BYTE_LENGTH} bytes
*/
@NonNull
- public static UwbAddress fromBytes(byte[] address) throws IllegalArgumentException {
- throw new UnsupportedOperationException();
+ public static UwbAddress fromBytes(@NonNull byte[] address) throws IllegalArgumentException {
+ if (address.length != SHORT_ADDRESS_BYTE_LENGTH
+ && address.length != EXTENDED_ADDRESS_BYTE_LENGTH) {
+ throw new IllegalArgumentException("Invalid UwbAddress length " + address.length);
+ }
+ return new UwbAddress(address);
}
/**
@@ -52,7 +66,7 @@ public final class UwbAddress {
*/
@NonNull
public byte[] toBytes() {
- throw new UnsupportedOperationException();
+ return mAddressBytes;
}
/**
@@ -61,22 +75,55 @@ public final class UwbAddress {
* {@link #EXTENDED_ADDRESS_BYTE_LENGTH}.
*/
public int size() {
- throw new UnsupportedOperationException();
+ return mAddressBytes.length;
}
@NonNull
@Override
public String toString() {
- throw new UnsupportedOperationException();
+ StringBuilder builder = new StringBuilder("0x");
+ for (byte addressByte : mAddressBytes) {
+ builder.append(String.format("%02X", addressByte));
+ }
+ return builder.toString();
}
@Override
public boolean equals(@Nullable Object obj) {
- throw new UnsupportedOperationException();
+ if (obj instanceof UwbAddress) {
+ return Arrays.equals(mAddressBytes, ((UwbAddress) obj).toBytes());
+ }
+ return false;
}
@Override
public int hashCode() {
- throw new UnsupportedOperationException();
+ return Arrays.hashCode(mAddressBytes);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mAddressBytes.length);
+ dest.writeByteArray(mAddressBytes);
}
+
+ public static final @android.annotation.NonNull Creator<UwbAddress> CREATOR =
+ new Creator<UwbAddress>() {
+ @Override
+ public UwbAddress createFromParcel(Parcel in) {
+ byte[] address = new byte[in.readInt()];
+ in.readByteArray(address);
+ return UwbAddress.fromBytes(address);
+ }
+
+ @Override
+ public UwbAddress[] newArray(int size) {
+ return new UwbAddress[size];
+ }
+ };
}
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index d58d5bfd8de3..2f1e2ded26ac 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -176,15 +176,14 @@ public final class UwbManager {
* arrangement, a platform may only support hemi-spherical azimuth angles
* ranging from -pi/2 to pi/2
*/
- public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 2;
+ public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3;
/**
* Indicate support for three dimensional angle of arrival measurement.
* Typically requires at least three antennas. This mode supports full
* azimuth angles ranging from -pi to pi.
*/
- public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 3;
-
+ public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4;
/**
* Gets the {@link AngleOfArrivalSupportType} supported on this platform
@@ -280,7 +279,10 @@ public final class UwbManager {
* <p>An open {@link RangingSession} will be automatically closed if client application process
* dies.
*
- * @param params {@link RangingParams} used to initialize this {@link RangingSession}
+ * <p>A UWB support library must be used in order to construct the {@code parameter}
+ * {@link PersistableBundle}.
+ *
+ * @param parameters the parameters that define the ranging session
* @param executor {@link Executor} to run callbacks
* @param callbacks {@link RangingSession.Callback} to associate with the
* {@link RangingSession} that is being opened.
@@ -291,8 +293,9 @@ public final class UwbManager {
* {@link RangingSession.Callback#onOpenSuccess}.
*/
@NonNull
- public AutoCloseable openRangingSession(@NonNull RangingParams params,
- @NonNull Executor executor, @NonNull RangingSession.Callback callbacks) {
+ public AutoCloseable openRangingSession(@NonNull PersistableBundle parameters,
+ @NonNull Executor executor,
+ @NonNull RangingSession.Callback callbacks) {
throw new UnsupportedOperationException();
}
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 237ed729e0b8..3021aa6a0783 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1405,16 +1405,29 @@ public final class Display {
private final int mWidth;
private final int mHeight;
private final float mRefreshRate;
+ @NonNull
+ private final float[] mAlternativeRefreshRates;
/**
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Mode(int modeId, int width, int height, float refreshRate) {
+ this(modeId, width, height, refreshRate, new float[0]);
+ }
+
+ /**
+ * @hide
+ */
+ public Mode(int modeId, int width, int height, float refreshRate,
+ float[] alternativeRefreshRates) {
mModeId = modeId;
mWidth = width;
mHeight = height;
mRefreshRate = refreshRate;
+ mAlternativeRefreshRates =
+ Arrays.copyOf(alternativeRefreshRates, alternativeRefreshRates.length);
+ Arrays.sort(mAlternativeRefreshRates);
}
/**
@@ -1464,6 +1477,28 @@ public final class Display {
}
/**
+ * Returns an array of refresh rates which can be switched to seamlessly.
+ * <p>
+ * A seamless switch is one without visual interruptions, such as a black screen for
+ * a second or two.
+ * <p>
+ * Presence in this list does not guarantee a switch will occur to the desired
+ * refresh rate, but rather, if a switch does occur to a refresh rate in this list,
+ * it is guaranteed to be seamless.
+ * <p>
+ * The binary relation "refresh rate X is alternative to Y" is non-reflexive,
+ * symmetric and transitive. For example the mode 1920x1080 60Hz, will never have an
+ * alternative refresh rate of 60Hz. If 1920x1080 60Hz has an alternative of 50Hz
+ * then 1920x1080 50Hz will have alternative refresh rate of 60Hz. If 1920x1080 60Hz
+ * has an alternative of 50Hz and 1920x1080 50Hz has an alternative of 24Hz, then 1920x1080
+ * 60Hz will also have an alternative of 24Hz.
+ */
+ @NonNull
+ public float[] getAlternativeRefreshRates() {
+ return mAlternativeRefreshRates;
+ }
+
+ /**
* Returns {@code true} if this mode matches the given parameters.
*
* @hide
@@ -1483,7 +1518,8 @@ public final class Display {
return false;
}
Mode that = (Mode) other;
- return mModeId == that.mModeId && matches(that.mWidth, that.mHeight, that.mRefreshRate);
+ return mModeId == that.mModeId && matches(that.mWidth, that.mHeight, that.mRefreshRate)
+ && Arrays.equals(mAlternativeRefreshRates, that.mAlternativeRefreshRates);
}
@Override
@@ -1493,6 +1529,7 @@ public final class Display {
hash = hash * 17 + mWidth;
hash = hash * 17 + mHeight;
hash = hash * 17 + Float.floatToIntBits(mRefreshRate);
+ hash = hash * 17 + Arrays.hashCode(mAlternativeRefreshRates);
return hash;
}
@@ -1503,6 +1540,8 @@ public final class Display {
.append(", width=").append(mWidth)
.append(", height=").append(mHeight)
.append(", fps=").append(mRefreshRate)
+ .append(", alternativeRefreshRates=")
+ .append(Arrays.toString(mAlternativeRefreshRates))
.append("}")
.toString();
}
@@ -1513,7 +1552,7 @@ public final class Display {
}
private Mode(Parcel in) {
- this(in.readInt(), in.readInt(), in.readInt(), in.readFloat());
+ this(in.readInt(), in.readInt(), in.readInt(), in.readFloat(), in.createFloatArray());
}
@Override
@@ -1522,6 +1561,7 @@ public final class Display {
out.writeInt(mWidth);
out.writeInt(mHeight);
out.writeFloat(mRefreshRate);
+ out.writeFloatArray(mAlternativeRefreshRates);
}
@SuppressWarnings("hiding")
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 5780d4f69f9e..f4d5a7b695eb 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.os.Trace.TRACE_TAG_VIEW;
import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER;
import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL;
import static android.view.InsetsController.AnimationType;
@@ -24,6 +25,7 @@ import static android.view.InsetsState.ITYPE_IME;
import android.annotation.Nullable;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
+import android.os.Trace;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl.Transaction;
import android.view.inputmethod.InputMethodManager;
@@ -105,6 +107,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
@Override
void notifyHidden() {
getImm().notifyImeHidden(mController.getHost().getWindowToken());
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0);
}
@Override
diff --git a/core/java/android/view/InputApplicationHandle.java b/core/java/android/view/InputApplicationHandle.java
index 108345e6db0e..4abffde68ffd 100644
--- a/core/java/android/view/InputApplicationHandle.java
+++ b/core/java/android/view/InputApplicationHandle.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.NonNull;
import android.os.IBinder;
/**
@@ -31,17 +32,20 @@ public final class InputApplicationHandle {
private long ptr;
// Application name.
- public String name;
+ public final @NonNull String name;
// Dispatching timeout.
- public long dispatchingTimeoutMillis;
+ public final long dispatchingTimeoutMillis;
- public final IBinder token;
+ public final @NonNull IBinder token;
private native void nativeDispose();
- public InputApplicationHandle(IBinder token) {
+ public InputApplicationHandle(@NonNull IBinder token, @NonNull String name,
+ long dispatchingTimeoutMillis) {
this.token = token;
+ this.name = name;
+ this.dispatchingTimeoutMillis = dispatchingTimeoutMillis;
}
public InputApplicationHandle(InputApplicationHandle handle) {
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index d1a9a05d5bf1..5a34a92a4b1a 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -37,7 +37,7 @@ public final class InputWindowHandle {
private long ptr;
// The input application handle.
- public final InputApplicationHandle inputApplicationHandle;
+ public InputApplicationHandle inputApplicationHandle;
// The token associates input data with a window and its input channel. The client input
// channel and the server input channel will both contain this token.
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index b5bf08443a6c..bcb3a36ebe2c 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.os.Trace.TRACE_TAG_VIEW;
import static android.view.InsetsControllerProto.CONTROL;
import static android.view.InsetsControllerProto.STATE;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
@@ -827,8 +828,16 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
public void show(@InsetsType int types, boolean fromIme) {
+ if ((types & ime()) != 0) {
+ Log.d(TAG, "show(ime(), fromIme=" + fromIme + ")");
+ }
if (fromIme) {
ImeTracing.getInstance().triggerDump();
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0);
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0);
+ } else {
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.showRequestFromApi", 0);
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0);
}
// Handle pending request ready in case there was one set.
if (fromIme && mPendingImeControlRequest != null) {
@@ -880,6 +889,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
void hide(@InsetsType int types, boolean fromIme) {
if (fromIme) {
ImeTracing.getInstance().triggerDump();
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0);
+ } else {
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0);
}
int typesReady = 0;
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
@@ -989,6 +1001,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
});
}
updateRequestedVisibility();
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApi", 0);
return;
}
@@ -1014,11 +1027,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
cancellationSignal.setOnCancelListener(() -> {
cancelAnimation(runner, true /* invokeCallback */);
});
+ } else {
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.pendingAnim", 0);
}
if (layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
- showDirectly(types);
+ showDirectly(types, fromIme);
} else {
- hideDirectly(types, false /* animationFinished */, animationType);
+ hideDirectly(types, false /* animationFinished */, animationType, fromIme);
}
updateRequestedVisibility();
}
@@ -1141,10 +1156,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
cancelAnimation(runner, false /* invokeCallback */);
if (DEBUG) Log.d(TAG, "notifyFinished. shown: " + shown);
if (shown) {
- showDirectly(runner.getTypes());
+ showDirectly(runner.getTypes(), true /* fromIme */);
} else {
hideDirectly(runner.getTypes(), true /* animationFinished */,
- runner.getAnimationType());
+ runner.getAnimationType(), true /* fromIme */);
}
}
@@ -1314,11 +1329,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
!hasAnimationCallbacks /* useInsetsAnimationThread */);
-
}
private void hideDirectly(
- @InsetsType int types, boolean animationFinished, @AnimationType int animationType) {
+ @InsetsType int types, boolean animationFinished, @AnimationType int animationType,
+ boolean fromIme) {
if ((types & ime()) != 0) {
ImeTracing.getInstance().triggerDump();
}
@@ -1327,9 +1342,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished, animationType);
}
updateRequestedVisibility();
+
+ if (fromIme) {
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromIme", 0);
+ }
}
- private void showDirectly(@InsetsType int types) {
+ private void showDirectly(@InsetsType int types, boolean fromIme) {
if ((types & ime()) != 0) {
ImeTracing.getInstance().triggerDump();
}
@@ -1338,6 +1357,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
getSourceConsumer(internalTypes.valueAt(i)).show(false /* fromIme */);
}
updateRequestedVisibility();
+
+ if (fromIme) {
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromIme", 0);
+ }
}
/**
@@ -1374,7 +1397,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (WARN) Log.w(TAG, "startAnimation canceled before preDraw");
return;
}
- Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW,
+ Trace.asyncTraceBegin(TRACE_TAG_VIEW,
"InsetsAnimation: " + WindowInsets.Type.toString(types), types);
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
@@ -1382,6 +1405,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
runningAnimation.startDispatched = true;
}
}
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.pendingAnim", 0);
mHost.dispatchWindowInsetsAnimationStart(animation, bounds);
mStartingAnimation = true;
controller.mReadyDispatched = true;
@@ -1392,7 +1416,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
public void dispatchAnimationEnd(WindowInsetsAnimation animation) {
- Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW,
+ Trace.asyncTraceEnd(TRACE_TAG_VIEW,
"InsetsAnimation: " + WindowInsets.Type.toString(animation.getTypeMask()),
animation.getTypeMask());
mHost.dispatchWindowInsetsAnimationEnd(animation);
diff --git a/core/java/android/view/OnReceiveContentCallback.java b/core/java/android/view/OnReceiveContentListener.java
index d74938c1d1fd..495528989a83 100644
--- a/core/java/android/view/OnReceiveContentCallback.java
+++ b/core/java/android/view/OnReceiveContentListener.java
@@ -22,77 +22,91 @@ import android.annotation.Nullable;
import android.content.ClipData;
import android.net.Uri;
import android.os.Bundle;
+import android.util.ArrayMap;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Map;
import java.util.Objects;
+import java.util.function.Predicate;
/**
- * Callback for apps to implement handling for insertion of content. Content may be both text and
+ * Listener for apps to implement handling for insertion of content. Content may be both text and
* non-text (plain/styled text, HTML, images, videos, audio files, etc).
*
- * <p>This callback can be attached to different types of UI components using
- * {@link View#setOnReceiveContentCallback}.
+ * <p>This listener can be attached to different types of UI components using
+ * {@link View#setOnReceiveContentListener}.
*
- * <p>For editable {@link android.widget.TextView} components, implementations can extend from
- * {@link android.widget.TextViewOnReceiveContentCallback} to reuse default platform behavior for
- * handling text.
- *
- * <p>Example implementation:<br>
+ * <p>Here is a sample implementation that handles content URIs and delegates the processing for
+ * text and everything else to the platform:<br>
* <pre class="prettyprint">
- * // (1) Define the callback
- * public class MyOnReceiveContentCallback implements OnReceiveContentCallback&lt;TextView&gt; {
- * public static final Set&lt;String&gt; MIME_TYPES = Collections.unmodifiableSet(
- * Set.of("image/*", "video/*"));
+ * // (1) Define the listener
+ * public class MyReceiver implements OnReceiveContentListener {
+ * public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};
*
* &#64;Override
- * public boolean onReceiveContent(@NonNull TextView view, @NonNull Payload payload) {
- * // ... app-specific logic to handle the content in the payload ...
+ * public Payload onReceiveContent(TextView view, Payload payload) {
+ * Map&lt;Boolean, Payload&gt; split = payload.partition(item -&gt; item.getUri() != null);
+ * if (split.get(true) != null) {
+ * ClipData clip = payload.getClip();
+ * for (int i = 0; i < clip.getItemCount(); i++) {
+ * Uri uri = clip.getItemAt(i).getUri();
+ * // ... app-specific logic to handle the URI ...
+ * }
+ * }
+ * // Return anything that we didn't handle ourselves. This preserves the default platform
+ * // behavior for text and anything else for which we are not implementing custom handling.
+ * return split.get(false);
* }
* }
*
- * // (2) Register the callback
+ * // (2) Register the listener
* public class MyActivity extends Activity {
* &#64;Override
* public void onCreate(Bundle savedInstanceState) {
* // ...
*
* EditText myInput = findViewById(R.id.my_input);
- * myInput.setOnReceiveContentCallback(
- * MyOnReceiveContentCallback.MIME_TYPES,
- * new MyOnReceiveContentCallback());
+ * myInput.setOnReceiveContentListener(MyReceiver.MIME_TYPES, new MyReceiver());
* }
* </pre>
- *
- * @param <T> The type of {@link View} with which this callback can be associated.
*/
-public interface OnReceiveContentCallback<T extends View> {
+public interface OnReceiveContentListener {
/**
* Receive the given content.
*
- * <p>This method is only invoked for content whose MIME type matches a type specified via
- * {@link View#setOnReceiveContentCallback}.
+ * <p>Implementations should handle any content items of interest and return all unhandled
+ * items to preserve the default platform behavior for content that does not have app-specific
+ * handling. For example, an implementation may provide handling for content URIs (to provide
+ * support for inserting images, etc) and delegate the processing of text to the platform to
+ * preserve the common behavior for inserting text. See the class javadoc for a sample
+ * implementation and see {@link Payload#partition} for a convenient way to split the passed-in
+ * content.
*
- * <p>For text, if the view has a selection, the selection should be overwritten by the clip; if
- * there's no selection, this method should insert the content at the current cursor position.
+ * <p>If implementing handling for text: if the view has a selection, the selection should
+ * be overwritten by the passed-in content; if there's no selection, the passed-in content
+ * should be inserted at the current cursor position.
*
- * <p>For non-text content (e.g. an image), the content may be inserted inline, or it may be
- * added as an attachment (could potentially be shown in a completely separate view).
+ * <p>If implementing handling for non-text content (e.g. images): the content may be
+ * inserted inline, or it may be added as an attachment (could potentially be shown in a
+ * completely separate view).
*
* @param view The view where the content insertion was requested.
* @param payload The content to insert and related metadata.
*
- * @return Returns true if the content was handled in some way, false otherwise. Actual
- * insertion may be processed asynchronously in the background and may or may not succeed even
- * if this method returns true. For example, an app may not end up inserting an item if it
- * exceeds the app's size limit for that type of content.
+ * @return The portion of the passed-in content whose processing should be delegated to
+ * the platform. Return null if all content was handled in some way. Actual insertion of
+ * the content may be processed asynchronously in the background and may or may not
+ * succeed even if this method returns null. For example, an app may end up not inserting
+ * an item if it exceeds the app's size limit for that type of content.
*/
- boolean onReceiveContent(@NonNull T view, @NonNull Payload payload);
+ @Nullable Payload onReceiveContent(@NonNull View view, @NonNull Payload payload);
/**
- * Holds all the relevant data for a request to {@link OnReceiveContentCallback}.
+ * Holds all the relevant data for a request to {@link OnReceiveContentListener}.
*/
final class Payload {
@@ -206,7 +220,7 @@ public interface OnReceiveContentCallback<T extends View> {
@Override
public String toString() {
return "Payload{"
- + "clip=" + mClip.getDescription()
+ + "clip=" + mClip
+ ", source=" + sourceToString(mSource)
+ ", flags=" + flagsToString(mFlags)
+ ", linkUri=" + mLinkUri
@@ -256,16 +270,74 @@ public interface OnReceiveContentCallback<T extends View> {
}
/**
+ * Partitions this payload based on the given predicate.
+ *
+ * <p>Similar to a
+ * {@link java.util.stream.Collectors#partitioningBy(Predicate) partitioning collector},
+ * this function classifies the content in this payload and organizes it into a map,
+ * grouping the content that matched vs didn't match the predicate.
+ *
+ * <p>Except for the {@link ClipData} items, the returned payloads will contain all the same
+ * metadata as the original payload.
+ *
+ * @param itemPredicate The predicate to test each {@link ClipData.Item} to determine which
+ * partition to place it into.
+ * @return A map containing the partitioned content. The map will contain a single entry if
+ * all items were classified into the same partition (all matched or all didn't match the
+ * predicate) or two entries (if there's at least one item that matched the predicate and at
+ * least one item that didn't match the predicate).
+ */
+ public @NonNull Map<Boolean, Payload> partition(
+ @NonNull Predicate<ClipData.Item> itemPredicate) {
+ if (mClip.getItemCount() == 1) {
+ Map<Boolean, Payload> result = new ArrayMap<>(1);
+ result.put(itemPredicate.test(mClip.getItemAt(0)), this);
+ return result;
+ }
+ ArrayList<ClipData.Item> accepted = new ArrayList<>();
+ ArrayList<ClipData.Item> remaining = new ArrayList<>();
+ for (int i = 0; i < mClip.getItemCount(); i++) {
+ ClipData.Item item = mClip.getItemAt(i);
+ if (itemPredicate.test(item)) {
+ accepted.add(item);
+ } else {
+ remaining.add(item);
+ }
+ }
+ Map<Boolean, Payload> result = new ArrayMap<>(2);
+ if (!accepted.isEmpty()) {
+ ClipData acceptedClip = new ClipData(mClip.getDescription(), accepted);
+ result.put(true, new Builder(this).setClip(acceptedClip).build());
+ }
+ if (!remaining.isEmpty()) {
+ ClipData remainingClip = new ClipData(mClip.getDescription(), remaining);
+ result.put(false, new Builder(this).setClip(remainingClip).build());
+ }
+ return result;
+ }
+
+ /**
* Builder for {@link Payload}.
*/
public static final class Builder {
- @NonNull private final ClipData mClip;
- private final @Source int mSource;
+ @NonNull private ClipData mClip;
+ private @Source int mSource;
private @Flags int mFlags;
@Nullable private Uri mLinkUri;
@Nullable private Bundle mExtras;
/**
+ * Creates a new builder initialized with the data from the given builder.
+ */
+ public Builder(@NonNull Payload payload) {
+ mClip = payload.mClip;
+ mSource = payload.mSource;
+ mFlags = payload.mFlags;
+ mLinkUri = payload.mLinkUri;
+ mExtras = payload.mExtras;
+ }
+
+ /**
* Creates a new builder.
* @param clip The data to insert.
* @param source The source of the operation. See {@code SOURCE_} constants.
@@ -276,6 +348,28 @@ public interface OnReceiveContentCallback<T extends View> {
}
/**
+ * Sets the data to be inserted.
+ * @param clip The data to insert.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setClip(@NonNull ClipData clip) {
+ mClip = clip;
+ return this;
+ }
+
+ /**
+ * Sets the source of the operation.
+ * @param source The source of the operation. See {@code SOURCE_} constants.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setSource(@Source int source) {
+ mSource = source;
+ return this;
+ }
+
+ /**
* Sets flags that control content insertion behavior.
* @param flags Optional flags to configure the insertion behavior. Use 0 for default
* behavior. See {@code FLAG_} constants.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 14748f03e934..15adc5a0ec2f 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -432,7 +432,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
* This gets called on a RenderThread worker thread, so members accessed here must
* be protected by a lock.
*/
- final boolean useBLAST = viewRoot.useBLAST();
+ final boolean useBLAST = useBLASTSync(viewRoot);
viewRoot.registerRtFrameCallback(frame -> {
try {
synchronized (mSurfaceControlLock) {
@@ -809,7 +809,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
* This gets called on a RenderThread worker thread, so members accessed here must
* be protected by a lock.
*/
- final boolean useBLAST = viewRoot.useBLAST();
+ final boolean useBLAST = useBLASTSync(viewRoot);
viewRoot.registerRtFrameCallback(frame -> {
try {
synchronized (mSurfaceControlLock) {
@@ -1110,7 +1110,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
final boolean needBLASTSync =
(layoutSizeChanged || positionChanged || visibleChanged) &&
- viewRoot.useBLAST();
+ useBLASTSync(viewRoot);
final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
translator, creating, sizeChanged, needBLASTSync);
final boolean redrawNeeded = sizeChanged || creating ||
@@ -1352,7 +1352,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
Rect position, long frameNumber) {
final ViewRootImpl viewRoot = getViewRootImpl();
- if (frameNumber > 0 && viewRoot != null && !viewRoot.useBLAST()) {
+ if (frameNumber > 0 && viewRoot != null && !useBLASTSync(viewRoot)) {
t.deferTransactionUntil(surface, viewRoot.getSurfaceControl(),
frameNumber);
}
@@ -1385,7 +1385,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private void setParentSpaceRectangle(Rect position, long frameNumber) {
final ViewRootImpl viewRoot = getViewRootImpl();
- final boolean useBLAST = viewRoot.useBLAST();
+ final boolean useBLAST = useBLASTSync(viewRoot);
if (useBLAST) {
synchronized (viewRoot.getBlastTransactionLock()) {
@@ -1444,7 +1444,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
@Override
public void positionLost(long frameNumber) {
final ViewRootImpl viewRoot = getViewRootImpl();
- boolean useBLAST = viewRoot != null && viewRoot.useBLAST();
+ boolean useBLAST = viewRoot != null && useBLASTSync(viewRoot);
if (DEBUG) {
Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
System.identityHashCode(this), frameNumber));
@@ -1920,4 +1920,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
+ "Exception requesting focus on embedded window", e);
}
}
+
+ private boolean useBLASTSync(ViewRootImpl viewRoot) {
+ return viewRoot.useBLAST() && mUseBlastAdapter;
+ }
}
diff --git a/core/java/android/view/VerifiedKeyEvent.java b/core/java/android/view/VerifiedKeyEvent.java
index dc5b7cc1e13a..77a7d0944521 100644
--- a/core/java/android/view/VerifiedKeyEvent.java
+++ b/core/java/android/view/VerifiedKeyEvent.java
@@ -137,11 +137,10 @@ public final class VerifiedKeyEvent extends VerifiedInputEvent implements Parcel
// 3. add the "super" call for constructor that receives a Parcel
// 4. add the "super" call to the writeToParcel method
// 5. Update "equals" and "hashcode" methods to include VerifiedInputEvent fields
- // 6. Edit "inputSignatures" to ensure KeyEventAction is properly qualified
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -180,14 +179,13 @@ public final class VerifiedKeyEvent extends VerifiedInputEvent implements Parcel
* this is the number of down/up pairs that have occurred.
* @hide
*/
- @DataClass.Generated.Member
public VerifiedKeyEvent(
int deviceId,
long eventTimeNanos,
int source,
int displayId,
@KeyEventAction int action,
- @SuppressLint({"MethodNameUnits"}) long downTimeNanos,
+ @SuppressLint({ "MethodNameUnits" }) long downTimeNanos,
int flags,
int keyCode,
int scanCode,
@@ -198,16 +196,11 @@ public final class VerifiedKeyEvent extends VerifiedInputEvent implements Parcel
com.android.internal.util.AnnotationValidations.validate(
KeyEventAction.class, null, mAction);
this.mDownTimeNanos = downTimeNanos;
- com.android.internal.util.AnnotationValidations.validate(
- SuppressLint.class, null, mDownTimeNanos,
- "value", "MethodNameUnits");
this.mFlags = flags;
this.mKeyCode = keyCode;
this.mScanCode = scanCode;
this.mMetaState = metaState;
this.mRepeatCount = repeatCount;
-
- // onConstructed(); // You can define this method to get a callback
}
/**
@@ -229,7 +222,7 @@ public final class VerifiedKeyEvent extends VerifiedInputEvent implements Parcel
* @see KeyEvent#getDownTime()
*/
@DataClass.Generated.Member
- public @SuppressLint({"MethodNameUnits"}) long getDownTimeNanos() {
+ public @SuppressLint({ "MethodNameUnits" }) long getDownTimeNanos() {
return mDownTimeNanos;
}
@@ -301,10 +294,7 @@ public final class VerifiedKeyEvent extends VerifiedInputEvent implements Parcel
VerifiedKeyEvent that = (VerifiedKeyEvent) o;
//noinspection PointlessBooleanExpression
return true
- && getDeviceId() == that.getDeviceId()
- && getEventTimeNanos() == that.getEventTimeNanos()
- && getSource() == that.getSource()
- && getDisplayId() == that.getDisplayId()
+ && super.equals(that)
&& mAction == that.mAction
&& mDownTimeNanos == that.mDownTimeNanos
&& mFlags == that.mFlags
@@ -321,10 +311,7 @@ public final class VerifiedKeyEvent extends VerifiedInputEvent implements Parcel
// int fieldNameHashCode() { ... }
int _hash = 1;
- _hash = 31 * _hash + getDeviceId();
- _hash = 31 * _hash + Long.hashCode(getEventTimeNanos());
- _hash = 31 * _hash + getSource();
- _hash = 31 * _hash + getDisplayId();
+ _hash = 31 * _hash + super.hashCode();
_hash = 31 * _hash + mAction;
_hash = 31 * _hash + Long.hashCode(mDownTimeNanos);
_hash = 31 * _hash + mFlags;
@@ -341,6 +328,7 @@ public final class VerifiedKeyEvent extends VerifiedInputEvent implements Parcel
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
super.writeToParcel(dest, flags);
+
dest.writeInt(mAction);
dest.writeLong(mDownTimeNanos);
dest.writeInt(mFlags);
@@ -361,6 +349,7 @@ public final class VerifiedKeyEvent extends VerifiedInputEvent implements Parcel
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
super(in, VERIFIED_KEY);
+
int action = in.readInt();
long downTimeNanos = in.readLong();
int flags = in.readInt();
@@ -373,9 +362,6 @@ public final class VerifiedKeyEvent extends VerifiedInputEvent implements Parcel
com.android.internal.util.AnnotationValidations.validate(
KeyEventAction.class, null, mAction);
this.mDownTimeNanos = downTimeNanos;
- com.android.internal.util.AnnotationValidations.validate(
- SuppressLint.class, null, mDownTimeNanos,
- "value", "MethodNameUnits");
this.mFlags = flags;
this.mKeyCode = keyCode;
this.mScanCode = scanCode;
@@ -400,10 +386,10 @@ public final class VerifiedKeyEvent extends VerifiedInputEvent implements Parcel
};
@DataClass.Generated(
- time = 1581107066890L,
- codegenVersion = "1.0.14",
+ time = 1604509197793L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/view/VerifiedKeyEvent.java",
- inputSignatures = "private static final java.lang.String TAG\nprivate @android.view.VerifiedKeyEvent.KeyEventAction int mAction\nprivate @android.annotation.SuppressLint({\"MethodNameUnits\"}) long mDownTimeNanos\nprivate int mFlags\nprivate int mKeyCode\nprivate int mScanCode\nprivate int mMetaState\nprivate int mRepeatCount\npublic @android.annotation.Nullable java.lang.Boolean getFlag(int)\nclass VerifiedKeyEvent extends android.view.VerifiedInputEvent implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true)")
+ inputSignatures = "private static final java.lang.String TAG\nprivate @android.view.VerifiedKeyEvent.KeyEventAction int mAction\nprivate @android.annotation.SuppressLint long mDownTimeNanos\nprivate int mFlags\nprivate int mKeyCode\nprivate int mScanCode\nprivate int mMetaState\nprivate int mRepeatCount\npublic @android.annotation.Nullable java.lang.Boolean getFlag(int)\nclass VerifiedKeyEvent extends android.view.VerifiedInputEvent implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/VerifiedMotionEvent.java b/core/java/android/view/VerifiedMotionEvent.java
index b4c5d24775ea..7d8345928bf0 100644
--- a/core/java/android/view/VerifiedMotionEvent.java
+++ b/core/java/android/view/VerifiedMotionEvent.java
@@ -131,11 +131,10 @@ public final class VerifiedMotionEvent extends VerifiedInputEvent implements Par
// 3. add the "super" call for constructor that receives a Parcel
// 4. add the "super" call to the writeToParcel method
// 5. Update "equals" and "hashcode" methods to include VerifiedInputEvent fields
- // 6. Edit "inputSignatures" to ensure MotionEventAction is properly qualified
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -174,7 +173,7 @@ public final class VerifiedMotionEvent extends VerifiedInputEvent implements Par
float rawX,
float rawY,
@MotionEventAction int actionMasked,
- @SuppressLint({"MethodNameUnits"}) long downTimeNanos,
+ @SuppressLint({ "MethodNameUnits" }) long downTimeNanos,
int flags,
int metaState,
int buttonState) {
@@ -185,9 +184,6 @@ public final class VerifiedMotionEvent extends VerifiedInputEvent implements Par
com.android.internal.util.AnnotationValidations.validate(
MotionEventAction.class, null, mActionMasked);
this.mDownTimeNanos = downTimeNanos;
- com.android.internal.util.AnnotationValidations.validate(
- SuppressLint.class, null, mDownTimeNanos,
- "value", "MethodNameUnits");
this.mFlags = flags;
this.mMetaState = metaState;
this.mButtonState = buttonState;
@@ -232,7 +228,7 @@ public final class VerifiedMotionEvent extends VerifiedInputEvent implements Par
* @see MotionEvent#getDownTime()
*/
@DataClass.Generated.Member
- public @SuppressLint({"MethodNameUnits"}) long getDownTimeNanos() {
+ public @SuppressLint({ "MethodNameUnits" }) long getDownTimeNanos() {
return mDownTimeNanos;
}
@@ -280,10 +276,7 @@ public final class VerifiedMotionEvent extends VerifiedInputEvent implements Par
VerifiedMotionEvent that = (VerifiedMotionEvent) o;
//noinspection PointlessBooleanExpression
return true
- && getDeviceId() == that.getDeviceId()
- && getEventTimeNanos() == that.getEventTimeNanos()
- && getSource() == that.getSource()
- && getDisplayId() == that.getDisplayId()
+ && super.equals(that)
&& mRawX == that.mRawX
&& mRawY == that.mRawY
&& mActionMasked == that.mActionMasked
@@ -300,10 +293,7 @@ public final class VerifiedMotionEvent extends VerifiedInputEvent implements Par
// int fieldNameHashCode() { ... }
int _hash = 1;
- _hash = 31 * _hash + getDeviceId();
- _hash = 31 * _hash + Long.hashCode(getEventTimeNanos());
- _hash = 31 * _hash + getSource();
- _hash = 31 * _hash + getDisplayId();
+ _hash = 31 * _hash + super.hashCode();
_hash = 31 * _hash + Float.hashCode(mRawX);
_hash = 31 * _hash + Float.hashCode(mRawY);
_hash = 31 * _hash + mActionMasked;
@@ -320,6 +310,7 @@ public final class VerifiedMotionEvent extends VerifiedInputEvent implements Par
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
super.writeToParcel(dest, flags);
+
dest.writeFloat(mRawX);
dest.writeFloat(mRawY);
dest.writeInt(mActionMasked);
@@ -340,6 +331,7 @@ public final class VerifiedMotionEvent extends VerifiedInputEvent implements Par
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
super(in, VERIFIED_MOTION);
+
float rawX = in.readFloat();
float rawY = in.readFloat();
int actionMasked = in.readInt();
@@ -354,9 +346,6 @@ public final class VerifiedMotionEvent extends VerifiedInputEvent implements Par
com.android.internal.util.AnnotationValidations.validate(
MotionEventAction.class, null, mActionMasked);
this.mDownTimeNanos = downTimeNanos;
- com.android.internal.util.AnnotationValidations.validate(
- SuppressLint.class, null, mDownTimeNanos,
- "value", "MethodNameUnits");
this.mFlags = flags;
this.mMetaState = metaState;
this.mButtonState = buttonState;
@@ -379,10 +368,10 @@ public final class VerifiedMotionEvent extends VerifiedInputEvent implements Par
};
@DataClass.Generated(
- time = 1581107073238L,
- codegenVersion = "1.0.14",
+ time = 1604509199368L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/view/VerifiedMotionEvent.java",
- inputSignatures = "private static final java.lang.String TAG\nprivate float mRawX\nprivate float mRawY\nprivate @android.view.VerifiedMotionEvent.MotionEventAction int mActionMasked\nprivate @android.annotation.SuppressLint({\"MethodNameUnits\"}) long mDownTimeNanos\nprivate int mFlags\nprivate int mMetaState\nprivate int mButtonState\npublic @android.annotation.Nullable java.lang.Boolean getFlag(int)\nclass VerifiedMotionEvent extends android.view.VerifiedInputEvent implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true)")
+ inputSignatures = "private static final java.lang.String TAG\nprivate float mRawX\nprivate float mRawY\nprivate @android.view.VerifiedMotionEvent.MotionEventAction int mActionMasked\nprivate @android.annotation.SuppressLint long mDownTimeNanos\nprivate int mFlags\nprivate int mMetaState\nprivate int mButtonState\npublic @android.annotation.Nullable java.lang.Boolean getFlag(int)\nclass VerifiedMotionEvent extends android.view.VerifiedInputEvent implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cefddd84ee32..a88ad9f24c10 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -112,6 +112,7 @@ import android.view.AccessibilityIterators.TextSegmentIterator;
import android.view.AccessibilityIterators.WordTextSegmentIterator;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.InputDevice.InputSourceClass;
+import android.view.OnReceiveContentListener.Payload;
import android.view.Window.OnContentApplyWindowInsetsListener;
import android.view.WindowInsets.Type;
import android.view.WindowInsetsAnimation.Bounds;
@@ -143,6 +144,7 @@ import android.widget.FrameLayout;
import android.widget.ScrollBarDrawable;
import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.Preconditions;
import com.android.internal.view.ScrollCaptureInternal;
@@ -4713,6 +4715,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* Allows the application to implement custom scroll capture support.
*/
ScrollCaptureCallback mScrollCaptureCallback;
+
+ @Nullable
+ private OnReceiveContentListener mOnReceiveContentListener;
}
@UnsupportedAppUsage
@@ -5246,8 +5251,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@Nullable
private String[] mOnReceiveContentMimeTypes;
- @Nullable
- private OnReceiveContentCallback mOnReceiveContentCallback;
/**
* Simple constructor to use when creating a view from code.
@@ -9005,72 +9008,92 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Sets the callback to handle insertion of content into this view.
+ * Sets the listener to be {@link #onReceiveContent used} to handle insertion of
+ * content into this view.
*
- * <p>Depending on the view, this callback may be invoked for scenarios such as content
- * insertion from the IME, Autofill, etc.
+ * <p>Depending on the type of view, this listener may be invoked for different scenarios. For
+ * example, for editable TextViews, this listener will be invoked for the following scenarios:
+ * <ol>
+ * <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the
+ * insertion/selection menu)
+ * <li>Content insertion from the keyboard (from {@link InputConnection#commitContent})
+ * <li>Drag and drop (drop events from {@link #onDragEvent(DragEvent)})
+ * <li>Autofill
+ * <li>Selection replacement via {@link Intent#ACTION_PROCESS_TEXT}
+ * </ol>
*
- * <p>This callback is only invoked for content whose MIME type matches a type specified via
- * the {code mimeTypes} parameter. If the MIME type is not supported by the callback, the
- * default platform handling will be executed instead (no-op for the default {@link View}).
+ * <p>When setting a listener, clients should also declare the MIME types accepted by it.
+ * When invoked with other types of content, the listener may reject the content (defer to
+ * the default platform behavior) or execute some other fallback logic. The MIME types
+ * declared here allow different features to optionally alter their behavior. For example,
+ * the soft keyboard may choose to hide its UI for inserting GIFs for a particular input
+ * field if the MIME types set here for that field don't include "image/gif" or "image/*".
*
- * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC
- * MIME types. As a result, you should always write your MIME types with lower case letters, or
- * use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to lower
- * case.</em>
+ * <p>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC
+ * MIME types. As a result, you should always write your MIME types with lowercase letters,
+ * or use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to
+ * lowercase.
*
- * @param mimeTypes The type of content for which the callback should be invoked. This may use
- * wildcards such as "text/*", "image/*", etc. This must not be null or empty if a non-null
- * callback is passed in.
- * @param callback The callback to use. This can be null to reset to the default behavior.
+ * @param mimeTypes The MIME types accepted by the given listener. These may use patterns
+ * such as "image/*", but may not start with a wildcard. This argument must
+ * not be null or empty if a non-null listener is passed in.
+ * @param listener The listener to use. This can be null to reset to the default behavior.
*/
@SuppressWarnings("rawtypes")
- public void setOnReceiveContentCallback(@Nullable String[] mimeTypes,
- @Nullable OnReceiveContentCallback callback) {
- if (callback != null) {
+ public void setOnReceiveContentListener(@Nullable String[] mimeTypes,
+ @Nullable OnReceiveContentListener listener) {
+ if (listener != null) {
Preconditions.checkArgument(mimeTypes != null && mimeTypes.length > 0,
- "When the callback is set, MIME types must also be set");
+ "When the listener is set, MIME types must also be set");
+ }
+ if (mimeTypes != null) {
+ Preconditions.checkArgument(Arrays.stream(mimeTypes).noneMatch(t -> t.startsWith("*")),
+ "A MIME type set here must not start with *: " + Arrays.toString(mimeTypes));
}
- mOnReceiveContentMimeTypes = mimeTypes;
- mOnReceiveContentCallback = callback;
+ mOnReceiveContentMimeTypes = ArrayUtils.isEmpty(mimeTypes) ? null : mimeTypes;
+ getListenerInfo().mOnReceiveContentListener = listener;
}
/**
- * Receives the given content. The default implementation invokes the callback set via
- * {@link #setOnReceiveContentCallback}. If no callback is set or if the callback does not
- * support the given content (based on the MIME type), returns false.
+ * Receives the given content. Invokes the listener configured via
+ * {@link #setOnReceiveContentListener}; if no listener is set, the default implementation is a
+ * no-op (returns the passed-in content without acting on it).
*
* @param payload The content to insert and related metadata.
*
- * @return Returns true if the content was handled in some way, false otherwise. Actual
- * insertion may be processed asynchronously in the background and may or may not succeed even
- * if this method returns true. For example, an app may not end up inserting an item if it
- * exceeds the app's size limit for that type of content.
+ * @return The portion of the passed-in content that was not accepted (may be all, some, or none
+ * of the passed-in content).
*/
- public boolean onReceiveContent(@NonNull OnReceiveContentCallback.Payload payload) {
- ClipDescription description = payload.getClip().getDescription();
- if (mOnReceiveContentCallback != null && mOnReceiveContentMimeTypes != null
- && description.hasMimeType(mOnReceiveContentMimeTypes)) {
- return mOnReceiveContentCallback.onReceiveContent(this, payload);
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public @Nullable Payload onReceiveContent(@NonNull Payload payload) {
+ final OnReceiveContentListener listener = (mListenerInfo == null) ? null
+ : getListenerInfo().mOnReceiveContentListener;
+ if (listener != null) {
+ return listener.onReceiveContent(this, payload);
}
- return false;
+ return payload;
}
/**
- * Returns the MIME types that can be handled by {@link #onReceiveContent} for this view, as
- * configured via {@link #setOnReceiveContentCallback}. By default returns null.
+ * Returns the MIME types accepted by {@link #onReceiveContent} for this view, as
+ * configured via {@link #setOnReceiveContentListener}. By default returns null.
*
- * <p>Different platform features (e.g. pasting from the clipboard, inserting stickers from the
- * keyboard, etc) may use this function to conditionally alter their behavior. For example, the
- * soft keyboard may choose to hide its UI for inserting GIFs for a particular input field if
- * the MIME types returned here for that field don't include "image/gif".
+ * <p>Different features (e.g. pasting from the clipboard, inserting stickers from the soft
+ * keyboard, etc) may optionally use this metadata to conditionally alter their behavior. For
+ * example, a soft keyboard may choose to hide its UI for inserting GIFs for a particular
+ * input field if the MIME types returned here for that field don't include "image/gif" or
+ * "image/*".
*
* <p>Note: Comparisons of MIME types should be performed using utilities such as
* {@link ClipDescription#compareMimeTypes} rather than simple string equality, in order to
- * correctly handle patterns (e.g. "text/*").
- *
- * @return The MIME types supported by {@link #onReceiveContent} for this view. The returned
- * MIME types may contain wildcards such as "text/*", "image/*", etc.
+ * correctly handle patterns such as "text/*", "image/*", etc. Note that MIME type matching
+ * in the Android framework is case-sensitive, unlike formal RFC MIME types. As a result,
+ * you should always write your MIME types with lowercase letters, or use
+ * {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to
+ * lowercase.
+ *
+ * @return The MIME types accepted by {@link #onReceiveContent} for this view (may
+ * include patterns such as "image/*").
*/
public @Nullable String[] getOnReceiveContentMimeTypes() {
return mOnReceiveContentMimeTypes;
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 16211fcecdf4..c2f17c310363 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -604,7 +604,6 @@ public class ViewConfiguration {
/**
* @return the duration in milliseconds between the first tap's up event and the second tap's
* down event for an interaction to be considered part of the same multi-press.
- * @hide
*/
public static int getMultiPressTimeout() {
return AppGlobals.getIntCoreSetting(Settings.Secure.MULTI_PRESS_TIMEOUT,
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0e8cd546a2ae..c0770063beea 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1890,8 +1890,10 @@ public final class ViewRootImpl implements ViewParent,
mSurface.release();
mSurfaceControl.release();
- // We should probably add an explicit dispose.
- mBlastBufferQueue = null;
+ if (mBlastBufferQueue != null) {
+ mBlastBufferQueue.destroy();
+ mBlastBufferQueue = null;
+ }
}
/**
@@ -2641,18 +2643,12 @@ public final class ViewRootImpl implements ViewParent,
|| mForceNextWindowRelayout) {
mForceNextWindowRelayout = false;
- if (isViewVisible) {
- // If this window is giving internal insets to the window
- // manager, and it is being added or changing its visibility,
- // then we want to first give the window manager "fake"
- // insets to cause it to effectively ignore the content of
- // the window during layout. This avoids it briefly causing
- // other windows to resize/move based on the raw frame of the
- // window, waiting until we can finish laying out this window
- // and get back to the window manager with the ultimately
- // computed insets.
- insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
- }
+ // If this window is giving internal insets to the window manager, then we want to first
+ // make the provided insets unchanged during layout. This avoids it briefly causing
+ // other windows to resize/move based on the raw frame of the window, waiting until we
+ // can finish laying out this window and get back to the window manager with the
+ // ultimately computed insets.
+ insetsPending = computesInternalInsets;
if (mSurfaceHolder != null) {
mSurfaceHolder.mSurfaceLock.lock();
@@ -3910,7 +3906,8 @@ public final class ViewRootImpl implements ViewParent,
return;
}
- final boolean fullRedrawNeeded = mFullRedrawNeeded || mReportNextDraw;
+ final boolean fullRedrawNeeded =
+ mFullRedrawNeeded || mReportNextDraw || mNextDrawUseBLASTSyncTransaction;
mFullRedrawNeeded = false;
mIsDrawing = true;
@@ -9919,6 +9916,18 @@ public final class ViewRootImpl implements ViewParent,
} else {
t.merge(mRtBLASTSyncTransaction);
}
+
+ // There's potential for the frame callback to get called even if nothing was drawn.
+ // When that occurs, we remove the transaction sent to BBQ since the draw we were
+ // waiting on will not happen. We can apply the transaction here but it will not contain
+ // a buffer since nothing new was drawn.
+ //
+ // This is mainly for the case when the SurfaceView has changed and wants to synchronize
+ // with the main window. If the main window doesn't need to draw anything, we can just
+ // apply the transaction without the new buffer from the main window.
+ if (mBlastBufferQueue != null) {
+ mBlastBufferQueue.setNextTransaction(null);
+ }
}
}
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 606e8f99999a..29ce231d5d87 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -97,6 +97,7 @@ public abstract class ViewStructure {
public abstract void setVisibility(int visibility);
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void setAssistBlocked(boolean state);
/**
@@ -431,6 +432,7 @@ public abstract class ViewStructure {
public abstract void asyncCommit();
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract Rect getTempRect();
/**
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 8dd4b667d357..9c163783124e 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1387,6 +1387,7 @@ public abstract class Window {
}
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void alwaysReadCloseOnTouchAttr();
@@ -1567,6 +1568,7 @@ public abstract class Window {
*
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void clearContentView();
/**
@@ -2636,18 +2638,21 @@ public abstract class Window {
* Called when the activity changes from fullscreen mode to multi-window mode and visa-versa.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void onMultiWindowModeChanged();
/**
* Called when the activity changes to/from picture-in-picture mode.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void onPictureInPictureModeChanged(boolean isInPictureInPictureMode);
/**
* Called when the activity just relaunched.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void reportActivityRelaunched();
/**
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index b4a841f8fdb0..72f76d1a9dc9 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -2237,6 +2237,8 @@ public interface WindowManager extends ViewManager {
PRIVATE_FLAG_BEHAVIOR_CONTROLLED,
PRIVATE_FLAG_FIT_INSETS_CONTROLLED,
PRIVATE_FLAG_TRUSTED_OVERLAY,
+ PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME,
+ PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP,
})
public @interface PrivateFlags {}
@@ -2347,6 +2349,10 @@ public interface WindowManager extends ViewManager {
equals = PRIVATE_FLAG_TRUSTED_OVERLAY,
name = "TRUSTED_OVERLAY"),
@ViewDebug.FlagToString(
+ mask = PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME,
+ equals = PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME,
+ name = "INSET_PARENT_FRAME_BY_IME"),
+ @ViewDebug.FlagToString(
mask = PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP,
equals = PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP,
name = "INTERCEPT_GLOBAL_DRAG_AND_DROP")
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
index 2343bf3e8d19..d0ab004d6cf3 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
@@ -50,4 +50,14 @@ import android.graphics.Rect;
* @param sourceBounds The magnified bounds in screen coordinates.
*/
void onSourceBoundsChanged(int displayId, in Rect sourceBounds);
+
+ /**
+ * Called when the accessibility action of scale requests to be performed.
+ * It is invoked from System UI. And the action is provided by the mirror window.
+ *
+ * @param displayId The logical display id.
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ */
+ void onPerformScaleAction(int displayId, float scale);
+
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 81db62857c17..299c41b02b23 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -19,7 +19,7 @@ package android.view.autofill;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_AUTOFILL;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
import static android.view.autofill.Helper.toList;
@@ -62,7 +62,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.Choreographer;
import android.view.KeyEvent;
-import android.view.OnReceiveContentCallback;
+import android.view.OnReceiveContentListener.Payload;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -2371,12 +2371,10 @@ public final class AutofillManager {
reportAutofillContentFailure(id);
return;
}
- OnReceiveContentCallback.Payload payload =
- new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_AUTOFILL)
- .build();
- boolean handled = view.onReceiveContent(payload);
- if (!handled) {
- Log.w(TAG, "autofillContent(): receiver returned false: id=" + id
+ Payload payload = new Payload.Builder(clip, SOURCE_AUTOFILL).build();
+ Payload result = view.onReceiveContent(payload);
+ if (result != null) {
+ Log.w(TAG, "autofillContent(): receiver could not insert content: id=" + id
+ ", view=" + view + ", clip=" + clip);
reportAutofillContentFailure(id);
return;
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 62b1b1f8cf53..a92d1f589e96 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -16,7 +16,7 @@
package android.view.inputmethod;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_INPUT_METHOD;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_INPUT_METHOD;
import android.annotation.CallSuper;
import android.annotation.IntRange;
@@ -40,7 +40,7 @@ import android.util.Log;
import android.util.LogPrinter;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
-import android.view.OnReceiveContentCallback;
+import android.view.OnReceiveContentListener;
import android.view.View;
class ComposingText implements NoCopySpan {
@@ -928,17 +928,14 @@ public class BaseInputConnection implements InputConnection {
/**
* Default implementation which invokes {@link View#onReceiveContent} on the target view if the
- * MIME type of the content matches one of the MIME types returned by
- * {@link View#getOnReceiveContentMimeTypes()}. If the MIME type of the content is not matched,
- * returns false without any side effects.
+ * view {@link View#getOnReceiveContentMimeTypes allows} content insertion; otherwise returns
+ * false without any side effects.
*/
public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
ClipDescription description = inputContentInfo.getDescription();
- final String[] viewMimeTypes = mTargetView.getOnReceiveContentMimeTypes();
- if (viewMimeTypes == null || !description.hasMimeType(viewMimeTypes)) {
+ if (mTargetView.getOnReceiveContentMimeTypes() == null) {
if (DEBUG) {
- Log.d(TAG, "Can't insert content from IME; unsupported MIME type: content="
- + description + ", viewMimeTypes=" + viewMimeTypes);
+ Log.d(TAG, "Can't insert content from IME: content=" + description);
}
return false;
}
@@ -950,13 +947,13 @@ public class BaseInputConnection implements InputConnection {
return false;
}
}
- final ClipData clip = new ClipData(description,
+ final ClipData clip = new ClipData(inputContentInfo.getDescription(),
new ClipData.Item(inputContentInfo.getContentUri()));
- final OnReceiveContentCallback.Payload payload =
- new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_INPUT_METHOD)
+ final OnReceiveContentListener.Payload payload =
+ new OnReceiveContentListener.Payload.Builder(clip, SOURCE_INPUT_METHOD)
.setLinkUri(inputContentInfo.getLinkUri())
.setExtras(opts)
.build();
- return mTargetView.onReceiveContent(payload);
+ return mTargetView.onReceiveContent(payload) == null;
}
}
diff --git a/core/java/android/view/inputmethod/InlineSuggestionInfo.java b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
index 1c703ecf06ca..73962d7f65e0 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionInfo.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionInfo.java
@@ -88,7 +88,7 @@ public final class InlineSuggestionInfo implements Parcelable {
- // Code below generated by codegen v1.0.15.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -346,10 +346,10 @@ public final class InlineSuggestionInfo implements Parcelable {
};
@DataClass.Generated(
- time = 1586992414034L,
- codegenVersion = "1.0.15",
+ time = 1604456249219L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionInfo.java",
- inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint({\"IntentName\"}) @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\nprivate final boolean mPinned\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.widget.inline.InlinePresentationSpec,java.lang.String,java.lang.String[],java.lang.String,boolean)\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
+ inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_SUGGESTION\npublic static final @android.annotation.SuppressLint @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String TYPE_ACTION\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Type java.lang.String mType\nprivate final boolean mPinned\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo newInlineSuggestionInfo(android.widget.inline.InlinePresentationSpec,java.lang.String,java.lang.String[],java.lang.String,boolean)\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 0fe47b7828d9..14b5d7c72d2f 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -190,7 +190,7 @@ public interface InputConnection {
*
* @param n The expected length of the text. This must be non-negative.
* @param flags Supplies additional options controlling how the text is
- * returned. May be either 0 or {@link #GET_TEXT_WITH_STYLES}.
+ * returned. May be either {@code 0} or {@link #GET_TEXT_WITH_STYLES}.
* @return the text before the cursor position; the length of the
* returned text might be less than <var>n</var>.
* @throws IllegalArgumentException if {@code n} is negative.
@@ -234,7 +234,7 @@ public interface InputConnection {
*
* @param n The expected length of the text. This must be non-negative.
* @param flags Supplies additional options controlling how the text is
- * returned. May be either 0 or {@link #GET_TEXT_WITH_STYLES}.
+ * returned. May be either {@code 0} or {@link #GET_TEXT_WITH_STYLES}.
*
* @return the text after the cursor position; the length of the
* returned text might be less than <var>n</var>.
@@ -273,7 +273,7 @@ public interface InputConnection {
* consistent with the results of the latest edits.</p>
*
* @param flags Supplies additional options controlling how the text is
- * returned. May be either 0 or {@link #GET_TEXT_WITH_STYLES}.
+ * returned. May be either {@code 0} or {@link #GET_TEXT_WITH_STYLES}.
* @return the text that is currently selected, if any, or null if
* no text is selected. In {@link android.os.Build.VERSION_CODES#N} and
* later, returns false when the target application does not implement
@@ -284,7 +284,8 @@ public interface InputConnection {
/**
* Gets the surrounding text around the current cursor, with <var>beforeLength</var> characters
* of text before the cursor (start of the selection), <var>afterLength</var> characters of text
- * after the cursor (end of the selection), and all of the selected text.
+ * after the cursor (end of the selection), and all of the selected text. The range are for java
+ * characters, not glyphs that can be multiple characters.
*
* <p>This method may fail either if the input connection has become invalid (such as its
* process crashing), or the client is taking too long to respond with the text (it is given a
@@ -306,8 +307,8 @@ public interface InputConnection {
*
* @param beforeLength The expected length of the text before the cursor.
* @param afterLength The expected length of the text after the cursor.
- * @param flags Supplies additional options controlling how the text is returned. Defined by the
- * constants.
+ * @param flags Supplies additional options controlling how the text is returned. May be either
+ * {@code 0} or {@link #GET_TEXT_WITH_STYLES}.
* @return an {@link android.view.inputmethod.SurroundingText} object describing the surrounding
* text and state of selection, or null if the input connection is no longer valid, or the
* editor can't comply with the request for some reason, or the application does not implement
@@ -394,7 +395,7 @@ public interface InputConnection {
*
* @param request Description of how the text should be returned.
* {@link android.view.inputmethod.ExtractedTextRequest}
- * @param flags Additional options to control the client, either 0 or
+ * @param flags Additional options to control the client, either {@code 0} or
* {@link #GET_EXTRACTED_TEXT_MONITOR}.
* @return an {@link android.view.inputmethod.ExtractedText}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 6243c63531eb..f1cbd2533a5a 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1672,10 +1672,12 @@ public final class InputMethodManager {
checkFocus();
synchronized (mH) {
if (!hasServedByInputMethodLocked(view)) {
+ Log.w(TAG, "Ignoring showSoftInput() as view=" + view + " is not served.");
return false;
}
try {
+ Log.d(TAG, "showSoftInput() view=" + view + " flags=" + flags);
return mService.showSoftInput(
mClient, view.getWindowToken(), flags, resultReceiver);
} catch (RemoteException e) {
diff --git a/core/java/android/view/inputmethod/SurroundingText.java b/core/java/android/view/inputmethod/SurroundingText.java
index 506f95a4ac7b..94e05a830b85 100644
--- a/core/java/android/view/inputmethod/SurroundingText.java
+++ b/core/java/android/view/inputmethod/SurroundingText.java
@@ -90,6 +90,10 @@ public final class SurroundingText implements Parcelable {
/**
* Returns the text offset of the start of the selection in the surrounding text.
+ *
+ * <p>A selection is the current range of the text that is selected by the user, or the current
+ * position of the cursor. A cursor is a selection where the start and end are at the same
+ * offset.<p>
*/
@IntRange(from = 0)
public int getSelectionStart() {
@@ -98,6 +102,10 @@ public final class SurroundingText implements Parcelable {
/**
* Returns the text offset of the end of the selection in the surrounding text.
+ *
+ * <p>A selection is the current range of the text that is selected by the user, or the current
+ * position of the cursor. A cursor is a selection where the start and end are at the same
+ * offset.<p>
*/
@IntRange(from = 0)
public int getSelectionEnd() {
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index f62a28ec0d07..023d9ff28f41 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -154,6 +154,7 @@ public abstract class CookieManager {
* HTTP request header
* @hide Used by Browser and by WebViewProvider implementations.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract String getCookie(String url, boolean privateBrowsing);
@@ -230,6 +231,7 @@ public abstract class CookieManager {
* @param privateBrowsing whether to use the private browsing cookie jar
* @hide Used by Browser and WebViewProvider implementations.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract boolean hasCookies(boolean privateBrowsing);
@@ -264,6 +266,7 @@ public abstract class CookieManager {
*
* @hide Only for use by WebViewProvider implementations
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
protected abstract boolean allowFileSchemeCookiesImpl();
@@ -299,6 +302,7 @@ public abstract class CookieManager {
*
* @hide Only for use by WebViewProvider implementations
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
protected abstract void setAcceptFileSchemeCookiesImpl(boolean accept);
}
diff --git a/core/java/android/webkit/WebHistoryItem.java b/core/java/android/webkit/WebHistoryItem.java
index b9e704285f84..2cb37b440128 100644
--- a/core/java/android/webkit/WebHistoryItem.java
+++ b/core/java/android/webkit/WebHistoryItem.java
@@ -35,6 +35,7 @@ public abstract class WebHistoryItem implements Cloneable {
* @deprecated This method is now obsolete.
* @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@Deprecated
public abstract int getId();
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
index 08956e0f1b78..b70565816037 100644
--- a/core/java/android/webkit/WebIconDatabase.java
+++ b/core/java/android/webkit/WebIconDatabase.java
@@ -75,6 +75,7 @@ public abstract class WebIconDatabase {
/** {@hide}
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract void bulkRequestIconForPageUrl(ContentResolver cr, String where,
IconListener listener);
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 91b9390745ef..9b753f1b2d44 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -268,6 +268,7 @@ public abstract class WebSettings {
* @deprecated This method is now obsolete.
* @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@Deprecated
public abstract void setNavDump(boolean enabled);
@@ -280,6 +281,7 @@ public abstract class WebSettings {
* @deprecated This method is now obsolete.
* @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@Deprecated
public abstract boolean getNavDump();
@@ -457,6 +459,7 @@ public abstract class WebSettings {
* @deprecated This method is now obsolete.
* @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@Deprecated
public abstract void setUseWebViewBackgroundForOverscrollBackground(boolean view);
@@ -469,6 +472,7 @@ public abstract class WebSettings {
* @deprecated This method is now obsolete.
* @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@Deprecated
public abstract boolean getUseWebViewBackgroundForOverscrollBackground();
@@ -534,6 +538,7 @@ public abstract class WebSettings {
* Developers should access this via {@link CookieManager#setShouldAcceptThirdPartyCookies}.
* @hide Internal API.
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract void setAcceptThirdPartyCookies(boolean accept);
@@ -542,6 +547,7 @@ public abstract class WebSettings {
* Developers should access this via {@link CookieManager#getShouldAcceptThirdPartyCookies}.
* @hide Internal API
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract boolean getAcceptThirdPartyCookies();
@@ -669,6 +675,7 @@ public abstract class WebSettings {
* @deprecated Please use {@link #setUserAgentString} instead.
* @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@Deprecated
public abstract void setUserAgent(int ua);
@@ -687,6 +694,7 @@ public abstract class WebSettings {
* @deprecated Please use {@link #getUserAgentString} instead.
* @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@Deprecated
public abstract int getUserAgent();
@@ -1050,6 +1058,7 @@ public abstract class WebSettings {
* {@link #setPluginState}
* @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@Deprecated
public abstract void setPluginsEnabled(boolean flag);
@@ -1259,6 +1268,7 @@ public abstract class WebSettings {
* @deprecated This method has been replaced by {@link #getPluginState}
* @hide Since API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@Deprecated
public abstract boolean getPluginsEnabled();
@@ -1445,6 +1455,7 @@ public abstract class WebSettings {
* WebView.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract void setVideoOverlayForEmbeddedEncryptedVideoEnabled(boolean flag);
@@ -1455,6 +1466,7 @@ public abstract class WebSettings {
* @see #setVideoOverlayForEmbeddedEncryptedVideoEnabled
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
public abstract boolean getVideoOverlayForEmbeddedEncryptedVideoEnabled();
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 88c0809613ee..e740cc2b1f7a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -5348,6 +5348,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*
* @param down true if the scroll is going down, false if it is going up
*/
+ @SuppressWarnings("HiddenAbstractMethod")
abstract void fillGap(boolean down);
void hideSelector() {
@@ -5385,6 +5386,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* @param y Where the user touched
* @return The position of the first (or only) item in the row containing y
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
abstract int findMotionRow(int y);
@@ -5432,6 +5434,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*
* @param position the position of the new selection
*/
+ @SuppressWarnings("HiddenAbstractMethod")
abstract void setSelectionInt(int position);
/**
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index daf6914ff030..76e97ad7a0f6 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -310,6 +310,7 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
}
}
+ @SuppressWarnings("HiddenAbstractMethod")
abstract void layout(int delta, boolean animate);
@Override
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 4099c8aa6710..da14f2cfbd5a 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -16,7 +16,7 @@
package android.widget;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_DRAG_AND_DROP;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_DRAG_AND_DROP;
import android.R;
import android.animation.ValueAnimator;
@@ -98,7 +98,7 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
-import android.view.OnReceiveContentCallback;
+import android.view.OnReceiveContentListener;
import android.view.SubMenu;
import android.view.View;
import android.view.View.DragShadowBuilder;
@@ -207,8 +207,8 @@ public class Editor {
}
// Default content insertion handler.
- private final TextViewOnReceiveContentCallback mDefaultOnReceiveContentCallback =
- new TextViewOnReceiveContentCallback();
+ private final TextViewOnReceiveContentListener mDefaultOnReceiveContentListener =
+ new TextViewOnReceiveContentListener();
// Each Editor manages its own undo stack.
private final UndoManager mUndoManager = new UndoManager();
@@ -589,8 +589,8 @@ public class Editor {
}
@VisibleForTesting
- public @NonNull TextViewOnReceiveContentCallback getDefaultOnReceiveContentCallback() {
- return mDefaultOnReceiveContentCallback;
+ public @NonNull TextViewOnReceiveContentListener getDefaultOnReceiveContentListener() {
+ return mDefaultOnReceiveContentListener;
}
/**
@@ -719,7 +719,7 @@ public class Editor {
hideCursorAndSpanControllers();
stopTextActionModeWithPreservingSelection();
- mDefaultOnReceiveContentCallback.clearInputConnectionInfo();
+ mDefaultOnReceiveContentListener.clearInputConnectionInfo();
}
private void discardTextDisplayLists() {
@@ -2869,8 +2869,8 @@ public class Editor {
final int originalLength = mTextView.getText().length();
Selection.setSelection((Spannable) mTextView.getText(), offset);
final ClipData clip = event.getClipData();
- final OnReceiveContentCallback.Payload payload =
- new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_DRAG_AND_DROP)
+ final OnReceiveContentListener.Payload payload =
+ new OnReceiveContentListener.Payload.Builder(clip, SOURCE_DRAG_AND_DROP)
.build();
mTextView.onReceiveContent(payload);
if (dragDropIntoItself) {
@@ -4116,6 +4116,8 @@ public class Editor {
private final boolean mHasSelection;
private final int mHandleHeight;
private final Map<MenuItem, OnClickListener> mAssistClickHandlers = new HashMap<>();
+ @Nullable
+ private TextClassification mPrevTextClassification;
TextActionModeCallback(@TextActionMode int mode) {
mHasSelection = mode == TextActionMode.SELECTION
@@ -4266,15 +4268,19 @@ public class Editor {
}
private void updateAssistMenuItems(Menu menu) {
- clearAssistMenuItems(menu);
- if (!shouldEnableAssistMenuItems()) {
- return;
- }
final TextClassification textClassification =
getSelectionActionModeHelper().getTextClassification();
+ if (mPrevTextClassification == textClassification) {
+ // Already handled.
+ return;
+ }
+ clearAssistMenuItems(menu);
if (textClassification == null) {
return;
}
+ if (!shouldEnableAssistMenuItems()) {
+ return;
+ }
if (!textClassification.getActions().isEmpty()) {
// Primary assist action (Always shown).
final MenuItem item = addAssistMenuItem(menu,
@@ -4301,6 +4307,7 @@ public class Editor {
MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START + i - 1,
MenuItem.SHOW_AS_ACTION_NEVER);
}
+ mPrevTextClassification = textClassification;
}
private MenuItem addAssistMenuItem(Menu menu, RemoteAction action, int itemId, int order,
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 92e9a96e4897..a5be202ec770 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -462,7 +462,7 @@ public class FrameLayout extends ViewGroup {
/**
* Creates a new set of layout parameters with the specified width, height
- * and weight.
+ * and gravity.
*
* @param width the width, either {@link #MATCH_PARENT},
* {@link #WRAP_CONTENT} or a fixed size in pixels
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 32c68bdd0491..e74ce53306c1 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -296,12 +296,12 @@ public final class SelectionActionModeHelper {
} else {
mTextClassification = null;
}
+ final SelectionModifierCursorController controller = mEditor.getSelectionController();
+ if (controller != null
+ && (mTextView.isTextSelectable() || mTextView.isTextEditable())) {
+ controller.show();
+ }
if (mEditor.startActionModeInternal(actionMode)) {
- final SelectionModifierCursorController controller = mEditor.getSelectionController();
- if (controller != null
- && (mTextView.isTextSelectable() || mTextView.isTextEditable())) {
- controller.show();
- }
if (result != null) {
switch (actionMode) {
case Editor.TextActionMode.SELECTION:
diff --git a/core/java/android/widget/SmartSelectSprite.java b/core/java/android/widget/SmartSelectSprite.java
index dc472e1bbd82..baf92e5dc3e8 100644
--- a/core/java/android/widget/SmartSelectSprite.java
+++ b/core/java/android/widget/SmartSelectSprite.java
@@ -50,11 +50,9 @@ import java.util.Objects;
*/
final class SmartSelectSprite {
- private static final int EXPAND_DURATION = 300;
- private static final int CORNER_DURATION = 50;
+ private static final int EXPAND_DURATION = 200;
private final Interpolator mExpandInterpolator;
- private final Interpolator mCornerInterpolator;
private Animator mActiveAnimator = null;
private final Runnable mInvalidator;
@@ -337,9 +335,6 @@ final class SmartSelectSprite {
mExpandInterpolator = AnimationUtils.loadInterpolator(
context,
android.R.interpolator.fast_out_slow_in);
- mCornerInterpolator = AnimationUtils.loadInterpolator(
- context,
- android.R.interpolator.fast_out_linear_in);
mFillColor = highlightColor;
mInvalidator = Objects.requireNonNull(invalidator);
}
@@ -372,7 +367,6 @@ final class SmartSelectSprite {
final int rectangleCount = destinationRectangles.size();
final List<RoundedRectangleShape> shapes = new ArrayList<>(rectangleCount);
- final List<Animator> cornerAnimators = new ArrayList<>(rectangleCount);
RectangleWithTextSelectionLayout centerRectangle = null;
@@ -405,7 +399,6 @@ final class SmartSelectSprite {
expansionDirections[index],
rectangleWithTextSelectionLayout.getTextSelectionLayout()
== Layout.TEXT_SELECTION_LAYOUT_RIGHT_TO_LEFT);
- cornerAnimators.add(createCornerAnimator(shape, updateListener));
shapes.add(shape);
}
@@ -420,7 +413,7 @@ final class SmartSelectSprite {
mExistingDrawable = shapeDrawable;
mActiveAnimator = createAnimator(rectangleList, startingOffset, startingOffset,
- cornerAnimators, updateListener, onAnimationEnd);
+ updateListener, onAnimationEnd);
mActiveAnimator.start();
}
@@ -433,7 +426,6 @@ final class SmartSelectSprite {
final RectangleList rectangleList,
final float startingOffsetLeft,
final float startingOffsetRight,
- final List<Animator> cornerAnimators,
final ValueAnimator.AnimatorUpdateListener updateListener,
final Runnable onAnimationEnd) {
final ObjectAnimator rightBoundaryAnimator = ObjectAnimator.ofFloat(
@@ -457,18 +449,12 @@ final class SmartSelectSprite {
rightBoundaryAnimator.setInterpolator(mExpandInterpolator);
leftBoundaryAnimator.setInterpolator(mExpandInterpolator);
- final AnimatorSet cornerAnimator = new AnimatorSet();
- cornerAnimator.playTogether(cornerAnimators);
-
final AnimatorSet boundaryAnimator = new AnimatorSet();
boundaryAnimator.playTogether(leftBoundaryAnimator, rightBoundaryAnimator);
- final AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.playSequentially(boundaryAnimator, cornerAnimator);
-
- setUpAnimatorListener(animatorSet, onAnimationEnd);
+ setUpAnimatorListener(boundaryAnimator, onAnimationEnd);
- return animatorSet;
+ return boundaryAnimator;
}
private void setUpAnimatorListener(final Animator animator, final Runnable onAnimationEnd) {
@@ -495,19 +481,6 @@ final class SmartSelectSprite {
});
}
- private ObjectAnimator createCornerAnimator(
- final RoundedRectangleShape shape,
- final ValueAnimator.AnimatorUpdateListener listener) {
- final ObjectAnimator animator = ObjectAnimator.ofFloat(
- shape,
- RoundedRectangleShape.PROPERTY_ROUND_RATIO,
- shape.getRoundRatio(), 0.0F);
- animator.setDuration(CORNER_DURATION);
- animator.addUpdateListener(listener);
- animator.setInterpolator(mCornerInterpolator);
- return animator;
- }
-
private static @RoundedRectangleShape.ExpansionDirection int[] generateDirections(
final RectangleWithTextSelectionLayout centerRectangle,
final List<RectangleWithTextSelectionLayout> rectangles) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3ac78bafdedc..9485753ce906 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,10 +17,10 @@
package android.widget;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.view.OnReceiveContentCallback.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_AUTOFILL;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_CLIPBOARD;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_PROCESS_TEXT;
+import static android.view.OnReceiveContentListener.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_CLIPBOARD;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_PROCESS_TEXT;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX;
@@ -154,7 +154,7 @@ import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
-import android.view.OnReceiveContentCallback;
+import android.view.OnReceiveContentListener.Payload;
import android.view.PointerIcon;
import android.view.View;
import android.view.ViewConfiguration;
@@ -2151,10 +2151,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (result != null) {
if (isTextEditable()) {
ClipData clip = ClipData.newPlainText("", result);
- OnReceiveContentCallback.Payload payload =
- new OnReceiveContentCallback.Payload.Builder(
- clip, SOURCE_PROCESS_TEXT)
- .build();
+ Payload payload = new Payload.Builder(clip, SOURCE_PROCESS_TEXT).build();
onReceiveContent(payload);
if (mEditor != null) {
mEditor.refreshTextActionMode();
@@ -11858,8 +11855,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
+ " cannot be autofilled into " + this);
return;
}
- final OnReceiveContentCallback.Payload payload =
- new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_AUTOFILL).build();
+ final Payload payload = new Payload.Builder(clip, SOURCE_AUTOFILL).build();
onReceiveContent(payload);
}
@@ -12926,8 +12922,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (clip == null) {
return;
}
- final OnReceiveContentCallback.Payload payload =
- new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_CLIPBOARD)
+ final Payload payload = new Payload.Builder(clip, SOURCE_CLIPBOARD)
.setFlags(withFormatting ? 0 : FLAG_CONVERT_TO_PLAIN_TEXT)
.build();
onReceiveContent(payload);
@@ -13717,7 +13712,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public void onInputConnectionOpenedInternal(@NonNull InputConnection ic,
@NonNull EditorInfo editorInfo, @Nullable Handler handler) {
if (mEditor != null) {
- mEditor.getDefaultOnReceiveContentCallback().setInputConnectionInfo(ic, editorInfo);
+ mEditor.getDefaultOnReceiveContentListener().setInputConnectionInfo(this, ic,
+ editorInfo);
}
}
@@ -13725,68 +13721,35 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void onInputConnectionClosedInternal() {
if (mEditor != null) {
- mEditor.getDefaultOnReceiveContentCallback().clearInputConnectionInfo();
+ mEditor.getDefaultOnReceiveContentListener().clearInputConnectionInfo();
}
}
/**
- * Sets the callback to handle insertion of content into this view.
+ * Receives the given content. Clients wishing to provide custom behavior should configure a
+ * listener via {@link #setOnReceiveContentListener}.
*
- * <p>This callback will be invoked for the following scenarios:
- * <ol>
- * <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the
- * insertion/selection menu)
- * <li>Content insertion from the keyboard (from {@link InputConnection#commitContent})
- * <li>Drag and drop (drop events from {@link #onDragEvent(DragEvent)})
- * <li>Autofill (from {@link #autofill(AutofillValue)})
- * <li>{@link Intent#ACTION_PROCESS_TEXT} replacement
- * </ol>
+ * <p>If a listener is set, invokes the listener. If the listener returns a non-null result,
+ * executes the default platform handling for the portion of the content returned by the
+ * listener.
*
- * <p>This callback is only invoked for content whose MIME type matches a type specified via
- * the {code mimeTypes} parameter. If the MIME type is not supported by the callback, the
- * default platform handling will be executed instead (no-op for the default {@link View}).
- *
- * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC
- * MIME types. As a result, you should always write your MIME types with lower case letters, or
- * use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to lower
- * case.</em>
- *
- * @param mimeTypes The type of content for which the callback should be invoked. This may use
- * wildcards such as "text/*", "image/*", etc. This must not be null or empty if a non-null
- * callback is passed in.
- * @param callback The callback to use. This can be null to reset to the default behavior.
- */
- @SuppressWarnings("rawtypes")
- @Override
- public void setOnReceiveContentCallback(
- @Nullable String[] mimeTypes,
- @Nullable OnReceiveContentCallback callback) {
- super.setOnReceiveContentCallback(mimeTypes, callback);
- }
-
- /**
- * Receives the given content. The default implementation invokes the callback set via
- * {@link #setOnReceiveContentCallback}. If no callback is set or if the callback does not
- * support the given content (based on the MIME type), executes the default platform handling
- * (e.g. coerces content to text if the source is
- * {@link OnReceiveContentCallback.Payload#SOURCE_CLIPBOARD} and this is an editable
- * {@link TextView}).
+ * <p>If no listener is set, executes the default platform behavior. For non-editable TextViews
+ * the default behavior is a no-op (returns the passed-in content without acting on it). For
+ * editable TextViews the default behavior coerces all content to text and inserts into the
+ * view.
*
* @param payload The content to insert and related metadata.
*
- * @return Returns true if the content was handled in some way, false otherwise. Actual
- * insertion may be processed asynchronously in the background and may or may not succeed even
- * if this method returns true. For example, an app may not end up inserting an item if it
- * exceeds the app's size limit for that type of content.
+ * @return The portion of the passed-in content that was not handled (may be all, some, or none
+ * of the passed-in content).
*/
@Override
- public boolean onReceiveContent(@NonNull OnReceiveContentCallback.Payload payload) {
- if (super.onReceiveContent(payload)) {
- return true;
- } else if (mEditor != null) {
- return mEditor.getDefaultOnReceiveContentCallback().onReceiveContent(this, payload);
+ public @Nullable Payload onReceiveContent(@NonNull Payload payload) {
+ Payload remaining = super.onReceiveContent(payload);
+ if (remaining != null && mEditor != null) {
+ return mEditor.getDefaultOnReceiveContentListener().onReceiveContent(this, remaining);
}
- return false;
+ return remaining;
}
private static void logCursor(String location, @Nullable String msgFormat, Object ... msgArgs) {
diff --git a/core/java/android/widget/TextViewOnReceiveContentCallback.java b/core/java/android/widget/TextViewOnReceiveContentListener.java
index 7ed70ec18a7b..7ef68ec7a4ee 100644
--- a/core/java/android/widget/TextViewOnReceiveContentCallback.java
+++ b/core/java/android/widget/TextViewOnReceiveContentListener.java
@@ -17,12 +17,10 @@
package android.widget;
import static android.content.ContentResolver.SCHEME_CONTENT;
-import static android.view.OnReceiveContentCallback.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_AUTOFILL;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_DRAG_AND_DROP;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_INPUT_METHOD;
-
-import static java.util.Collections.singleton;
+import static android.view.OnReceiveContentListener.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_DRAG_AND_DROP;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_INPUT_METHOD;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -39,11 +37,10 @@ import android.text.Editable;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
-import android.util.ArraySet;
import android.util.Log;
-import android.view.OnReceiveContentCallback;
-import android.view.OnReceiveContentCallback.Payload.Flags;
-import android.view.OnReceiveContentCallback.Payload.Source;
+import android.view.OnReceiveContentListener;
+import android.view.OnReceiveContentListener.Payload.Flags;
+import android.view.OnReceiveContentListener.Payload.Source;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
@@ -54,42 +51,38 @@ import com.android.internal.annotations.VisibleForTesting;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Set;
/**
- * Default implementation of {@link android.view.OnReceiveContentCallback} for editable
+ * Default implementation of {@link OnReceiveContentListener} for editable
* {@link TextView} components. This class handles insertion of text (plain text, styled text, HTML,
- * etc) but not images or other content. This class can be used as a base class for an
- * implementation of {@link android.view.OnReceiveContentCallback} for a {@link TextView}, to
- * provide consistent behavior for insertion of text.
+ * etc) but not images or other content.
+ *
+ * @hide
*/
-public class TextViewOnReceiveContentCallback implements OnReceiveContentCallback<TextView> {
+@VisibleForTesting
+public final class TextViewOnReceiveContentListener implements OnReceiveContentListener {
private static final String LOG_TAG = "OnReceiveContent";
- private static final String MIME_TYPE_ALL_TEXT = "text/*";
- private static final Set<String> MIME_TYPES_ALL_TEXT = singleton(MIME_TYPE_ALL_TEXT);
-
@Nullable private InputConnectionInfo mInputConnectionInfo;
- @Nullable private ArraySet<String> mCachedSupportedMimeTypes;
@Override
- public boolean onReceiveContent(@NonNull TextView view, @NonNull Payload payload) {
+ public @Nullable Payload onReceiveContent(@NonNull View view, @NonNull Payload payload) {
if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
Log.d(LOG_TAG, "onReceive: " + payload);
}
- ClipData clip = payload.getClip();
- @Source int source = payload.getSource();
- @Flags int flags = payload.getFlags();
+ final @Source int source = payload.getSource();
if (source == SOURCE_INPUT_METHOD) {
// InputConnection.commitContent() should only be used for non-text input which is not
// supported by the default implementation.
- return false;
+ return payload;
}
if (source == SOURCE_AUTOFILL) {
- return onReceiveForAutofill(view, clip, flags);
+ onReceiveForAutofill((TextView) view, payload);
+ return null;
}
if (source == SOURCE_DRAG_AND_DROP) {
- return onReceiveForDragAndDrop(view, clip, flags);
+ onReceiveForDragAndDrop((TextView) view, payload);
+ return null;
}
// The code here follows the original paste logic from TextView:
@@ -97,7 +90,9 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
// In particular, multiple items within the given ClipData will trigger separate calls to
// replace/insert. This is to preserve the original behavior with respect to TextWatcher
// notifications fired from SpannableStringBuilder when replace/insert is called.
- final Editable editable = (Editable) view.getText();
+ final ClipData clip = payload.getClip();
+ final @Flags int flags = payload.getFlags();
+ final Editable editable = (Editable) ((TextView) view).getText();
final Context context = view.getContext();
boolean didFirst = false;
for (int i = 0; i < clip.getItemCount(); i++) {
@@ -118,7 +113,7 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
}
}
}
- return didFirst;
+ return null;
}
private static void replaceSelection(@NonNull Editable editable,
@@ -131,37 +126,33 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
editable.replace(start, end, replacement);
}
- private boolean onReceiveForAutofill(@NonNull TextView view, @NonNull ClipData clip,
- @Flags int flags) {
+ private void onReceiveForAutofill(@NonNull TextView view, @NonNull Payload payload) {
+ ClipData clip = payload.getClip();
if (isUsageOfImeCommitContentEnabled(view)) {
clip = handleNonTextViaImeCommitContent(clip);
if (clip == null) {
if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
Log.v(LOG_TAG, "onReceive: Handled via IME");
}
- return true;
+ return;
}
}
- final CharSequence text = coerceToText(clip, view.getContext(), flags);
+ final CharSequence text = coerceToText(clip, view.getContext(), payload.getFlags());
// First autofill it...
view.setText(text);
// ...then move cursor to the end.
final Editable editable = (Editable) view.getText();
Selection.setSelection(editable, editable.length());
- return true;
}
- private static boolean onReceiveForDragAndDrop(@NonNull TextView textView,
- @NonNull ClipData clip, @Flags int flags) {
- final CharSequence text = coerceToText(clip, textView.getContext(), flags);
- if (text.length() == 0) {
- return false;
- }
- replaceSelection((Editable) textView.getText(), text);
- return true;
+ private static void onReceiveForDragAndDrop(@NonNull TextView view, @NonNull Payload payload) {
+ final CharSequence text = coerceToText(payload.getClip(), view.getContext(),
+ payload.getFlags());
+ replaceSelection((Editable) view.getText(), text);
}
- private static CharSequence coerceToText(ClipData clip, Context context, @Flags int flags) {
+ private static @NonNull CharSequence coerceToText(@NonNull ClipData clip,
+ @NonNull Context context, @Flags int flags) {
SpannableStringBuilder ssb = new SpannableStringBuilder();
for (int i = 0; i < clip.getItemCount(); i++) {
CharSequence itemText;
@@ -183,17 +174,17 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
* augmented autofill framework (see
* <a href="/guide/topics/text/autofill-services">autofill services</a>). In order for an app to
* be able to handle these suggestions, it must normally implement the
- * {@link android.view.OnReceiveContentCallback} API. To make the adoption of this smoother for
+ * {@link android.view.OnReceiveContentListener} API. To make the adoption of this smoother for
* apps that have previously implemented the
* {@link android.view.inputmethod.InputConnection#commitContent(InputContentInfo, int, Bundle)}
- * API, we reuse that API as a fallback if {@link android.view.OnReceiveContentCallback} is not
+ * API, we reuse that API as a fallback if {@link android.view.OnReceiveContentListener} is not
* yet implemented by the app. This fallback is only enabled on Android S. This change ID
* disables the fallback, such that apps targeting Android T and above must implement the
- * {@link android.view.OnReceiveContentCallback} API in order to accept non-text suggestions.
+ * {@link android.view.OnReceiveContentListener} API in order to accept non-text suggestions.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S) // Enabled on Android T and higher
- private static final long AUTOFILL_NON_TEXT_REQUIRES_ON_RECEIVE_CONTENT_CALLBACK = 163400105L;
+ private static final long AUTOFILL_NON_TEXT_REQUIRES_ON_RECEIVE_CONTENT_LISTENER = 163400105L;
/**
* Returns true if we can use the IME {@link InputConnection#commitContent} API in order handle
@@ -206,7 +197,7 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
}
return false;
}
- if (Compatibility.isChangeEnabled(AUTOFILL_NON_TEXT_REQUIRES_ON_RECEIVE_CONTENT_CALLBACK)) {
+ if (Compatibility.isChangeEnabled(AUTOFILL_NON_TEXT_REQUIRES_ON_RECEIVE_CONTENT_LISTENER)) {
if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
Log.v(LOG_TAG, "Fallback to commitContent disabled (target SDK is above S)");
}
@@ -238,11 +229,16 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
* Invoked by the platform when an {@link InputConnection} is successfully created for the view
* that owns this callback instance.
*/
- void setInputConnectionInfo(@NonNull InputConnection ic, @NonNull EditorInfo editorInfo) {
+ void setInputConnectionInfo(@NonNull TextView view, @NonNull InputConnection ic,
+ @NonNull EditorInfo editorInfo) {
if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
Log.v(LOG_TAG, "setInputConnectionInfo: "
+ Arrays.toString(editorInfo.contentMimeTypes));
}
+ if (!isUsageOfImeCommitContentEnabled(view)) {
+ mInputConnectionInfo = null;
+ return;
+ }
String[] contentMimeTypes = editorInfo.contentMimeTypes;
if (contentMimeTypes == null || contentMimeTypes.length == 0) {
mInputConnectionInfo = null;
@@ -262,82 +258,26 @@ public class TextViewOnReceiveContentCallback implements OnReceiveContentCallbac
mInputConnectionInfo = null;
}
- // TODO(b/168253885): Use this to populate the assist structure for Autofill
-
/** @hide */
@VisibleForTesting
- public Set<String> getMimeTypes(TextView view) {
+ @Nullable
+ public String[] getEditorInfoMimeTypes(@NonNull TextView view) {
if (!isUsageOfImeCommitContentEnabled(view)) {
- return MIME_TYPES_ALL_TEXT;
+ return null;
}
- return getSupportedMimeTypesAugmentedWithImeCommitContentMimeTypes();
- }
-
- private Set<String> getSupportedMimeTypesAugmentedWithImeCommitContentMimeTypes() {
- InputConnectionInfo icInfo = mInputConnectionInfo;
+ final InputConnectionInfo icInfo = mInputConnectionInfo;
if (icInfo == null) {
if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
- Log.v(LOG_TAG, "getSupportedMimeTypes: No usable EditorInfo/InputConnection");
+ Log.v(LOG_TAG, "getEditorInfoMimeTypes: No usable EditorInfo");
}
- return MIME_TYPES_ALL_TEXT;
+ return null;
}
- String[] editorInfoContentMimeTypes = icInfo.mEditorInfoContentMimeTypes;
+ final String[] editorInfoContentMimeTypes = icInfo.mEditorInfoContentMimeTypes;
if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
- Log.v(LOG_TAG, "getSupportedMimeTypes: Augmenting with EditorInfo.contentMimeTypes: "
+ Log.v(LOG_TAG, "getEditorInfoMimeTypes: "
+ Arrays.toString(editorInfoContentMimeTypes));
}
- ArraySet<String> supportedMimeTypes = mCachedSupportedMimeTypes;
- if (canReuse(supportedMimeTypes, editorInfoContentMimeTypes)) {
- return supportedMimeTypes;
- }
- supportedMimeTypes = new ArraySet<>(editorInfoContentMimeTypes);
- supportedMimeTypes.add(MIME_TYPE_ALL_TEXT);
- mCachedSupportedMimeTypes = supportedMimeTypes;
- return supportedMimeTypes;
- }
-
- /**
- * We want to avoid creating a new set on every invocation of
- * {@link #getSupportedMimeTypesAugmentedWithImeCommitContentMimeTypes()}.
- * This method will check if the cached set of MIME types matches the data in the given array
- * from {@link EditorInfo} or if a new set should be created. The custom logic is needed for
- * comparing the data because the set contains the additional "text/*" MIME type.
- *
- * @param cachedMimeTypes Previously cached set of MIME types.
- * @param newEditorInfoMimeTypes MIME types from {@link EditorInfo}.
- *
- * @return Returns true if the data in the given cached set matches the data in the array.
- *
- * @hide
- */
- @VisibleForTesting
- public static boolean canReuse(@Nullable ArraySet<String> cachedMimeTypes,
- @NonNull String[] newEditorInfoMimeTypes) {
- if (cachedMimeTypes == null) {
- return false;
- }
- if (newEditorInfoMimeTypes.length != cachedMimeTypes.size()
- && newEditorInfoMimeTypes.length != (cachedMimeTypes.size() - 1)) {
- return false;
- }
- final boolean ignoreAllTextMimeType =
- newEditorInfoMimeTypes.length == (cachedMimeTypes.size() - 1);
- for (String mimeType : cachedMimeTypes) {
- if (ignoreAllTextMimeType && mimeType.equals(MIME_TYPE_ALL_TEXT)) {
- continue;
- }
- boolean present = false;
- for (String editorInfoContentMimeType : newEditorInfoMimeTypes) {
- if (editorInfoContentMimeType.equals(mimeType)) {
- present = true;
- break;
- }
- }
- if (!present) {
- return false;
- }
- }
- return true;
+ return editorInfoContentMimeTypes;
}
/**
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java
index 6ec093e045fa..6cc3cd398703 100644
--- a/core/java/android/window/DisplayAreaOrganizer.java
+++ b/core/java/android/window/DisplayAreaOrganizer.java
@@ -78,6 +78,12 @@ public class DisplayAreaOrganizer extends WindowOrganizer {
public static final int FEATURE_FULLSCREEN_MAGNIFICATION = FEATURE_SYSTEM_FIRST + 5;
/**
+ * Display area for hiding display cutout feature
+ * @hide
+ */
+ public static final int FEATURE_HIDE_DISPLAY_CUTOUT = FEATURE_SYSTEM_FIRST + 6;
+
+ /**
* The last boundary of display area for system features
*/
public static final int FEATURE_SYSTEM_LAST = 10_000;
@@ -88,9 +94,11 @@ public class DisplayAreaOrganizer extends WindowOrganizer {
public static final int FEATURE_VENDOR_FIRST = FEATURE_SYSTEM_LAST + 1;
/**
- * Registers a DisplayAreaOrganizer to manage display areas for a given feature.
+ * Registers a DisplayAreaOrganizer to manage display areas for a given feature. A feature can
+ * not be registered by multiple organizers at the same time.
*
* @return a list of display areas that should be managed by the organizer.
+ * @throws IllegalStateException if the feature has already been registered.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
@CallSuper
diff --git a/core/java/android/window/IDisplayAreaOrganizerController.aidl b/core/java/android/window/IDisplayAreaOrganizerController.aidl
index 8943847073c7..edabcf8ad0de 100644
--- a/core/java/android/window/IDisplayAreaOrganizerController.aidl
+++ b/core/java/android/window/IDisplayAreaOrganizerController.aidl
@@ -24,9 +24,11 @@ import android.window.IDisplayAreaOrganizer;
interface IDisplayAreaOrganizerController {
/**
- * Registers a DisplayAreaOrganizer to manage display areas for a given feature.
+ * Registers a DisplayAreaOrganizer to manage display areas for a given feature. A feature can
+ * not be registered by multiple organizers at the same time.
*
* @return a list of display areas that should be managed by the organizer.
+ * @throws IllegalStateException if the feature has already been registered.
*/
ParceledListSlice<DisplayAreaAppearedInfo> registerOrganizer(in IDisplayAreaOrganizer organizer,
int displayAreaFeature);
diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl
index abca136c347e..b503184f4c51 100644
--- a/core/java/android/window/ITaskOrganizer.aidl
+++ b/core/java/android/window/ITaskOrganizer.aidl
@@ -26,6 +26,21 @@ import android.window.WindowContainerToken;
*/
oneway interface ITaskOrganizer {
/**
+ * Called when a Task is starting and the system would like to show a UI to indicate that an
+ * application is starting. The client is responsible to add/remove the starting window if it
+ * has create a starting window for the Task.
+ *
+ * @param taskInfo The information about the Task that's available
+ * @param appToken Token of the application being started.
+ */
+ void addStartingWindow(in ActivityManager.RunningTaskInfo taskInfo, IBinder appToken);
+
+ /**
+ * Called when the Task want to remove the starting window.
+ */
+ void removeStartingWindow(in ActivityManager.RunningTaskInfo taskInfo);
+
+ /**
* A callback when the Task is available for the registered organizer. The client is responsible
* for releasing the SurfaceControl in the callback. For non-root tasks, the leash may initially
* be hidden so it is up to the organizer to show this task.
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 4e209206f233..eda168dd8553 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -85,6 +85,25 @@ public class TaskOrganizer extends WindowOrganizer {
}
/**
+ * Called when a Task is starting and the system would like to show a UI to indicate that an
+ * application is starting. The client is responsible to add/remove the starting window if it
+ * has create a starting window for the Task.
+ *
+ * @param taskInfo The information about the Task that's available
+ * @param appToken Token of the application being started.
+ * context to for resources
+ */
+ @BinderThread
+ public void addStartingWindow(@NonNull ActivityManager.RunningTaskInfo taskInfo,
+ @NonNull IBinder appToken) {}
+
+ /**
+ * Called when the Task want to remove the starting window.
+ */
+ @BinderThread
+ public void removeStartingWindow(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
+
+ /**
* Called when a task with the registered windowing mode can be controlled by this task
* organizer. For non-root tasks, the leash may initially be hidden so it is up to the organizer
* to show this task.
@@ -192,6 +211,15 @@ public class TaskOrganizer extends WindowOrganizer {
}
private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
+ @Override
+ public void addStartingWindow(ActivityManager.RunningTaskInfo taskInfo, IBinder appToken) {
+ TaskOrganizer.this.addStartingWindow(taskInfo, appToken);
+ }
+
+ @Override
+ public void removeStartingWindow(ActivityManager.RunningTaskInfo taskInfo) {
+ TaskOrganizer.this.removeStartingWindow(taskInfo);
+ }
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
diff --git a/core/java/com/android/internal/BrightnessSynchronizer.java b/core/java/com/android/internal/BrightnessSynchronizer.java
index 15463cb34157..9049ca56bc53 100644
--- a/core/java/com/android/internal/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/BrightnessSynchronizer.java
@@ -73,18 +73,26 @@ public class BrightnessSynchronizer {
}
};
+ private float mPreferredSettingValue;
+
public BrightnessSynchronizer(Context context) {
- final BrightnessSyncObserver mBrightnessSyncObserver;
mContext = context;
- mBrightnessSyncObserver = new BrightnessSyncObserver(mHandler);
- mBrightnessSyncObserver.startObserving();
+ }
+
+ /**
+ * Starts brightnessSyncObserver to ensure that the float and int brightness values stay
+ * in sync.
+ * This also ensures that values are synchronized at system start up too.
+ * So we force an update to the int value, since float is the source of truth. Fallback to int
+ * value, if float is invalid. If both are invalid, use default float value from config.
+ */
+ public void startSynchronizing() {
+ final BrightnessSyncObserver brightnessSyncObserver;
+ brightnessSyncObserver = new BrightnessSyncObserver(mHandler);
+ brightnessSyncObserver.startObserving();
- // It is possible for the system to start up with the int and float values not
- // synchronized. So we force an update to the int value, since float is the source
- // of truth. Fallback to int value, if float is invalid. If both are invalid, use default
- // float value from config.
- final float currentFloatBrightness = getScreenBrightnessFloat(context);
- final int currentIntBrightness = getScreenBrightnessInt(context);
+ final float currentFloatBrightness = getScreenBrightnessFloat(mContext);
+ final int currentIntBrightness = getScreenBrightnessInt(mContext);
if (!Float.isNaN(currentFloatBrightness)) {
updateBrightnessIntFromFloat(currentFloatBrightness);
@@ -156,8 +164,6 @@ public class BrightnessSynchronizer {
UserHandle.USER_CURRENT);
}
- private float mPreferredSettingValue;
-
/**
* Updates the float setting based on a passed in int value. This is called whenever the int
* setting changes. mWriteHistory keeps a record of the values that been written to the settings
diff --git a/core/java/com/android/internal/app/ChooserFlags.java b/core/java/com/android/internal/app/ChooserFlags.java
index 1a93f1bc947f..3e26679e28a4 100644
--- a/core/java/com/android/internal/app/ChooserFlags.java
+++ b/core/java/com/android/internal/app/ChooserFlags.java
@@ -33,7 +33,7 @@ public class ChooserFlags {
*/
public static final boolean USE_SERVICE_TARGETS_FOR_DIRECT_TARGETS =
DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.SHARE_USE_SERVICE_TARGETS, false);
+ SystemUiDeviceConfigFlags.SHARE_USE_SERVICE_TARGETS, true);
/**
* Whether to use {@link AppPredictionManager} to query for direct share targets (as opposed to
diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl
index f8aac42b8018..3874de395bea 100644
--- a/core/java/com/android/internal/app/ISoundTriggerService.aidl
+++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl
@@ -38,8 +38,12 @@ interface ISoundTriggerService {
*
* It is good practice to clear the binder calling identity prior to calling this, in case the
* caller is ever in the same process as the callee.
+ *
+ * The binder object being passed is used by the server to keep track of client death, in order
+ * to clean-up whenever that happens.
*/
- ISoundTriggerSession attachAsOriginator(in Identity originatorIdentity);
+ ISoundTriggerSession attachAsOriginator(in Identity originatorIdentity,
+ IBinder client);
/**
* Creates a new session.
@@ -54,7 +58,11 @@ interface ISoundTriggerService {
*
* It is good practice to clear the binder calling identity prior to calling this, in case the
* caller is ever in the same process as the callee.
+ *
+ * The binder object being passed is used by the server to keep track of client death, in order
+ * to clean-up whenever that happens.
*/
ISoundTriggerSession attachAsMiddleman(in Identity middlemanIdentity,
- in Identity originatorIdentity);
+ in Identity originatorIdentity,
+ IBinder client);
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 81c61aa0f250..db2551444e42 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -216,7 +216,11 @@ interface IVoiceInteractionManagerService {
* Caller must provide an identity, used for permission tracking purposes.
* The uid/pid elements of the identity will be ignored by the server and replaced with the ones
* provided by binder.
+ *
+ * The client argument is any binder owned by the client, used for tracking is death and
+ * cleaning up in this event.
*/
IVoiceInteractionSoundTriggerSession createSoundTriggerSessionAsOriginator(
- in Identity originatorIdentity);
+ in Identity originatorIdentity,
+ IBinder client);
}
diff --git a/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java b/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java
index 6ea9e665c009..9eab6211dd43 100644
--- a/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java
+++ b/core/java/com/android/internal/graphics/drawable/BackgroundBlurDrawable.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
@@ -75,7 +76,8 @@ public final class BackgroundBlurDrawable extends Drawable {
private BackgroundBlurDrawable(Aggregator aggregator) {
mAggregator = aggregator;
- mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+ mPaint.setColor(Color.TRANSPARENT);
mRenderNode = new RenderNode("BackgroundBlurDrawable");
mRenderNode.addPositionUpdateListener(mPositionUpdateListener);
}
@@ -85,11 +87,17 @@ public final class BackgroundBlurDrawable extends Drawable {
if (mRectPath.isEmpty() || !isVisible() || getAlpha() == 0) {
return;
}
+
canvas.drawPath(mRectPath, mPaint);
canvas.drawRenderNode(mRenderNode);
}
@Override
+ public void setTint(int tintColor) {
+ mPaint.setColor(tintColor);
+ }
+
+ @Override
public boolean setVisible(boolean visible, boolean restart) {
boolean changed = super.setVisible(visible, restart);
if (changed) {
diff --git a/core/java/com/android/internal/inputmethod/CancellationGroup.java b/core/java/com/android/internal/inputmethod/CancellationGroup.java
index a4a220880d46..aef9e3b9a0fc 100644
--- a/core/java/com/android/internal/inputmethod/CancellationGroup.java
+++ b/core/java/com/android/internal/inputmethod/CancellationGroup.java
@@ -24,11 +24,10 @@ import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
/**
- * A utility class, which works as both a factory class of completable objects and a cancellation
- * signal to cancel all the completable objects created by this object.
+ * A utility class, which works as both a factory class of a cancellation signal to cancel
+ * all the completable objects.
*/
public final class CancellationGroup {
private final Object mLock = new Object();
@@ -46,274 +45,8 @@ public final class CancellationGroup {
@GuardedBy("mLock")
private boolean mCanceled = false;
- /**
- * An inner class to consolidate completable object types supported by
- * {@link CancellationGroup}.
- */
- public static final class Completable {
-
- /**
- * Not intended to be instantiated.
- */
- private Completable() {
- }
-
- /**
- * Base class of all the completable types supported by {@link CancellationGroup}.
- */
- protected static class ValueBase {
- /**
- * {@link CountDownLatch} to be signaled to unblock {@link #await(int, TimeUnit)}.
- */
- private final CountDownLatch mLatch = new CountDownLatch(1);
-
- /**
- * {@link CancellationGroup} to which this completable object belongs.
- */
- @NonNull
- private final CancellationGroup mParentGroup;
-
- /**
- * Lock {@link Object} to guard complete operations within this class.
- */
- protected final Object mValueLock = new Object();
-
- /**
- * {@code true} after {@link #onComplete()} gets called.
- */
- @GuardedBy("mValueLock")
- protected boolean mHasValue = false;
-
- /**
- * Base constructor.
- *
- * @param parentGroup {@link CancellationGroup} to which this completable object
- * belongs.
- */
- protected ValueBase(@NonNull CancellationGroup parentGroup) {
- mParentGroup = parentGroup;
- }
-
- /**
- * @return {@link true} if {@link #onComplete()} gets called already.
- */
- @AnyThread
- public boolean hasValue() {
- synchronized (mValueLock) {
- return mHasValue;
- }
- }
-
- /**
- * Called by subclasses to signale {@link #mLatch}.
- */
- @AnyThread
- protected void onComplete() {
- mLatch.countDown();
- }
-
- /**
- * Blocks the calling thread until at least one of the following conditions is met.
- *
- * <p>
- * <ol>
- * <li>This object becomes ready to return the value.</li>
- * <li>{@link CancellationGroup#cancelAll()} gets called.</li>
- * <li>The given timeout period has passed.</li>
- * </ol>
- * </p>
- *
- * <p>The caller can distinguish the case 1 and case 2 by calling {@link #hasValue()}.
- * Note that the return value of {@link #hasValue()} can change from {@code false} to
- * {@code true} at any time, even after this methods finishes with returning
- * {@code true}.</p>
- *
- * @param timeout length of the timeout.
- * @param timeUnit unit of {@code timeout}.
- * @return {@code false} if and only if the given timeout period has passed. Otherwise
- * {@code true}.
- */
- @AnyThread
- public boolean await(int timeout, @NonNull TimeUnit timeUnit) {
- if (!mParentGroup.registerLatch(mLatch)) {
- // Already canceled when this method gets called.
- return false;
- }
- try {
- return mLatch.await(timeout, timeUnit);
- } catch (InterruptedException e) {
- return true;
- } finally {
- mParentGroup.unregisterLatch(mLatch);
- }
- }
- }
-
- /**
- * Completable object of integer primitive.
- */
- public static final class Int extends ValueBase {
- @GuardedBy("mValueLock")
- private int mValue = 0;
-
- private Int(@NonNull CancellationGroup factory) {
- super(factory);
- }
-
- /**
- * Notify when a value is set to this completable object.
- *
- * @param value value to be set.
- */
- @AnyThread
- void onComplete(int value) {
- synchronized (mValueLock) {
- if (mHasValue) {
- throw new UnsupportedOperationException(
- "onComplete() cannot be called multiple times");
- }
- mValue = value;
- mHasValue = true;
- }
- onComplete();
- }
-
- /**
- * @return value associated with this object.
- * @throws UnsupportedOperationException when called while {@link #hasValue()} returns
- * {@code false}.
- */
- @AnyThread
- public int getValue() {
- synchronized (mValueLock) {
- if (!mHasValue) {
- throw new UnsupportedOperationException(
- "getValue() is allowed only if hasValue() returns true");
- }
- return mValue;
- }
- }
- }
-
- /**
- * Base class of completable object types.
- *
- * @param <T> type associated with this completable object.
- */
- public static class Values<T> extends ValueBase {
- @GuardedBy("mValueLock")
- @Nullable
- private T mValue = null;
-
- protected Values(@NonNull CancellationGroup factory) {
- super(factory);
- }
-
- /**
- * Notify when a value is set to this completable value object.
- *
- * @param value value to be set.
- */
- @AnyThread
- void onComplete(@Nullable T value) {
- synchronized (mValueLock) {
- if (mHasValue) {
- throw new UnsupportedOperationException(
- "onComplete() cannot be called multiple times");
- }
- mValue = value;
- mHasValue = true;
- }
- onComplete();
- }
-
- /**
- * @return value associated with this object.
- * @throws UnsupportedOperationException when called while {@link #hasValue()} returns
- * {@code false}.
- */
- @AnyThread
- @Nullable
- public T getValue() {
- synchronized (mValueLock) {
- if (!mHasValue) {
- throw new UnsupportedOperationException(
- "getValue() is allowed only if hasValue() returns true");
- }
- return mValue;
- }
- }
- }
-
- /**
- * Completable object of {@link java.lang.CharSequence}.
- */
- public static final class CharSequence extends Values<java.lang.CharSequence> {
- private CharSequence(@NonNull CancellationGroup factory) {
- super(factory);
- }
- }
-
- /**
- * Completable object of {@link android.view.inputmethod.ExtractedText}.
- */
- public static final class ExtractedText
- extends Values<android.view.inputmethod.ExtractedText> {
- private ExtractedText(@NonNull CancellationGroup factory) {
- super(factory);
- }
- }
-
- /**
- * Completable object of {@link android.view.inputmethod.SurroundingText}.
- */
- public static final class SurroundingText
- extends Values<android.view.inputmethod.SurroundingText> {
- private SurroundingText(@NonNull CancellationGroup factory) {
- super(factory);
- }
- }
- }
-
- /**
- * @return an instance of {@link Completable.Int} that is associated with this
- * {@link CancellationGroup}.
- */
- @AnyThread
- public Completable.Int createCompletableInt() {
- return new Completable.Int(this);
- }
-
- /**
- * @return an instance of {@link Completable.CharSequence} that is associated with this
- * {@link CancellationGroup}.
- */
- @AnyThread
- public Completable.CharSequence createCompletableCharSequence() {
- return new Completable.CharSequence(this);
- }
-
- /**
- * @return an instance of {@link Completable.ExtractedText} that is associated with this
- * {@link CancellationGroup}.
- */
- @AnyThread
- public Completable.ExtractedText createCompletableExtractedText() {
- return new Completable.ExtractedText(this);
- }
-
- /**
- * @return an instance of {@link Completable.SurroundingText} that is associated with this
- * {@link CancellationGroup}.
- */
- @AnyThread
- public Completable.SurroundingText createCompletableSurroundingText() {
- return new Completable.SurroundingText(this);
- }
-
-
@AnyThread
- private boolean registerLatch(@NonNull CountDownLatch latch) {
+ boolean registerLatch(@NonNull CountDownLatch latch) {
synchronized (mLock) {
if (mCanceled) {
return false;
@@ -329,7 +62,7 @@ public final class CancellationGroup {
}
@AnyThread
- private void unregisterLatch(@NonNull CountDownLatch latch) {
+ void unregisterLatch(@NonNull CountDownLatch latch) {
synchronized (mLock) {
if (mLatchList != null) {
mLatchList.remove(latch);
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
new file mode 100644
index 000000000000..16473b98b813
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/Completable.java
@@ -0,0 +1,278 @@
+/*
+ * 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.inputmethod;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An class to consolidate completable object types supported by
+ * {@link CancellationGroup}.
+ */
+public final class Completable {
+
+ /**
+ * Not intended to be instantiated.
+ */
+ private Completable() {
+ }
+
+ /**
+ * Base class of all the completable types supported by {@link CancellationGroup}.
+ */
+ protected static class ValueBase {
+ /**
+ * {@link CountDownLatch} to be signaled to unblock
+ * {@link #await(int, TimeUnit, CancellationGroup)}.
+ */
+ private final CountDownLatch mLatch = new CountDownLatch(1);
+
+ /**
+ * Lock {@link Object} to guard complete operations within this class.
+ */
+ protected final Object mValueLock = new Object();
+
+ /**
+ * {@code true} after {@link #onComplete()} gets called.
+ */
+ @GuardedBy("mValueLock")
+ protected boolean mHasValue = false;
+
+ /**
+ * @return {@link true} if {@link #onComplete()} gets called already.
+ */
+ @AnyThread
+ public boolean hasValue() {
+ synchronized (mValueLock) {
+ return mHasValue;
+ }
+ }
+
+ /**
+ * Called by subclasses to signale {@link #mLatch}.
+ */
+ @AnyThread
+ protected void onComplete() {
+ mLatch.countDown();
+ }
+
+ /**
+ * Blocks the calling thread until at least one of the following conditions is met.
+ *
+ * <p>
+ * <ol>
+ * <li>This object becomes ready to return the value.</li>
+ * <li>{@link CancellationGroup#cancelAll()} gets called.</li>
+ * <li>The given timeout period has passed.</li>
+ * </ol>
+ * </p>
+ *
+ * <p>The caller can distinguish the case 1 and case 2 by calling {@link #hasValue()}.
+ * Note that the return value of {@link #hasValue()} can change from {@code false} to
+ * {@code true} at any time, even after this methods finishes with returning
+ * {@code true}.</p>
+ *
+ * @param timeout length of the timeout.
+ * @param timeUnit unit of {@code timeout}.
+ * @param cancellationGroup {@link CancellationGroup} to cancel completable objects.
+ * @return {@code false} if and only if the given timeout period has passed. Otherwise
+ * {@code true}.
+ */
+ @AnyThread
+ public boolean await(int timeout, @NonNull TimeUnit timeUnit,
+ @Nullable CancellationGroup cancellationGroup) {
+ if (cancellationGroup == null) {
+ return awaitInner(timeout, timeUnit);
+ }
+
+ if (!cancellationGroup.registerLatch(mLatch)) {
+ // Already canceled when this method gets called.
+ return false;
+ }
+ try {
+ return awaitInner(timeout, timeUnit);
+ } finally {
+ cancellationGroup.unregisterLatch(mLatch);
+ }
+ }
+
+ private boolean awaitInner(int timeout, @NonNull TimeUnit timeUnit) {
+ try {
+ return mLatch.await(timeout, timeUnit);
+ } catch (InterruptedException e) {
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Completable object of integer primitive.
+ */
+ public static final class Int extends ValueBase {
+ @GuardedBy("mValueLock")
+ private int mValue = 0;
+
+ /**
+ * Notify when a value is set to this completable object.
+ *
+ * @param value value to be set.
+ */
+ @AnyThread
+ void onComplete(int value) {
+ synchronized (mValueLock) {
+ if (mHasValue) {
+ throw new UnsupportedOperationException(
+ "onComplete() cannot be called multiple times");
+ }
+ mValue = value;
+ mHasValue = true;
+ }
+ onComplete();
+ }
+
+ /**
+ * @return value associated with this object.
+ * @throws UnsupportedOperationException when called while {@link #hasValue()} returns
+ * {@code false}.
+ */
+ @AnyThread
+ public int getValue() {
+ synchronized (mValueLock) {
+ if (!mHasValue) {
+ throw new UnsupportedOperationException(
+ "getValue() is allowed only if hasValue() returns true");
+ }
+ return mValue;
+ }
+ }
+ }
+
+ /**
+ * Base class of completable object types.
+ *
+ * @param <T> type associated with this completable object.
+ */
+ public static class Values<T> extends ValueBase {
+ @GuardedBy("mValueLock")
+ @Nullable
+ private T mValue = null;
+
+ /**
+ * Notify when a value is set to this completable value object.
+ *
+ * @param value value to be set.
+ */
+ @AnyThread
+ void onComplete(@Nullable T value) {
+ synchronized (mValueLock) {
+ if (mHasValue) {
+ throw new UnsupportedOperationException(
+ "onComplete() cannot be called multiple times");
+ }
+ mValue = value;
+ mHasValue = true;
+ }
+ onComplete();
+ }
+
+ /**
+ * @return value associated with this object.
+ * @throws UnsupportedOperationException when called while {@link #hasValue()} returns
+ * {@code false}.
+ */
+ @AnyThread
+ @Nullable
+ public T getValue() {
+ synchronized (mValueLock) {
+ if (!mHasValue) {
+ throw new UnsupportedOperationException(
+ "getValue() is allowed only if hasValue() returns true");
+ }
+ return mValue;
+ }
+ }
+ }
+
+ /**
+ * @return an instance of {@link Completable.Int}.
+ */
+ public static Completable.Int createInt() {
+ return new Completable.Int();
+ }
+
+ /**
+ * @return an instance of {@link Completable.Boolean}.
+ */
+ public static Completable.Boolean createBoolean() {
+ return new Completable.Boolean();
+ }
+
+ /**
+ * @return an instance of {@link Completable.CharSequence}.
+ */
+ public static Completable.CharSequence createCharSequence() {
+ return new Completable.CharSequence();
+ }
+
+ /**
+ * @return an instance of {@link Completable.ExtractedText}.
+ */
+ public static Completable.ExtractedText createExtractedText() {
+ return new Completable.ExtractedText();
+ }
+
+ /**
+ * @return an instance of {@link Completable.SurroundingText}.
+ */
+ public static Completable.SurroundingText createSurroundingText() {
+ return new Completable.SurroundingText();
+ }
+
+ /**
+ * Completable object of {@link java.lang.Boolean}.
+ */
+ public static final class Boolean extends Values<java.lang.Boolean> { }
+
+ /**
+ * Completable object of {@link java.lang.CharSequence}.
+ */
+ public static final class CharSequence extends Values<java.lang.CharSequence> { }
+
+ /**
+ * Completable object of {@link android.view.inputmethod.ExtractedText}.
+ */
+ public static final class ExtractedText
+ extends Values<android.view.inputmethod.ExtractedText> { }
+
+ /**
+ * Completable object of {@link android.view.inputmethod.SurroundingText}.
+ */
+ public static final class SurroundingText
+ extends Values<android.view.inputmethod.SurroundingText> { }
+
+ /**
+ * Completable object of {@link com.android.internal.view.InputBindResult}.
+ */
+ public static final class InputBindResult
+ extends Values<com.android.internal.view.InputBindResult> { }
+}
diff --git a/core/java/com/android/internal/inputmethod/ResultCallbacks.java b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
index 5eba898fde8a..7131284e42df 100644
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
@@ -26,7 +26,7 @@ import java.util.concurrent.atomic.AtomicReference;
/**
* Defines a set of factory methods to create {@link android.os.IBinder}-based callbacks that are
- * associated with completable objects defined in {@link CancellationGroup.Completable}.
+ * associated with completable objects defined in {@link Completable}.
*/
public final class ResultCallbacks {
@@ -50,22 +50,22 @@ public final class ResultCallbacks {
}
/**
- * Creates {@link IIntResultCallback.Stub} that is to set
- * {@link CancellationGroup.Completable.Int} when receiving the result.
+ * Creates {@link IIntResultCallback.Stub} that is to set {@link Completable.Int} when receiving
+ * the result.
*
- * @param value {@link CancellationGroup.Completable.Int} to be set when receiving the result.
+ * @param value {@link Completable.Int} to be set when receiving the result.
* @return {@link IIntResultCallback.Stub} that can be passed as a binder IPC parameter.
*/
@AnyThread
- public static IIntResultCallback.Stub of(@NonNull CancellationGroup.Completable.Int value) {
- final AtomicReference<WeakReference<CancellationGroup.Completable.Int>>
+ public static IIntResultCallback.Stub of(@NonNull Completable.Int value) {
+ final AtomicReference<WeakReference<Completable.Int>>
atomicRef = new AtomicReference<>(new WeakReference<>(value));
return new IIntResultCallback.Stub() {
@BinderThread
@Override
public void onResult(int result) {
- final CancellationGroup.Completable.Int value = unwrap(atomicRef);
+ final Completable.Int value = unwrap(atomicRef);
if (value == null) {
return;
}
@@ -76,24 +76,23 @@ public final class ResultCallbacks {
/**
* Creates {@link ICharSequenceResultCallback.Stub} that is to set
- * {@link CancellationGroup.Completable.CharSequence} when receiving the result.
+ * {@link Completable.CharSequence} when receiving the result.
*
- * @param value {@link CancellationGroup.Completable.CharSequence} to be set when receiving the
- * result.
+ * @param value {@link Completable.CharSequence} to be set when receiving the result.
* @return {@link ICharSequenceResultCallback.Stub} that can be passed as a binder IPC
* parameter.
*/
@AnyThread
public static ICharSequenceResultCallback.Stub of(
- @NonNull CancellationGroup.Completable.CharSequence value) {
- final AtomicReference<WeakReference<CancellationGroup.Completable.CharSequence>> atomicRef =
+ @NonNull Completable.CharSequence value) {
+ final AtomicReference<WeakReference<Completable.CharSequence>> atomicRef =
new AtomicReference<>(new WeakReference<>(value));
return new ICharSequenceResultCallback.Stub() {
@BinderThread
@Override
public void onResult(CharSequence result) {
- final CancellationGroup.Completable.CharSequence value = unwrap(atomicRef);
+ final Completable.CharSequence value = unwrap(atomicRef);
if (value == null) {
return;
}
@@ -104,24 +103,23 @@ public final class ResultCallbacks {
/**
* Creates {@link IExtractedTextResultCallback.Stub} that is to set
- * {@link CancellationGroup.Completable.ExtractedText} when receiving the result.
+ * {@link Completable.ExtractedText} when receiving the result.
*
- * @param value {@link CancellationGroup.Completable.ExtractedText} to be set when receiving the
- * result.
+ * @param value {@link Completable.ExtractedText} to be set when receiving the result.
* @return {@link IExtractedTextResultCallback.Stub} that can be passed as a binder IPC
* parameter.
*/
@AnyThread
public static IExtractedTextResultCallback.Stub of(
- @NonNull CancellationGroup.Completable.ExtractedText value) {
- final AtomicReference<WeakReference<CancellationGroup.Completable.ExtractedText>>
+ @NonNull Completable.ExtractedText value) {
+ final AtomicReference<WeakReference<Completable.ExtractedText>>
atomicRef = new AtomicReference<>(new WeakReference<>(value));
return new IExtractedTextResultCallback.Stub() {
@BinderThread
@Override
public void onResult(android.view.inputmethod.ExtractedText result) {
- final CancellationGroup.Completable.ExtractedText value = unwrap(atomicRef);
+ final Completable.ExtractedText value = unwrap(atomicRef);
if (value == null) {
return;
}
@@ -132,24 +130,23 @@ public final class ResultCallbacks {
/**
* Creates {@link ISurroundingTextResultCallback.Stub} that is to set
- * {@link CancellationGroup.Completable.SurroundingText} when receiving the result.
+ * {@link Completable.SurroundingText} when receiving the result.
*
- * @param value {@link CancellationGroup.Completable.SurroundingText} to be set when receiving
- * the result.
+ * @param value {@link Completable.SurroundingText} to be set when receiving the result.
* @return {@link ISurroundingTextResultCallback.Stub} that can be passed as a binder IPC
* parameter.
*/
@AnyThread
public static ISurroundingTextResultCallback.Stub of(
- @NonNull CancellationGroup.Completable.SurroundingText value) {
- final AtomicReference<WeakReference<CancellationGroup.Completable.SurroundingText>>
+ @NonNull Completable.SurroundingText value) {
+ final AtomicReference<WeakReference<Completable.SurroundingText>>
atomicRef = new AtomicReference<>(new WeakReference<>(value));
return new ISurroundingTextResultCallback.Stub() {
@BinderThread
@Override
public void onResult(android.view.inputmethod.SurroundingText result) {
- final CancellationGroup.Completable.SurroundingText value = unwrap(atomicRef);
+ final Completable.SurroundingText value = unwrap(atomicRef);
if (value == null) {
return;
}
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index f46626be48a8..ffc7f05eb703 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -144,7 +144,7 @@ public @interface SoftInputShowHideReason {
int HIDE_RECENTS_ANIMATION = 18;
/**
- * Hide soft input when {@link com.android.systemui.bubbles.BubbleController} is expanding,
+ * Hide soft input when {@link com.android.wm.shell.bubbles.BubbleController} is expanding,
* switching, or collapsing Bubbles.
*/
int HIDE_BUBBLES = 19;
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 85dc2aea4b1c..c0d46f632500 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -176,7 +176,7 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
* Trigger the prefetto daemon.
*/
public void triggerPerfetto() {
- InteractionJankMonitor.getInstance().trigger();
+ InteractionJankMonitor.getInstance().trigger(mSession);
}
/**
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 3624f0d34725..fcaa963feda2 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -22,7 +22,12 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_RECENTS;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_COLLAPSE_LOCK;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_APPEAR;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_DISAPPEAR;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_ADD;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_REMOVE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_EXPAND_COLLAPSE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_QS_SCROLL_SWIPE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_EXPAND;
@@ -67,6 +72,11 @@ public class InteractionJankMonitor {
public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME = 9;
public static final int CUJ_LAUNCHER_APP_CLOSE_TO_PIP = 10;
public static final int CUJ_LAUNCHER_QUICK_SWITCH = 11;
+ public static final int CUJ_NOTIFICATION_HEADS_UP_APPEAR = 12;
+ public static final int CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR = 13;
+ public static final int CUJ_NOTIFICATION_ADD = 14;
+ public static final int CUJ_NOTIFICATION_REMOVE = 15;
+ public static final int CUJ_NOTIFICATION_APP_START = 16;
private static final int NO_STATSD_LOGGING = -1;
@@ -87,6 +97,11 @@ public class InteractionJankMonitor {
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_QUICK_SWITCH,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_APPEAR,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_HEADS_UP_DISAPPEAR,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_ADD,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_NOTIFICATION_REMOVE,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_APP_LAUNCH,
};
private static volatile InteractionJankMonitor sInstance;
@@ -112,6 +127,11 @@ public class InteractionJankMonitor {
CUJ_LAUNCHER_APP_CLOSE_TO_HOME,
CUJ_LAUNCHER_APP_CLOSE_TO_PIP,
CUJ_LAUNCHER_QUICK_SWITCH,
+ CUJ_NOTIFICATION_HEADS_UP_APPEAR,
+ CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR,
+ CUJ_NOTIFICATION_ADD,
+ CUJ_NOTIFICATION_REMOVE,
+ CUJ_NOTIFICATION_APP_START,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {}
@@ -319,15 +339,66 @@ public class InteractionJankMonitor {
* Trigger the perfetto daemon to collect and upload data.
*/
@VisibleForTesting
- public void trigger() {
+ public void trigger(Session session) {
synchronized (this) {
if (!mInitialized) return;
mWorker.getThreadHandler().post(
- () -> PerfettoTrigger.trigger(PerfettoTrigger.TRIGGER_TYPE_JANK));
+ () -> PerfettoTrigger.trigger(session.getPerfettoTrigger()));
}
}
/**
+ * A helper method to translate interaction type to CUJ name.
+ *
+ * @param interactionType the interaction type defined in AtomsProto.java
+ * @return the name of the interaction type
+ */
+ public static String getNameOfInteraction(int interactionType) {
+ // There is an offset amount of 1 between cujType and interactionType.
+ return getNameOfCuj(interactionType - 1);
+ }
+
+ private static String getNameOfCuj(int cujType) {
+ switch (cujType) {
+ case CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE:
+ return "SHADE_EXPAND_COLLAPSE";
+ case CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK:
+ return "SHADE_EXPAND_COLLAPSE_LOCK";
+ case CUJ_NOTIFICATION_SHADE_SCROLL_FLING:
+ return "SHADE_SCROLL_FLING";
+ case CUJ_NOTIFICATION_SHADE_ROW_EXPAND:
+ return "SHADE_ROW_EXPAND";
+ case CUJ_NOTIFICATION_SHADE_ROW_SWIPE:
+ return "SHADE_ROW_SWIPE";
+ case CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE:
+ return "SHADE_QS_EXPAND_COLLAPSE";
+ case CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE:
+ return "SHADE_QS_SCROLL_SWIPE";
+ case CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS:
+ return "LAUNCHER_APP_LAUNCH_FROM_RECENTS";
+ case CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON:
+ return "LAUNCHER_APP_LAUNCH_FROM_ICON";
+ case CUJ_LAUNCHER_APP_CLOSE_TO_HOME:
+ return "LAUNCHER_APP_CLOSE_TO_HOME";
+ case CUJ_LAUNCHER_APP_CLOSE_TO_PIP:
+ return "LAUNCHER_APP_CLOSE_TO_PIP";
+ case CUJ_LAUNCHER_QUICK_SWITCH:
+ return "LAUNCHER_QUICK_SWITCH";
+ case CUJ_NOTIFICATION_HEADS_UP_APPEAR:
+ return "NOTIFICATION_HEADS_UP_APPEAR";
+ case CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR:
+ return "NOTIFICATION_HEADS_UP_DISAPPEAR";
+ case CUJ_NOTIFICATION_ADD:
+ return "NOTIFICATION_ADD";
+ case CUJ_NOTIFICATION_REMOVE:
+ return "NOTIFICATION_REMOVE";
+ case CUJ_NOTIFICATION_APP_START:
+ return "NOTIFICATION_APP_START";
+ }
+ return "UNKNOWN";
+ }
+
+ /**
* A class to represent a session.
*/
public static class Session {
@@ -350,9 +421,12 @@ public class InteractionJankMonitor {
return getStatsdInteractionType() != NO_STATSD_LOGGING;
}
+ public String getPerfettoTrigger() {
+ return String.format("interaction-jank-monitor-%d", mCujType);
+ }
+
public String getName() {
- return "Cuj<" + getCuj() + ">";
+ return "Cuj<" + getNameOfCuj(mCujType) + ">";
}
}
-
}
diff --git a/core/java/com/android/internal/jank/PerfettoTrigger.java b/core/java/com/android/internal/jank/PerfettoTrigger.java
index 6c8d3cdcf5ae..643d24a51b58 100644
--- a/core/java/com/android/internal/jank/PerfettoTrigger.java
+++ b/core/java/com/android/internal/jank/PerfettoTrigger.java
@@ -17,15 +17,12 @@
//TODO (165884885): Make PerfettoTrigger more generic and move it to another package.
package com.android.internal.jank;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
/**
* A trigger implementation with perfetto backend.
@@ -35,23 +32,14 @@ public class PerfettoTrigger {
private static final String TAG = PerfettoTrigger.class.getSimpleName();
private static final boolean DEBUG = false;
private static final String TRIGGER_COMMAND = "/system/bin/trigger_perfetto";
- private static final String[] TRIGGER_TYPE_NAMES = new String[] { "jank-tracker" };
- public static final int TRIGGER_TYPE_JANK = 0;
-
- /** @hide */
- @IntDef({
- TRIGGER_TYPE_JANK
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface TriggerType {}
/**
- * @param type the trigger type
+ * @param triggerName The name of the trigger. Must match the value defined in the AOT
+ * Perfetto config.
*/
- public static void trigger(@NonNull @TriggerType int type) {
+ public static void trigger(String triggerName) {
try {
- Token token = new Token(type, TRIGGER_TYPE_NAMES[type]);
- ProcessBuilder pb = new ProcessBuilder(TRIGGER_COMMAND, token.getName());
+ ProcessBuilder pb = new ProcessBuilder(TRIGGER_COMMAND, triggerName);
if (DEBUG) {
StringBuilder sb = new StringBuilder();
for (String arg : pb.command()) {
@@ -64,7 +52,7 @@ public class PerfettoTrigger {
readConsoleOutput(process);
}
} catch (IOException | InterruptedException e) {
- Log.w(TAG, "Failed to trigger " + type, e);
+ Log.w(TAG, "Failed to trigger " + triggerName, e);
}
}
@@ -82,34 +70,4 @@ public class PerfettoTrigger {
Log.d(TAG, "err message=" + errLine.toString());
}
}
-
- /**
- * Token which is used to trigger perfetto.
- */
- public static class Token {
- private int mType;
- private String mName;
-
- Token(@TriggerType int type, String name) {
- mType = type;
- mName = name;
- }
-
- /**
- * Get trigger type.
- * @return trigger type, should be @TriggerType
- */
- public int getType() {
- return mType;
- }
-
- /**
- * Get name of this token as the argument while triggering perfetto.
- * @return name
- */
- public String getName() {
- return mName;
- }
- }
-
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index e7e75a84643b..7c442b408624 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4014,7 +4014,7 @@ public class BatteryStatsImpl extends BatteryStats {
/**
* Schedules a read of the latest cpu times before removing the isolated UID.
- * @see #removeIsolatedUidLocked(int)
+ * @see #removeIsolatedUidLocked(int, int, int)
*/
public void scheduleRemoveIsolatedUidLocked(int isolatedUid, int appUid) {
int curUid = mIsolatedUids.get(isolatedUid, -1);
@@ -4030,14 +4030,6 @@ public class BatteryStatsImpl extends BatteryStats {
* @see #scheduleRemoveIsolatedUidLocked(int, int)
*/
@GuardedBy("this")
- public void removeIsolatedUidLocked(int isolatedUid) {
- removeIsolatedUidLocked(isolatedUid, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
- }
-
- /**
- * @see #removeIsolatedUidLocked(int)
- */
- @GuardedBy("this")
public void removeIsolatedUidLocked(int isolatedUid, long elapsedRealtimeMs, long uptimeMs) {
final int idx = mIsolatedUids.indexOfKey(isolatedUid);
if (idx >= 0) {
@@ -11429,13 +11421,6 @@ public class BatteryStatsImpl extends BatteryStats {
* Distribute WiFi energy info and network traffic to apps.
* @param info The energy information from the WiFi controller.
*/
- public void updateWifiState(@Nullable final WifiActivityEnergyInfo info) {
- updateWifiState(info, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
- }
-
- /**
- * @see #updateWifiState(WifiActivityEnergyInfo)
- */
public void updateWifiState(@Nullable final WifiActivityEnergyInfo info,
long elapsedRealtimeMs, long uptimeMs) {
if (DEBUG_ENERGY) {
@@ -11714,13 +11699,6 @@ public class BatteryStatsImpl extends BatteryStats {
/**
* Distribute Cell radio energy info and network traffic to apps.
*/
- public void updateMobileRadioState(@Nullable final ModemActivityInfo activityInfo) {
- updateMobileRadioState(activityInfo, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
- }
-
- /**
- * @see #updateMobileRadioState(ModemActivityInfo)
- */
public void updateMobileRadioState(@Nullable final ModemActivityInfo activityInfo,
long elapsedRealtimeMs, long uptimeMs) {
if (DEBUG_ENERGY) {
@@ -11954,13 +11932,6 @@ public class BatteryStatsImpl extends BatteryStats {
*
* @param info The energy information from the bluetooth controller.
*/
- public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
- updateBluetoothStateLocked(info, mClocks.elapsedRealtime(), mClocks.uptimeMillis());
- }
-
- /**
- * @see #updateBluetoothStateLocked(BluetoothActivityEnergyInfo)
- */
public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info,
long elapsedRealtimeMs, long uptimeMs) {
if (DEBUG_ENERGY) {
@@ -12138,13 +12109,6 @@ public class BatteryStatsImpl extends BatteryStats {
* If RPM stats were fetched more recently than RPM_STATS_UPDATE_FREQ_MS ago, uses the old data
* instead of fetching it anew.
*/
- public void updateRpmStatsLocked() {
- updateRpmStatsLocked(mClocks.elapsedRealtime() * 1000);
- }
-
- /**
- * @see #updateRpmStatsLocked()
- */
public void updateRpmStatsLocked(long elapsedRealtimeUs) {
if (mPlatformIdleStateCallback == null) return;
long now = SystemClock.elapsedRealtime();
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index 3d35d2fbaa82..f668bbaf9438 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -21,8 +21,8 @@ import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.StrictMode;
import android.os.SystemClock;
-import android.system.suspend.ISuspendControlService;
-import android.system.suspend.WakeLockInfo;
+import android.system.suspend.internal.ISuspendControlServiceInternal;
+import android.system.suspend.internal.WakeLockInfo;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -66,7 +66,7 @@ public class KernelWakelockReader {
private final String[] mProcWakelocksName = new String[3];
private final long[] mProcWakelocksData = new long[3];
- private ISuspendControlService mSuspendControlService = null;
+ private ISuspendControlServiceInternal mSuspendControlService = null;
private byte[] mKernelWakelockBuffer = new byte[32 * 1024];
/**
@@ -155,11 +155,12 @@ public class KernelWakelockReader {
/**
* Attempt to wait for suspend_control service if not immediately available.
*/
- private ISuspendControlService waitForSuspendControlService() throws ServiceNotFoundException {
- final String name = "suspend_control";
+ private ISuspendControlServiceInternal waitForSuspendControlService()
+ throws ServiceNotFoundException {
+ final String name = "suspend_control_internal";
final int numRetries = 5;
for (int i = 0; i < numRetries; i++) {
- mSuspendControlService = ISuspendControlService.Stub.asInterface(
+ mSuspendControlService = ISuspendControlServiceInternal.Stub.asInterface(
ServiceManager.getService(name));
if (mSuspendControlService != null) {
return mSuspendControlService;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 5571a58a8999..e067f5fbdf45 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -776,8 +776,10 @@ public class ArrayUtils {
int matchesCount = 0;
int size = size(items);
+ final boolean[] tests = new boolean[size];
for (int i = 0; i < size; i++) {
- if (predicate.test(items[i])) {
+ tests[i] = predicate.test(items[i]);
+ if (tests[i]) {
matchesCount++;
}
}
@@ -790,7 +792,7 @@ public class ArrayUtils {
}
int outIdx = 0;
for (int i = 0; i < size; i++) {
- if (predicate.test(items[i])) {
+ if (tests[i]) {
result[outIdx++] = items[i];
}
}
diff --git a/core/java/com/android/internal/util/BinaryXmlPullParser.java b/core/java/com/android/internal/util/BinaryXmlPullParser.java
new file mode 100644
index 000000000000..da16eca5239c
--- /dev/null
+++ b/core/java/com/android/internal/util/BinaryXmlPullParser.java
@@ -0,0 +1,899 @@
+/*
+ * 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.util;
+
+import static com.android.internal.util.BinaryXmlSerializer.ATTRIBUTE;
+import static com.android.internal.util.BinaryXmlSerializer.PROTOCOL_MAGIC_VERSION_0;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_BOOLEAN_FALSE;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_BOOLEAN_TRUE;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_BYTES_BASE64;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_BYTES_HEX;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_DOUBLE;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_FLOAT;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_INT;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_INT_HEX;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_LONG;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_LONG_HEX;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_NULL;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_STRING;
+import static com.android.internal.util.BinaryXmlSerializer.TYPE_STRING_INTERNED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Parser that reads XML documents using a custom binary wire protocol which
+ * benchmarking has shown to be 8.5x faster than {@link Xml.newFastPullParser()}
+ * for a typical {@code packages.xml}.
+ * <p>
+ * The high-level design of the wire protocol is to directly serialize the event
+ * stream, while efficiently and compactly writing strongly-typed primitives
+ * delivered through the {@link TypedXmlSerializer} interface.
+ * <p>
+ * Each serialized event is a single byte where the lower half is a normal
+ * {@link XmlPullParser} token and the upper half is an optional data type
+ * signal, such as {@link #TYPE_INT}.
+ * <p>
+ * This parser has some specific limitations:
+ * <ul>
+ * <li>Only the UTF-8 encoding is supported.
+ * <li>Variable length values, such as {@code byte[]} or {@link String}, are
+ * limited to 65,535 bytes in length. Note that {@link String} values are stored
+ * as UTF-8 on the wire.
+ * <li>Namespaces, prefixes, properties, and options are unsupported.
+ * </ul>
+ */
+public final class BinaryXmlPullParser implements TypedXmlPullParser {
+ /**
+ * Default buffer size, which matches {@code FastXmlSerializer}. This should
+ * be kept in sync with {@link BinaryXmlPullParser}.
+ */
+ private static final int BUFFER_SIZE = 32_768;
+
+ private FastDataInput mIn;
+
+ private int mCurrentToken = START_DOCUMENT;
+ private int mCurrentDepth = 0;
+ private String mCurrentName;
+ private String mCurrentText;
+
+ /**
+ * Pool of attributes parsed for the currently tag. All interactions should
+ * be done via {@link #obtainAttribute()}, {@link #findAttribute(String)},
+ * and {@link #resetAttributes()}.
+ */
+ private int mAttributeCount = 0;
+ private Attribute[] mAttributes;
+
+ @Override
+ public void setInput(InputStream is, String inputEncoding) throws XmlPullParserException {
+ if (inputEncoding != null && !StandardCharsets.UTF_8.name().equals(inputEncoding)) {
+ throw new UnsupportedOperationException();
+ }
+
+ mIn = new FastDataInput(is, BUFFER_SIZE);
+
+ mCurrentToken = START_DOCUMENT;
+ mCurrentDepth = 0;
+ mCurrentName = null;
+ mCurrentText = null;
+
+ mAttributeCount = 0;
+ mAttributes = new Attribute[8];
+ for (int i = 0; i < mAttributes.length; i++) {
+ mAttributes[i] = new Attribute();
+ }
+
+ try {
+ final byte[] magic = new byte[4];
+ mIn.readFully(magic);
+ if (!Arrays.equals(magic, PROTOCOL_MAGIC_VERSION_0)) {
+ throw new IOException("Unexpected magic " + bytesToHexString(magic));
+ }
+
+ // We're willing to immediately consume a START_DOCUMENT if present,
+ // but we're okay if it's missing
+ if (peekNextExternalToken() == START_DOCUMENT) {
+ consumeToken();
+ }
+ } catch (IOException e) {
+ throw new XmlPullParserException(e.toString());
+ }
+ }
+
+ @Override
+ public void setInput(Reader in) throws XmlPullParserException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int next() throws XmlPullParserException, IOException {
+ while (true) {
+ final int token = nextToken();
+ switch (token) {
+ case START_TAG:
+ case END_TAG:
+ case END_DOCUMENT:
+ return token;
+ case TEXT:
+ consumeAdditionalText();
+ // Per interface docs, empty text regions are skipped
+ if (mCurrentText == null || mCurrentText.length() == 0) {
+ continue;
+ } else {
+ return TEXT;
+ }
+ }
+ }
+ }
+
+ @Override
+ public int nextToken() throws XmlPullParserException, IOException {
+ if (mCurrentToken == XmlPullParser.END_TAG) {
+ mCurrentDepth--;
+ }
+
+ int token;
+ try {
+ token = peekNextExternalToken();
+ consumeToken();
+ } catch (EOFException e) {
+ token = END_DOCUMENT;
+ }
+ switch (token) {
+ case XmlPullParser.START_TAG:
+ // We need to peek forward to find the next external token so
+ // that we parse all pending INTERNAL_ATTRIBUTE tokens
+ peekNextExternalToken();
+ mCurrentDepth++;
+ break;
+ }
+ mCurrentToken = token;
+ return token;
+ }
+
+ /**
+ * Peek at the next "external" token without consuming it.
+ * <p>
+ * External tokens, such as {@link #START_TAG}, are expected by typical
+ * {@link XmlPullParser} clients. In contrast, internal tokens, such as
+ * {@link #ATTRIBUTE}, are not expected by typical clients.
+ * <p>
+ * This method consumes any internal events until it reaches the next
+ * external event.
+ */
+ private int peekNextExternalToken() throws IOException, XmlPullParserException {
+ while (true) {
+ final int token = peekNextToken();
+ switch (token) {
+ case ATTRIBUTE:
+ consumeToken();
+ continue;
+ default:
+ return token;
+ }
+ }
+ }
+
+ /**
+ * Peek at the next token in the underlying stream without consuming it.
+ */
+ private int peekNextToken() throws IOException {
+ return mIn.peekByte() & 0x0f;
+ }
+
+ /**
+ * Parse and consume the next token in the underlying stream.
+ */
+ private void consumeToken() throws IOException, XmlPullParserException {
+ final int event = mIn.readByte();
+ final int token = event & 0x0f;
+ final int type = event & 0xf0;
+ switch (token) {
+ case ATTRIBUTE: {
+ final Attribute attr = obtainAttribute();
+ attr.name = mIn.readInternedUTF();
+ attr.type = type;
+ switch (type) {
+ case TYPE_NULL:
+ case TYPE_BOOLEAN_TRUE:
+ case TYPE_BOOLEAN_FALSE:
+ // Nothing extra to fill in
+ break;
+ case TYPE_STRING:
+ attr.valueString = mIn.readUTF();
+ break;
+ case TYPE_STRING_INTERNED:
+ attr.valueString = mIn.readInternedUTF();
+ break;
+ case TYPE_BYTES_HEX:
+ case TYPE_BYTES_BASE64:
+ final int len = mIn.readUnsignedShort();
+ final byte[] res = new byte[len];
+ mIn.readFully(res);
+ attr.valueBytes = res;
+ break;
+ case TYPE_INT:
+ case TYPE_INT_HEX:
+ attr.valueInt = mIn.readInt();
+ break;
+ case TYPE_LONG:
+ case TYPE_LONG_HEX:
+ attr.valueLong = mIn.readLong();
+ break;
+ case TYPE_FLOAT:
+ attr.valueFloat = mIn.readFloat();
+ break;
+ case TYPE_DOUBLE:
+ attr.valueDouble = mIn.readDouble();
+ break;
+ default:
+ throw new IOException("Unexpected data type " + type);
+ }
+ break;
+ }
+ case XmlPullParser.START_DOCUMENT: {
+ break;
+ }
+ case XmlPullParser.END_DOCUMENT: {
+ break;
+ }
+ case XmlPullParser.START_TAG: {
+ mCurrentName = mIn.readInternedUTF();
+ resetAttributes();
+ break;
+ }
+ case XmlPullParser.END_TAG: {
+ mCurrentName = mIn.readInternedUTF();
+ resetAttributes();
+ break;
+ }
+ case XmlPullParser.TEXT:
+ case XmlPullParser.CDSECT:
+ case XmlPullParser.PROCESSING_INSTRUCTION:
+ case XmlPullParser.COMMENT:
+ case XmlPullParser.DOCDECL:
+ case XmlPullParser.IGNORABLE_WHITESPACE: {
+ mCurrentText = mIn.readUTF();
+ break;
+ }
+ case XmlPullParser.ENTITY_REF: {
+ mCurrentName = mIn.readUTF();
+ mCurrentText = resolveEntity(mCurrentName);
+ break;
+ }
+ default: {
+ throw new IOException("Unknown token " + token + " with type " + type);
+ }
+ }
+ }
+
+ /**
+ * When the current tag is {@link #TEXT}, consume all subsequent "text"
+ * events, as described by {@link #next}. When finished, the current event
+ * will still be {@link #TEXT}.
+ */
+ private void consumeAdditionalText() throws IOException, XmlPullParserException {
+ String combinedText = mCurrentText;
+ while (true) {
+ final int token = peekNextExternalToken();
+ switch (token) {
+ case COMMENT:
+ case PROCESSING_INSTRUCTION:
+ // Quietly consumed
+ consumeToken();
+ break;
+ case TEXT:
+ case CDSECT:
+ case ENTITY_REF:
+ // Additional text regions collected
+ consumeToken();
+ combinedText += mCurrentText;
+ break;
+ default:
+ // Next token is something non-text, so wrap things up
+ mCurrentToken = TEXT;
+ mCurrentName = null;
+ mCurrentText = combinedText;
+ return;
+ }
+ }
+ }
+
+ static @NonNull String resolveEntity(@NonNull String entity)
+ throws XmlPullParserException {
+ switch (entity) {
+ case "lt": return "<";
+ case "gt": return ">";
+ case "amp": return "&";
+ case "apos": return "'";
+ case "quot": return "\"";
+ }
+ if (entity.length() > 1 && entity.charAt(0) == '#') {
+ final char c = (char) Integer.parseInt(entity.substring(1));
+ return new String(new char[] { c });
+ }
+ throw new XmlPullParserException("Unknown entity " + entity);
+ }
+
+ @Override
+ public void require(int type, String namespace, String name)
+ throws XmlPullParserException, IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ if (mCurrentToken != type || !Objects.equals(mCurrentName, name)) {
+ throw new XmlPullParserException(getPositionDescription());
+ }
+ }
+
+ @Override
+ public String nextText() throws XmlPullParserException, IOException {
+ if (getEventType() != START_TAG) {
+ throw new XmlPullParserException(getPositionDescription());
+ }
+ int eventType = next();
+ if (eventType == TEXT) {
+ String result = getText();
+ eventType = next();
+ if (eventType != END_TAG) {
+ throw new XmlPullParserException(getPositionDescription());
+ }
+ return result;
+ } else if (eventType == END_TAG) {
+ return "";
+ } else {
+ throw new XmlPullParserException(getPositionDescription());
+ }
+ }
+
+ @Override
+ public int nextTag() throws XmlPullParserException, IOException {
+ int eventType = next();
+ if (eventType == TEXT && isWhitespace()) {
+ eventType = next();
+ }
+ if (eventType != START_TAG && eventType != END_TAG) {
+ throw new XmlPullParserException(getPositionDescription());
+ }
+ return eventType;
+ }
+
+ /**
+ * Allocate and return a new {@link Attribute} associated with the tag being
+ * currently processed. This will automatically grow the internal pool as
+ * needed.
+ */
+ private @NonNull Attribute obtainAttribute() {
+ if (mAttributeCount == mAttributes.length) {
+ final int before = mAttributes.length;
+ final int after = before + (before >> 1);
+ mAttributes = Arrays.copyOf(mAttributes, after);
+ for (int i = before; i < after; i++) {
+ mAttributes[i] = new Attribute();
+ }
+ }
+ return mAttributes[mAttributeCount++];
+ }
+
+ /**
+ * Clear any {@link Attribute} instances that have been allocated by
+ * {@link #obtainAttribute()}, returning them into the pool for recycling.
+ */
+ private void resetAttributes() {
+ for (int i = 0; i < mAttributeCount; i++) {
+ mAttributes[i].reset();
+ }
+ mAttributeCount = 0;
+ }
+
+ /**
+ * Search through the pool of currently allocated {@link Attribute}
+ * instances for one that matches the given name.
+ */
+ private @NonNull Attribute findAttribute(@NonNull String name) throws IOException {
+ for (int i = 0; i < mAttributeCount; i++) {
+ if (Objects.equals(mAttributes[i].name, name)) {
+ return mAttributes[i];
+ }
+ }
+ throw new IOException("Missing attribute " + name);
+ }
+
+ @Override
+ public String getAttributeValue(String namespace, String name) {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ try {
+ return findAttribute(name).getValueString();
+ } catch (IOException e) {
+ // Missing attributes default to null
+ return null;
+ }
+ }
+
+ @Override
+ public String getAttributeValue(int index) {
+ return mAttributes[index].getValueString();
+ }
+
+ @Override
+ public byte[] getAttributeBytesHex(String namespace, String name) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ return findAttribute(name).getValueBytesHex();
+ }
+
+ @Override
+ public byte[] getAttributeBytesBase64(String namespace, String name) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ return findAttribute(name).getValueBytesBase64();
+ }
+
+ @Override
+ public int getAttributeInt(String namespace, String name) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ return findAttribute(name).getValueInt();
+ }
+
+ @Override
+ public int getAttributeIntHex(String namespace, String name) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ return findAttribute(name).getValueIntHex();
+ }
+
+ @Override
+ public long getAttributeLong(String namespace, String name) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ return findAttribute(name).getValueLong();
+ }
+
+ @Override
+ public long getAttributeLongHex(String namespace, String name) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ return findAttribute(name).getValueLongHex();
+ }
+
+ @Override
+ public float getAttributeFloat(String namespace, String name) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ return findAttribute(name).getValueFloat();
+ }
+
+ @Override
+ public double getAttributeDouble(String namespace, String name) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ return findAttribute(name).getValueDouble();
+ }
+
+ @Override
+ public boolean getAttributeBoolean(String namespace, String name) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ return findAttribute(name).getValueBoolean();
+ }
+
+ @Override
+ public String getText() {
+ return mCurrentText;
+ }
+
+ @Override
+ public char[] getTextCharacters(int[] holderForStartAndLength) {
+ final char[] chars = mCurrentText.toCharArray();
+ holderForStartAndLength[0] = 0;
+ holderForStartAndLength[1] = chars.length;
+ return chars;
+ }
+
+ @Override
+ public String getInputEncoding() {
+ return StandardCharsets.UTF_8.name();
+ }
+
+ @Override
+ public int getDepth() {
+ return mCurrentDepth;
+ }
+
+ @Override
+ public String getPositionDescription() {
+ // Not very helpful, but it's the best information we have
+ return "Token " + mCurrentToken + " at depth " + mCurrentDepth;
+ }
+
+ @Override
+ public int getLineNumber() {
+ return -1;
+ }
+
+ @Override
+ public int getColumnNumber() {
+ return -1;
+ }
+
+ @Override
+ public boolean isWhitespace() throws XmlPullParserException {
+ switch (mCurrentToken) {
+ case IGNORABLE_WHITESPACE:
+ return true;
+ case TEXT:
+ case CDSECT:
+ return !TextUtils.isGraphic(mCurrentText);
+ default:
+ throw new XmlPullParserException("Not applicable for token " + mCurrentToken);
+ }
+ }
+
+ @Override
+ public String getNamespace() {
+ switch (mCurrentToken) {
+ case START_TAG:
+ case END_TAG:
+ // Namespaces are unsupported
+ return NO_NAMESPACE;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public String getName() {
+ return mCurrentName;
+ }
+
+ @Override
+ public String getPrefix() {
+ // Prefixes are not supported
+ return null;
+ }
+
+ @Override
+ public boolean isEmptyElementTag() throws XmlPullParserException {
+ switch (mCurrentToken) {
+ case START_TAG:
+ try {
+ return (peekNextExternalToken() == END_TAG);
+ } catch (IOException e) {
+ throw new XmlPullParserException(e.toString());
+ }
+ default:
+ throw new XmlPullParserException("Not at START_TAG");
+ }
+ }
+
+ @Override
+ public int getAttributeCount() {
+ return mAttributeCount;
+ }
+
+ @Override
+ public String getAttributeNamespace(int index) {
+ // Namespaces are unsupported
+ return NO_NAMESPACE;
+ }
+
+ @Override
+ public String getAttributeName(int index) {
+ return mAttributes[index].name;
+ }
+
+ @Override
+ public String getAttributePrefix(int index) {
+ // Prefixes are not supported
+ return null;
+ }
+
+ @Override
+ public String getAttributeType(int index) {
+ // Validation is not supported
+ return "CDATA";
+ }
+
+ @Override
+ public boolean isAttributeDefault(int index) {
+ // Validation is not supported
+ return false;
+ }
+
+ @Override
+ public int getEventType() throws XmlPullParserException {
+ return mCurrentToken;
+ }
+
+ @Override
+ public int getNamespaceCount(int depth) throws XmlPullParserException {
+ // Namespaces are unsupported
+ return 0;
+ }
+
+ @Override
+ public String getNamespacePrefix(int pos) throws XmlPullParserException {
+ // Namespaces are unsupported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getNamespaceUri(int pos) throws XmlPullParserException {
+ // Namespaces are unsupported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getNamespace(String prefix) {
+ // Namespaces are unsupported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void defineEntityReplacementText(String entityName, String replacementText)
+ throws XmlPullParserException {
+ // Custom entities are not supported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setFeature(String name, boolean state) throws XmlPullParserException {
+ // Features are not supported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getFeature(String name) {
+ // Features are not supported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setProperty(String name, Object value) throws XmlPullParserException {
+ // Properties are not supported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getProperty(String name) {
+ // Properties are not supported
+ throw new UnsupportedOperationException();
+ }
+
+ private static IllegalArgumentException illegalNamespace() {
+ throw new IllegalArgumentException("Namespaces are not supported");
+ }
+
+ /**
+ * Holder representing a single attribute. This design enables object
+ * recycling without resorting to autoboxing.
+ * <p>
+ * To support conversion between human-readable XML and binary XML, the
+ * various accessor methods will transparently convert from/to
+ * human-readable values when needed.
+ */
+ private static class Attribute {
+ public String name;
+ public int type;
+
+ public String valueString;
+ public byte[] valueBytes;
+ public int valueInt;
+ public long valueLong;
+ public float valueFloat;
+ public double valueDouble;
+
+ public void reset() {
+ name = null;
+ valueString = null;
+ valueBytes = null;
+ }
+
+ public @Nullable String getValueString() {
+ switch (type) {
+ case TYPE_NULL:
+ return null;
+ case TYPE_STRING:
+ case TYPE_STRING_INTERNED:
+ return valueString;
+ case TYPE_BYTES_HEX:
+ return bytesToHexString(valueBytes);
+ case TYPE_BYTES_BASE64:
+ return Base64.encodeToString(valueBytes, Base64.NO_WRAP);
+ case TYPE_INT:
+ return Integer.toString(valueInt);
+ case TYPE_INT_HEX:
+ return Integer.toString(valueInt, 16);
+ case TYPE_LONG:
+ return Long.toString(valueLong);
+ case TYPE_LONG_HEX:
+ return Long.toString(valueLong, 16);
+ case TYPE_FLOAT:
+ return Float.toString(valueFloat);
+ case TYPE_DOUBLE:
+ return Double.toString(valueDouble);
+ case TYPE_BOOLEAN_TRUE:
+ return "true";
+ case TYPE_BOOLEAN_FALSE:
+ return "false";
+ default:
+ // Unknown data type; null is the best we can offer
+ return null;
+ }
+ }
+
+ public @Nullable byte[] getValueBytesHex() throws IOException {
+ switch (type) {
+ case TYPE_NULL:
+ return null;
+ case TYPE_BYTES_HEX:
+ case TYPE_BYTES_BASE64:
+ return valueBytes;
+ case TYPE_STRING:
+ return hexStringToBytes(valueString);
+ default:
+ throw new IOException("Invalid conversion from " + type);
+ }
+ }
+
+ public @Nullable byte[] getValueBytesBase64() throws IOException {
+ switch (type) {
+ case TYPE_NULL:
+ return null;
+ case TYPE_BYTES_HEX:
+ case TYPE_BYTES_BASE64:
+ return valueBytes;
+ case TYPE_STRING:
+ return Base64.decode(valueString, Base64.NO_WRAP);
+ default:
+ throw new IOException("Invalid conversion from " + type);
+ }
+ }
+
+ public int getValueInt() throws IOException {
+ switch (type) {
+ case TYPE_INT:
+ case TYPE_INT_HEX:
+ return valueInt;
+ case TYPE_STRING:
+ return Integer.parseInt(valueString);
+ default:
+ throw new IOException("Invalid conversion from " + type);
+ }
+ }
+
+ public int getValueIntHex() throws IOException {
+ switch (type) {
+ case TYPE_INT:
+ case TYPE_INT_HEX:
+ return valueInt;
+ case TYPE_STRING:
+ return Integer.parseInt(valueString, 16);
+ default:
+ throw new IOException("Invalid conversion from " + type);
+ }
+ }
+
+ public long getValueLong() throws IOException {
+ switch (type) {
+ case TYPE_LONG:
+ case TYPE_LONG_HEX:
+ return valueLong;
+ case TYPE_STRING:
+ return Long.parseLong(valueString);
+ default:
+ throw new IOException("Invalid conversion from " + type);
+ }
+ }
+
+ public long getValueLongHex() throws IOException {
+ switch (type) {
+ case TYPE_LONG:
+ case TYPE_LONG_HEX:
+ return valueLong;
+ case TYPE_STRING:
+ return Long.parseLong(valueString, 16);
+ default:
+ throw new IOException("Invalid conversion from " + type);
+ }
+ }
+
+ public float getValueFloat() throws IOException {
+ switch (type) {
+ case TYPE_FLOAT:
+ return valueFloat;
+ case TYPE_STRING:
+ return Float.parseFloat(valueString);
+ default:
+ throw new IOException("Invalid conversion from " + type);
+ }
+ }
+
+ public double getValueDouble() throws IOException {
+ switch (type) {
+ case TYPE_DOUBLE:
+ return valueDouble;
+ case TYPE_STRING:
+ return Double.parseDouble(valueString);
+ default:
+ throw new IOException("Invalid conversion from " + type);
+ }
+ }
+
+ public boolean getValueBoolean() throws IOException {
+ switch (type) {
+ case TYPE_BOOLEAN_TRUE:
+ return true;
+ case TYPE_BOOLEAN_FALSE:
+ return false;
+ case TYPE_STRING:
+ if ("true".equalsIgnoreCase(valueString)) {
+ return true;
+ } else if ("false".equalsIgnoreCase(valueString)) {
+ return false;
+ } else {
+ throw new IOException("Invalid boolean: " + valueString);
+ }
+ default:
+ throw new IOException("Invalid conversion from " + type);
+ }
+ }
+ }
+
+ // NOTE: To support unbundled clients, we include an inlined copy
+ // of hex conversion logic from HexDump below
+ private final static char[] HEX_DIGITS =
+ { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ private static int toByte(char c) throws IOException {
+ if (c >= '0' && c <= '9') return (c - '0');
+ if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
+ if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
+ throw new IOException("Invalid hex char '" + c + "'");
+ }
+
+ static String bytesToHexString(byte[] value) {
+ final int length = value.length;
+ final char[] buf = new char[length * 2];
+ int bufIndex = 0;
+ for (int i = 0; i < length; i++) {
+ byte b = value[i];
+ buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
+ buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
+ }
+ return new String(buf);
+ }
+
+ static byte[] hexStringToBytes(String value) throws IOException {
+ final int length = value.length();
+ if (length % 2 != 0) {
+ throw new IOException("Invalid hex length " + length);
+ }
+ byte[] buffer = new byte[length / 2];
+ for (int i = 0; i < length; i += 2) {
+ buffer[i / 2] = (byte) ((toByte(value.charAt(i)) << 4)
+ | toByte(value.charAt(i + 1)));
+ }
+ return buffer;
+ }
+}
diff --git a/core/java/com/android/internal/util/BinaryXmlSerializer.java b/core/java/com/android/internal/util/BinaryXmlSerializer.java
new file mode 100644
index 000000000000..d3fcf71ba399
--- /dev/null
+++ b/core/java/com/android/internal/util/BinaryXmlSerializer.java
@@ -0,0 +1,396 @@
+/*
+ * 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.util;
+
+import static org.xmlpull.v1.XmlPullParser.CDSECT;
+import static org.xmlpull.v1.XmlPullParser.COMMENT;
+import static org.xmlpull.v1.XmlPullParser.DOCDECL;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.ENTITY_REF;
+import static org.xmlpull.v1.XmlPullParser.IGNORABLE_WHITESPACE;
+import static org.xmlpull.v1.XmlPullParser.PROCESSING_INSTRUCTION;
+import static org.xmlpull.v1.XmlPullParser.START_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import static org.xmlpull.v1.XmlPullParser.TEXT;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * Serializer that writes XML documents using a custom binary wire protocol
+ * which benchmarking has shown to be 4.3x faster and use 2.4x less disk space
+ * than {@code Xml.newFastSerializer()} for a typical {@code packages.xml}.
+ * <p>
+ * The high-level design of the wire protocol is to directly serialize the event
+ * stream, while efficiently and compactly writing strongly-typed primitives
+ * delivered through the {@link TypedXmlSerializer} interface.
+ * <p>
+ * Each serialized event is a single byte where the lower half is a normal
+ * {@link XmlPullParser} token and the upper half is an optional data type
+ * signal, such as {@link #TYPE_INT}.
+ * <p>
+ * This serializer has some specific limitations:
+ * <ul>
+ * <li>Only the UTF-8 encoding is supported.
+ * <li>Variable length values, such as {@code byte[]} or {@link String}, are
+ * limited to 65,535 bytes in length. Note that {@link String} values are stored
+ * as UTF-8 on the wire.
+ * <li>Namespaces, prefixes, properties, and options are unsupported.
+ * </ul>
+ */
+public final class BinaryXmlSerializer implements TypedXmlSerializer {
+ /**
+ * The wire protocol always begins with a well-known magic value of
+ * {@code ABX_}, representing "Android Binary XML." The final byte is a
+ * version number which may be incremented as the protocol changes.
+ */
+ static final byte[] PROTOCOL_MAGIC_VERSION_0 = new byte[] { 0x41, 0x42, 0x58, 0x00 };
+
+ /**
+ * Internal token which represents an attribute associated with the most
+ * recent {@link #START_TAG} token.
+ */
+ static final int ATTRIBUTE = 15;
+
+ static final int TYPE_NULL = 1 << 4;
+ static final int TYPE_STRING = 2 << 4;
+ static final int TYPE_STRING_INTERNED = 3 << 4;
+ static final int TYPE_BYTES_HEX = 4 << 4;
+ static final int TYPE_BYTES_BASE64 = 5 << 4;
+ static final int TYPE_INT = 6 << 4;
+ static final int TYPE_INT_HEX = 7 << 4;
+ static final int TYPE_LONG = 8 << 4;
+ static final int TYPE_LONG_HEX = 9 << 4;
+ static final int TYPE_FLOAT = 10 << 4;
+ static final int TYPE_DOUBLE = 11 << 4;
+ static final int TYPE_BOOLEAN_TRUE = 12 << 4;
+ static final int TYPE_BOOLEAN_FALSE = 13 << 4;
+
+ /**
+ * Default buffer size, which matches {@code FastXmlSerializer}. This should
+ * be kept in sync with {@link BinaryXmlPullParser}.
+ */
+ private static final int BUFFER_SIZE = 32_768;
+
+ private FastDataOutput mOut;
+
+ /**
+ * Stack of tags which are currently active via {@link #startTag} and which
+ * haven't been terminated via {@link #endTag}.
+ */
+ private int mTagCount = 0;
+ private String[] mTagNames;
+
+ /**
+ * Write the given token and optional {@link String} into our buffer.
+ */
+ private void writeToken(int token, @Nullable String text) throws IOException {
+ if (text != null) {
+ mOut.writeByte(token | TYPE_STRING);
+ mOut.writeUTF(text);
+ } else {
+ mOut.writeByte(token | TYPE_NULL);
+ }
+ }
+
+ @Override
+ public void setOutput(@NonNull OutputStream os, @Nullable String encoding) throws IOException {
+ if (encoding != null && !StandardCharsets.UTF_8.name().equals(encoding)) {
+ throw new UnsupportedOperationException();
+ }
+
+ mOut = new FastDataOutput(os, BUFFER_SIZE);
+ mOut.write(PROTOCOL_MAGIC_VERSION_0);
+
+ mTagCount = 0;
+ mTagNames = new String[8];
+ }
+
+ @Override
+ public void setOutput(Writer writer) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ mOut.flush();
+ }
+
+ @Override
+ public void startDocument(@Nullable String encoding, @Nullable Boolean standalone)
+ throws IOException {
+ if (encoding != null && !StandardCharsets.UTF_8.name().equals(encoding)) {
+ throw new UnsupportedOperationException();
+ }
+ mOut.writeByte(START_DOCUMENT | TYPE_NULL);
+ }
+
+ @Override
+ public void endDocument() throws IOException {
+ mOut.writeByte(END_DOCUMENT | TYPE_NULL);
+ flush();
+ }
+
+ @Override
+ public int getDepth() {
+ return mTagCount;
+ }
+
+ @Override
+ public String getNamespace() {
+ // Namespaces are unsupported
+ return XmlPullParser.NO_NAMESPACE;
+ }
+
+ @Override
+ public String getName() {
+ return mTagNames[mTagCount - 1];
+ }
+
+ @Override
+ public XmlSerializer startTag(String namespace, String name) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ if (mTagCount == mTagNames.length) {
+ mTagNames = Arrays.copyOf(mTagNames, mTagCount + (mTagCount >> 1));
+ }
+ mTagNames[mTagCount++] = name;
+ mOut.writeByte(START_TAG | TYPE_STRING_INTERNED);
+ mOut.writeInternedUTF(name);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer endTag(String namespace, String name) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ mTagCount--;
+ mOut.writeByte(END_TAG | TYPE_STRING_INTERNED);
+ mOut.writeInternedUTF(name);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer attribute(String namespace, String name, String value) throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ mOut.writeByte(ATTRIBUTE | TYPE_STRING);
+ mOut.writeInternedUTF(name);
+ mOut.writeUTF(value);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer attributeInterned(String namespace, String name, String value)
+ throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ mOut.writeByte(ATTRIBUTE | TYPE_STRING_INTERNED);
+ mOut.writeInternedUTF(name);
+ mOut.writeInternedUTF(value);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer attributeBytesHex(String namespace, String name, byte[] value)
+ throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ mOut.writeByte(ATTRIBUTE | TYPE_BYTES_HEX);
+ mOut.writeInternedUTF(name);
+ mOut.writeShort(value.length);
+ mOut.write(value);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer attributeBytesBase64(String namespace, String name, byte[] value)
+ throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ mOut.writeByte(ATTRIBUTE | TYPE_BYTES_BASE64);
+ mOut.writeInternedUTF(name);
+ mOut.writeShort(value.length);
+ mOut.write(value);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer attributeInt(String namespace, String name, int value)
+ throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ mOut.writeByte(ATTRIBUTE | TYPE_INT);
+ mOut.writeInternedUTF(name);
+ mOut.writeInt(value);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer attributeIntHex(String namespace, String name, int value)
+ throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ mOut.writeByte(ATTRIBUTE | TYPE_INT_HEX);
+ mOut.writeInternedUTF(name);
+ mOut.writeInt(value);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer attributeLong(String namespace, String name, long value)
+ throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ mOut.writeByte(ATTRIBUTE | TYPE_LONG);
+ mOut.writeInternedUTF(name);
+ mOut.writeLong(value);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer attributeLongHex(String namespace, String name, long value)
+ throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ mOut.writeByte(ATTRIBUTE | TYPE_LONG_HEX);
+ mOut.writeInternedUTF(name);
+ mOut.writeLong(value);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer attributeFloat(String namespace, String name, float value)
+ throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ mOut.writeByte(ATTRIBUTE | TYPE_FLOAT);
+ mOut.writeInternedUTF(name);
+ mOut.writeFloat(value);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer attributeDouble(String namespace, String name, double value)
+ throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ mOut.writeByte(ATTRIBUTE | TYPE_DOUBLE);
+ mOut.writeInternedUTF(name);
+ mOut.writeDouble(value);
+ return this;
+ }
+
+ @Override
+ public XmlSerializer attributeBoolean(String namespace, String name, boolean value)
+ throws IOException {
+ if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();
+ if (value) {
+ mOut.writeByte(ATTRIBUTE | TYPE_BOOLEAN_TRUE);
+ mOut.writeInternedUTF(name);
+ } else {
+ mOut.writeByte(ATTRIBUTE | TYPE_BOOLEAN_FALSE);
+ mOut.writeInternedUTF(name);
+ }
+ return this;
+ }
+
+ @Override
+ public XmlSerializer text(char[] buf, int start, int len) throws IOException {
+ writeToken(TEXT, new String(buf, start, len));
+ return this;
+ }
+
+ @Override
+ public XmlSerializer text(String text) throws IOException {
+ writeToken(TEXT, text);
+ return this;
+ }
+
+ @Override
+ public void cdsect(String text) throws IOException {
+ writeToken(CDSECT, text);
+ }
+
+ @Override
+ public void entityRef(String text) throws IOException {
+ writeToken(ENTITY_REF, text);
+ }
+
+ @Override
+ public void processingInstruction(String text) throws IOException {
+ writeToken(PROCESSING_INSTRUCTION, text);
+ }
+
+ @Override
+ public void comment(String text) throws IOException {
+ writeToken(COMMENT, text);
+ }
+
+ @Override
+ public void docdecl(String text) throws IOException {
+ writeToken(DOCDECL, text);
+ }
+
+ @Override
+ public void ignorableWhitespace(String text) throws IOException {
+ writeToken(IGNORABLE_WHITESPACE, text);
+ }
+
+ @Override
+ public void setFeature(String name, boolean state) {
+ // Quietly handle no-op features
+ if ("http://xmlpull.org/v1/doc/features.html#indent-output".equals(name)) {
+ return;
+ }
+ // Features are not supported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getFeature(String name) {
+ // Features are not supported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setProperty(String name, Object value) {
+ // Properties are not supported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getProperty(String name) {
+ // Properties are not supported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPrefix(String prefix, String namespace) {
+ // Prefixes are not supported
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getPrefix(String namespace, boolean generatePrefix) {
+ // Prefixes are not supported
+ throw new UnsupportedOperationException();
+ }
+
+ private static IllegalArgumentException illegalNamespace() {
+ throw new IllegalArgumentException("Namespaces are not supported");
+ }
+}
diff --git a/core/java/com/android/internal/util/FastDataInput.java b/core/java/com/android/internal/util/FastDataInput.java
new file mode 100644
index 000000000000..f8d241b5ede0
--- /dev/null
+++ b/core/java/com/android/internal/util/FastDataInput.java
@@ -0,0 +1,262 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.util.CharsetUtils;
+
+import dalvik.system.VMRuntime;
+
+import java.io.BufferedInputStream;
+import java.io.Closeable;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Optimized implementation of {@link DataInput} which buffers data in memory
+ * from the underlying {@link InputStream}.
+ * <p>
+ * Benchmarks have demonstrated this class is 3x more efficient than using a
+ * {@link DataInputStream} with a {@link BufferedInputStream}.
+ */
+public class FastDataInput implements DataInput, Closeable {
+ private static final int MAX_UNSIGNED_SHORT = 65_535;
+
+ private final VMRuntime mRuntime;
+ private final InputStream mIn;
+
+ private final byte[] mBuffer;
+ private final long mBufferPtr;
+ private final int mBufferCap;
+
+ private int mBufferPos;
+ private int mBufferLim;
+
+ /**
+ * Values that have been "interned" by {@link #readInternedUTF()}.
+ */
+ private int mStringRefCount = 0;
+ private String[] mStringRefs = new String[32];
+
+ public FastDataInput(@NonNull InputStream in, int bufferSize) {
+ mRuntime = VMRuntime.getRuntime();
+ mIn = Objects.requireNonNull(in);
+ if (bufferSize < 8) {
+ throw new IllegalArgumentException();
+ }
+
+ mBuffer = (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize);
+ mBufferPtr = mRuntime.addressOf(mBuffer);
+ mBufferCap = mBuffer.length;
+ }
+
+ private void fill(int need) throws IOException {
+ final int remain = mBufferLim - mBufferPos;
+ System.arraycopy(mBuffer, mBufferPos, mBuffer, 0, remain);
+ mBufferPos = 0;
+ mBufferLim = remain;
+ need -= remain;
+
+ while (need > 0) {
+ int c = mIn.read(mBuffer, mBufferLim, mBufferCap - mBufferLim);
+ if (c == -1) {
+ throw new EOFException();
+ } else {
+ mBufferLim += c;
+ need -= c;
+ }
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ mIn.close();
+ }
+
+ @Override
+ public void readFully(byte[] b) throws IOException {
+ readFully(b, 0, b.length);
+ }
+
+ @Override
+ public void readFully(byte[] b, int off, int len) throws IOException {
+ // Attempt to read directly from buffer space if there's enough room,
+ // otherwise fall back to chunking into place
+ if (mBufferCap >= len) {
+ if (mBufferLim - mBufferPos < len) fill(len);
+ System.arraycopy(mBuffer, mBufferPos, b, off, len);
+ mBufferPos += len;
+ } else {
+ final int remain = mBufferLim - mBufferPos;
+ System.arraycopy(mBuffer, mBufferPos, b, off, remain);
+ mBufferPos += remain;
+ off += remain;
+ len -= remain;
+
+ while (len > 0) {
+ int c = mIn.read(b, off, len);
+ if (c == -1) {
+ throw new EOFException();
+ } else {
+ off += c;
+ len -= c;
+ }
+ }
+ }
+ }
+
+ @Override
+ public String readUTF() throws IOException {
+ // Attempt to read directly from buffer space if there's enough room,
+ // otherwise fall back to chunking into place
+ final int len = readUnsignedShort();
+ if (mBufferCap > len) {
+ if (mBufferLim - mBufferPos < len) fill(len);
+ final String res = CharsetUtils.fromModifiedUtf8Bytes(mBufferPtr, mBufferPos, len);
+ mBufferPos += len;
+ return res;
+ } else {
+ final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);
+ readFully(tmp, 0, len);
+ return CharsetUtils.fromModifiedUtf8Bytes(mRuntime.addressOf(tmp), 0, len);
+ }
+ }
+
+ /**
+ * Read a {@link String} value with the additional signal that the given
+ * value is a candidate for being canonicalized, similar to
+ * {@link String#intern()}.
+ * <p>
+ * Canonicalization is implemented by writing each unique string value once
+ * the first time it appears, and then writing a lightweight {@code short}
+ * reference when that string is written again in the future.
+ *
+ * @see FastDataOutput#writeInternedUTF(String)
+ */
+ public @NonNull String readInternedUTF() throws IOException {
+ final int ref = readUnsignedShort();
+ if (ref == MAX_UNSIGNED_SHORT) {
+ final String s = readUTF();
+
+ // We can only safely intern when we have remaining values; if we're
+ // full we at least sent the string value above
+ if (mStringRefCount < MAX_UNSIGNED_SHORT) {
+ if (mStringRefCount == mStringRefs.length) {
+ mStringRefs = Arrays.copyOf(mStringRefs,
+ mStringRefCount + (mStringRefCount >> 1));
+ }
+ mStringRefs[mStringRefCount++] = s;
+ }
+
+ return s;
+ } else {
+ return mStringRefs[ref];
+ }
+ }
+
+ @Override
+ public boolean readBoolean() throws IOException {
+ return readByte() != 0;
+ }
+
+ /**
+ * Returns the same decoded value as {@link #readByte()} but without
+ * actually consuming the underlying data.
+ */
+ public byte peekByte() throws IOException {
+ if (mBufferLim - mBufferPos < 1) fill(1);
+ return mBuffer[mBufferPos];
+ }
+
+ @Override
+ public byte readByte() throws IOException {
+ if (mBufferLim - mBufferPos < 1) fill(1);
+ return mBuffer[mBufferPos++];
+ }
+
+ @Override
+ public int readUnsignedByte() throws IOException {
+ return Byte.toUnsignedInt(readByte());
+ }
+
+ @Override
+ public short readShort() throws IOException {
+ if (mBufferLim - mBufferPos < 2) fill(2);
+ return (short) (((mBuffer[mBufferPos++] & 0xff) << 8) |
+ ((mBuffer[mBufferPos++] & 0xff) << 0));
+ }
+
+ @Override
+ public int readUnsignedShort() throws IOException {
+ return Short.toUnsignedInt((short) readShort());
+ }
+
+ @Override
+ public char readChar() throws IOException {
+ return (char) readShort();
+ }
+
+ @Override
+ public int readInt() throws IOException {
+ if (mBufferLim - mBufferPos < 4) fill(4);
+ return (((mBuffer[mBufferPos++] & 0xff) << 24) |
+ ((mBuffer[mBufferPos++] & 0xff) << 16) |
+ ((mBuffer[mBufferPos++] & 0xff) << 8) |
+ ((mBuffer[mBufferPos++] & 0xff) << 0));
+ }
+
+ @Override
+ public long readLong() throws IOException {
+ if (mBufferLim - mBufferPos < 8) fill(8);
+ int h = ((mBuffer[mBufferPos++] & 0xff) << 24) |
+ ((mBuffer[mBufferPos++] & 0xff) << 16) |
+ ((mBuffer[mBufferPos++] & 0xff) << 8) |
+ ((mBuffer[mBufferPos++] & 0xff) << 0);
+ int l = ((mBuffer[mBufferPos++] & 0xff) << 24) |
+ ((mBuffer[mBufferPos++] & 0xff) << 16) |
+ ((mBuffer[mBufferPos++] & 0xff) << 8) |
+ ((mBuffer[mBufferPos++] & 0xff) << 0);
+ return (((long) h) << 32L) | ((long) l) & 0xffffffffL;
+ }
+
+ @Override
+ public float readFloat() throws IOException {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ @Override
+ public double readDouble() throws IOException {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ @Override
+ public int skipBytes(int n) throws IOException {
+ // Callers should read data piecemeal
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String readLine() throws IOException {
+ // Callers should read data piecemeal
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/core/java/com/android/internal/util/FastDataOutput.java b/core/java/com/android/internal/util/FastDataOutput.java
new file mode 100644
index 000000000000..83d26e181228
--- /dev/null
+++ b/core/java/com/android/internal/util/FastDataOutput.java
@@ -0,0 +1,236 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+import android.util.CharsetUtils;
+
+import dalvik.system.VMRuntime;
+
+import java.io.BufferedOutputStream;
+import java.io.Closeable;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Objects;
+
+/**
+ * Optimized implementation of {@link DataOutput} which buffers data in memory
+ * before flushing to the underlying {@link OutputStream}.
+ * <p>
+ * Benchmarks have demonstrated this class is 2x more efficient than using a
+ * {@link DataOutputStream} with a {@link BufferedOutputStream}.
+ */
+public class FastDataOutput implements DataOutput, Flushable, Closeable {
+ private static final int MAX_UNSIGNED_SHORT = 65_535;
+
+ private final VMRuntime mRuntime;
+ private final OutputStream mOut;
+
+ private final byte[] mBuffer;
+ private final long mBufferPtr;
+ private final int mBufferCap;
+
+ private int mBufferPos;
+
+ /**
+ * Values that have been "interned" by {@link #writeInternedUTF(String)}.
+ */
+ private HashMap<String, Short> mStringRefs = new HashMap<>();
+
+ public FastDataOutput(@NonNull OutputStream out, int bufferSize) {
+ mRuntime = VMRuntime.getRuntime();
+ mOut = Objects.requireNonNull(out);
+ if (bufferSize < 8) {
+ throw new IllegalArgumentException();
+ }
+
+ mBuffer = (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize);
+ mBufferPtr = mRuntime.addressOf(mBuffer);
+ mBufferCap = mBuffer.length;
+ }
+
+ private void drain() throws IOException {
+ if (mBufferPos > 0) {
+ mOut.write(mBuffer, 0, mBufferPos);
+ mBufferPos = 0;
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ drain();
+ mOut.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ mOut.close();
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ writeByte(b);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (mBufferCap < len) {
+ drain();
+ mOut.write(b, off, len);
+ } else {
+ if (mBufferCap - mBufferPos < len) drain();
+ System.arraycopy(b, off, mBuffer, mBufferPos, len);
+ mBufferPos += len;
+ }
+ }
+
+ @Override
+ public void writeUTF(String s) throws IOException {
+ // Attempt to write directly to buffer space if there's enough room,
+ // otherwise fall back to chunking into place
+ if (mBufferCap - mBufferPos < 2 + s.length()) drain();
+
+ // Magnitude of this returned value indicates the number of bytes
+ // required to encode the string; sign indicates success/failure
+ int len = CharsetUtils.toModifiedUtf8Bytes(s, mBufferPtr, mBufferPos + 2,
+ mBufferCap - mBufferPos - 2);
+ if (Math.abs(len) > MAX_UNSIGNED_SHORT) {
+ throw new IOException("Modified UTF-8 length too large: " + len);
+ }
+
+ if (len >= 0) {
+ // Positive value indicates the string was encoded into the buffer
+ // successfully, so we only need to prefix with length
+ writeShort(len);
+ mBufferPos += len;
+ } else {
+ // Negative value indicates buffer was too small and we need to
+ // allocate a temporary buffer for encoding
+ len = -len;
+ final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);
+ CharsetUtils.toModifiedUtf8Bytes(s, mRuntime.addressOf(tmp), 0, tmp.length);
+ writeShort(len);
+ write(tmp, 0, len);
+ }
+ }
+
+ /**
+ * Write a {@link String} value with the additional signal that the given
+ * value is a candidate for being canonicalized, similar to
+ * {@link String#intern()}.
+ * <p>
+ * Canonicalization is implemented by writing each unique string value once
+ * the first time it appears, and then writing a lightweight {@code short}
+ * reference when that string is written again in the future.
+ *
+ * @see FastDataInput#readInternedUTF()
+ */
+ public void writeInternedUTF(@NonNull String s) throws IOException {
+ Short ref = mStringRefs.get(s);
+ if (ref != null) {
+ writeShort(ref);
+ } else {
+ writeShort(MAX_UNSIGNED_SHORT);
+ writeUTF(s);
+
+ // We can only safely intern when we have remaining values; if we're
+ // full we at least sent the string value above
+ ref = (short) mStringRefs.size();
+ if (ref < MAX_UNSIGNED_SHORT) {
+ mStringRefs.put(s, ref);
+ }
+ }
+ }
+
+ @Override
+ public void writeBoolean(boolean v) throws IOException {
+ writeByte(v ? 1 : 0);
+ }
+
+ @Override
+ public void writeByte(int v) throws IOException {
+ if (mBufferCap - mBufferPos < 1) drain();
+ mBuffer[mBufferPos++] = (byte) ((v >> 0) & 0xff);
+ }
+
+ @Override
+ public void writeShort(int v) throws IOException {
+ if (mBufferCap - mBufferPos < 2) drain();
+ mBuffer[mBufferPos++] = (byte) ((v >> 8) & 0xff);
+ mBuffer[mBufferPos++] = (byte) ((v >> 0) & 0xff);
+ }
+
+ @Override
+ public void writeChar(int v) throws IOException {
+ writeShort((short) v);
+ }
+
+ @Override
+ public void writeInt(int v) throws IOException {
+ if (mBufferCap - mBufferPos < 4) drain();
+ mBuffer[mBufferPos++] = (byte) ((v >> 24) & 0xff);
+ mBuffer[mBufferPos++] = (byte) ((v >> 16) & 0xff);
+ mBuffer[mBufferPos++] = (byte) ((v >> 8) & 0xff);
+ mBuffer[mBufferPos++] = (byte) ((v >> 0) & 0xff);
+ }
+
+ @Override
+ public void writeLong(long v) throws IOException {
+ if (mBufferCap - mBufferPos < 8) drain();
+ int i = (int) (v >> 32);
+ mBuffer[mBufferPos++] = (byte) ((i >> 24) & 0xff);
+ mBuffer[mBufferPos++] = (byte) ((i >> 16) & 0xff);
+ mBuffer[mBufferPos++] = (byte) ((i >> 8) & 0xff);
+ mBuffer[mBufferPos++] = (byte) ((i >> 0) & 0xff);
+ i = (int) v;
+ mBuffer[mBufferPos++] = (byte) ((i >> 24) & 0xff);
+ mBuffer[mBufferPos++] = (byte) ((i >> 16) & 0xff);
+ mBuffer[mBufferPos++] = (byte) ((i >> 8) & 0xff);
+ mBuffer[mBufferPos++] = (byte) ((i >> 0) & 0xff);
+ }
+
+ @Override
+ public void writeFloat(float v) throws IOException {
+ writeInt(Float.floatToIntBits(v));
+ }
+
+ @Override
+ public void writeDouble(double v) throws IOException {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ @Override
+ public void writeBytes(String s) throws IOException {
+ // Callers should use writeUTF()
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void writeChars(String s) throws IOException {
+ // Callers should use writeUTF()
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index c7ac1895855b..a87e8aaa0e64 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -139,6 +139,38 @@ public class LatencyTracker {
BackgroundThread.getHandler().post(this::readSettings);
}
+ /**
+ * A helper method to translate action type to name.
+ *
+ * @param action the action type defined in AtomsProto.java
+ * @return the name of the action
+ */
+ public static String getNameOfAction(int action) {
+ // Defined in AtomsProto.java
+ switch (action) {
+ case 0:
+ return "UNKNOWN";
+ case 1:
+ return "ACTION_EXPAND_PANEL";
+ case 2:
+ return "ACTION_TOGGLE_RECENTS";
+ case 3:
+ return "ACTION_FINGERPRINT_WAKE_AND_UNLOCK";
+ case 4:
+ return "ACTION_CHECK_CREDENTIAL";
+ case 5:
+ return "ACTION_CHECK_CREDENTIAL_UNLOCKED";
+ case 6:
+ return "ACTION_TURN_ON_SCREEN";
+ case 7:
+ return "ACTION_ROTATE_SCREEN";
+ case 8:
+ return "ACTION_FACE_WAKE_AND_UNLOCK";
+ default:
+ throw new IllegalArgumentException("Invalid action");
+ }
+ }
+
private void registerSettingsObserver() {
Uri settingsUri = Settings.Global.getUriFor(Settings.Global.LATENCY_TRACKER);
mContext.getContentResolver().registerContentObserver(
diff --git a/core/java/com/android/internal/util/XmlPullParserWrapper.java b/core/java/com/android/internal/util/XmlPullParserWrapper.java
new file mode 100644
index 000000000000..efa17ef4d9cb
--- /dev/null
+++ b/core/java/com/android/internal/util/XmlPullParserWrapper.java
@@ -0,0 +1,189 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.Objects;
+
+/**
+ * Wrapper which delegates all calls through to the given {@link XmlPullParser}.
+ */
+public class XmlPullParserWrapper implements XmlPullParser {
+ private final XmlPullParser mWrapped;
+
+ public XmlPullParserWrapper(@NonNull XmlPullParser wrapped) {
+ mWrapped = Objects.requireNonNull(wrapped);
+ }
+
+ public void setFeature(String name, boolean state) throws XmlPullParserException {
+ mWrapped.setFeature(name, state);
+ }
+
+ public boolean getFeature(String name) {
+ return mWrapped.getFeature(name);
+ }
+
+ public void setProperty(String name, Object value) throws XmlPullParserException {
+ mWrapped.setProperty(name, value);
+ }
+
+ public Object getProperty(String name) {
+ return mWrapped.getProperty(name);
+ }
+
+ public void setInput(Reader in) throws XmlPullParserException {
+ mWrapped.setInput(in);
+ }
+
+ public void setInput(InputStream inputStream, String inputEncoding)
+ throws XmlPullParserException {
+ mWrapped.setInput(inputStream, inputEncoding);
+ }
+
+ public String getInputEncoding() {
+ return mWrapped.getInputEncoding();
+ }
+
+ public void defineEntityReplacementText(String entityName, String replacementText)
+ throws XmlPullParserException {
+ mWrapped.defineEntityReplacementText(entityName, replacementText);
+ }
+
+ public int getNamespaceCount(int depth) throws XmlPullParserException {
+ return mWrapped.getNamespaceCount(depth);
+ }
+
+ public String getNamespacePrefix(int pos) throws XmlPullParserException {
+ return mWrapped.getNamespacePrefix(pos);
+ }
+
+ public String getNamespaceUri(int pos) throws XmlPullParserException {
+ return mWrapped.getNamespaceUri(pos);
+ }
+
+ public String getNamespace(String prefix) {
+ return mWrapped.getNamespace(prefix);
+ }
+
+ public int getDepth() {
+ return mWrapped.getDepth();
+ }
+
+ public String getPositionDescription() {
+ return mWrapped.getPositionDescription();
+ }
+
+ public int getLineNumber() {
+ return mWrapped.getLineNumber();
+ }
+
+ public int getColumnNumber() {
+ return mWrapped.getColumnNumber();
+ }
+
+ public boolean isWhitespace() throws XmlPullParserException {
+ return mWrapped.isWhitespace();
+ }
+
+ public String getText() {
+ return mWrapped.getText();
+ }
+
+ public char[] getTextCharacters(int[] holderForStartAndLength) {
+ return mWrapped.getTextCharacters(holderForStartAndLength);
+ }
+
+ public String getNamespace() {
+ return mWrapped.getNamespace();
+ }
+
+ public String getName() {
+ return mWrapped.getName();
+ }
+
+ public String getPrefix() {
+ return mWrapped.getPrefix();
+ }
+
+ public boolean isEmptyElementTag() throws XmlPullParserException {
+ return mWrapped.isEmptyElementTag();
+ }
+
+ public int getAttributeCount() {
+ return mWrapped.getAttributeCount();
+ }
+
+ public String getAttributeNamespace(int index) {
+ return mWrapped.getAttributeNamespace(index);
+ }
+
+ public String getAttributeName(int index) {
+ return mWrapped.getAttributeName(index);
+ }
+
+ public String getAttributePrefix(int index) {
+ return mWrapped.getAttributePrefix(index);
+ }
+
+ public String getAttributeType(int index) {
+ return mWrapped.getAttributeType(index);
+ }
+
+ public boolean isAttributeDefault(int index) {
+ return mWrapped.isAttributeDefault(index);
+ }
+
+ public String getAttributeValue(int index) {
+ return mWrapped.getAttributeValue(index);
+ }
+
+ public String getAttributeValue(String namespace, String name) {
+ return mWrapped.getAttributeValue(namespace, name);
+ }
+
+ public int getEventType() throws XmlPullParserException {
+ return mWrapped.getEventType();
+ }
+
+ public int next() throws XmlPullParserException, IOException {
+ return mWrapped.next();
+ }
+
+ public int nextToken() throws XmlPullParserException, IOException {
+ return mWrapped.nextToken();
+ }
+
+ public void require(int type, String namespace, String name)
+ throws XmlPullParserException, IOException {
+ mWrapped.require(type, namespace, name);
+ }
+
+ public String nextText() throws XmlPullParserException, IOException {
+ return mWrapped.nextText();
+ }
+
+ public int nextTag() throws XmlPullParserException, IOException {
+ return mWrapped.nextTag();
+ }
+}
diff --git a/core/java/com/android/internal/util/XmlSerializerWrapper.java b/core/java/com/android/internal/util/XmlSerializerWrapper.java
new file mode 100644
index 000000000000..2131db0cfb6f
--- /dev/null
+++ b/core/java/com/android/internal/util/XmlSerializerWrapper.java
@@ -0,0 +1,140 @@
+/*
+ * 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.util;
+
+import android.annotation.NonNull;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.util.Objects;
+
+/**
+ * Wrapper which delegates all calls through to the given {@link XmlSerializer}.
+ */
+public class XmlSerializerWrapper {
+ private final XmlSerializer mWrapped;
+
+ public XmlSerializerWrapper(@NonNull XmlSerializer wrapped) {
+ mWrapped = Objects.requireNonNull(wrapped);
+ }
+
+ public void setFeature(String name, boolean state) {
+ mWrapped.setFeature(name, state);
+ }
+
+ public boolean getFeature(String name) {
+ return mWrapped.getFeature(name);
+ }
+
+ public void setProperty(String name, Object value) {
+ mWrapped.setProperty(name, value);
+ }
+
+ public Object getProperty(String name) {
+ return mWrapped.getProperty(name);
+ }
+
+ public void setOutput(OutputStream os, String encoding) throws IOException {
+ mWrapped.setOutput(os, encoding);
+ }
+
+ public void setOutput(Writer writer)
+ throws IOException, IllegalArgumentException, IllegalStateException {
+ mWrapped.setOutput(writer);
+ }
+
+ public void startDocument(String encoding, Boolean standalone) throws IOException {
+ mWrapped.startDocument(encoding, standalone);
+ }
+
+ public void endDocument() throws IOException {
+ mWrapped.endDocument();
+ }
+
+ public void setPrefix(String prefix, String namespace) throws IOException {
+ mWrapped.setPrefix(prefix, namespace);
+ }
+
+ public String getPrefix(String namespace, boolean generatePrefix) {
+ return mWrapped.getPrefix(namespace, generatePrefix);
+ }
+
+ public int getDepth() {
+ return mWrapped.getDepth();
+ }
+
+ public String getNamespace() {
+ return mWrapped.getNamespace();
+ }
+
+ public String getName() {
+ return mWrapped.getName();
+ }
+
+ public XmlSerializer startTag(String namespace, String name) throws IOException {
+ return mWrapped.startTag(namespace, name);
+ }
+
+ public XmlSerializer attribute(String namespace, String name, String value)
+ throws IOException {
+ return mWrapped.attribute(namespace, name, value);
+ }
+
+ public XmlSerializer endTag(String namespace, String name) throws IOException {
+ return mWrapped.endTag(namespace, name);
+ }
+
+ public XmlSerializer text(String text) throws IOException{
+ return mWrapped.text(text);
+ }
+
+ public XmlSerializer text(char[] buf, int start, int len) throws IOException {
+ return mWrapped.text(buf, start, len);
+ }
+
+ public void cdsect(String text)
+ throws IOException, IllegalArgumentException, IllegalStateException {
+ mWrapped.cdsect(text);
+ }
+
+ public void entityRef(String text) throws IOException {
+ mWrapped.entityRef(text);
+ }
+
+ public void processingInstruction(String text) throws IOException {
+ mWrapped.processingInstruction(text);
+ }
+
+ public void comment(String text) throws IOException {
+ mWrapped.comment(text);
+ }
+
+ public void docdecl(String text) throws IOException {
+ mWrapped.docdecl(text);
+ }
+
+ public void ignorableWhitespace(String text) throws IOException {
+ mWrapped.ignorableWhitespace(text);
+ }
+
+ public void flush() throws IOException {
+ mWrapped.flush();
+ }
+}
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index bd6b950623eb..cdd0e04b0fad 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -16,6 +16,7 @@
package com.android.internal.util;
+import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
@@ -24,6 +25,8 @@ import android.net.Uri;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Base64;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
import android.util.Xml;
import libcore.util.HexEncoding;
@@ -48,9 +51,193 @@ import java.util.Set;
/** {@hide} */
public class XmlUtils {
-
private static final String STRING_ARRAY_SEPARATOR = ":";
+ private static class ForcedTypedXmlSerializer extends XmlSerializerWrapper
+ implements TypedXmlSerializer {
+ public ForcedTypedXmlSerializer(XmlSerializer wrapped) {
+ super(wrapped);
+ }
+
+ @Override
+ public XmlSerializer attributeInterned(String namespace, String name, String value)
+ throws IOException {
+ return attribute(namespace, name, value);
+ }
+
+ @Override
+ public XmlSerializer attributeBytesHex(String namespace, String name, byte[] value)
+ throws IOException {
+ return attribute(namespace, name, HexDump.toHexString(value));
+ }
+
+ @Override
+ public XmlSerializer attributeBytesBase64(String namespace, String name, byte[] value)
+ throws IOException {
+ return attribute(namespace, name, Base64.encodeToString(value, Base64.NO_WRAP));
+ }
+
+ @Override
+ public XmlSerializer attributeInt(String namespace, String name, int value)
+ throws IOException {
+ return attribute(namespace, name, Integer.toString(value));
+ }
+
+ @Override
+ public XmlSerializer attributeIntHex(String namespace, String name, int value)
+ throws IOException {
+ return attribute(namespace, name, Integer.toString(value, 16));
+ }
+
+ @Override
+ public XmlSerializer attributeLong(String namespace, String name, long value)
+ throws IOException {
+ return attribute(namespace, name, Long.toString(value));
+ }
+
+ @Override
+ public XmlSerializer attributeLongHex(String namespace, String name, long value)
+ throws IOException {
+ return attribute(namespace, name, Long.toString(value, 16));
+ }
+
+ @Override
+ public XmlSerializer attributeFloat(String namespace, String name, float value)
+ throws IOException {
+ return attribute(namespace, name, Float.toString(value));
+ }
+
+ @Override
+ public XmlSerializer attributeDouble(String namespace, String name, double value)
+ throws IOException {
+ return attribute(namespace, name, Double.toString(value));
+ }
+
+ @Override
+ public XmlSerializer attributeBoolean(String namespace, String name, boolean value)
+ throws IOException {
+ return attribute(namespace, name, Boolean.toString(value));
+ }
+ }
+
+ /**
+ * Return a specialization of the given {@link XmlSerializer} which has
+ * explicit methods to support consistent and efficient conversion of
+ * primitive data types.
+ */
+ public static @NonNull TypedXmlSerializer makeTyped(@NonNull XmlSerializer xml) {
+ if (xml instanceof TypedXmlSerializer) {
+ return (TypedXmlSerializer) xml;
+ } else {
+ return new ForcedTypedXmlSerializer(xml);
+ }
+ }
+
+ private static class ForcedTypedXmlPullParser extends XmlPullParserWrapper
+ implements TypedXmlPullParser {
+ public ForcedTypedXmlPullParser(XmlPullParser wrapped) {
+ super(wrapped);
+ }
+
+ @Override
+ public byte[] getAttributeBytesHex(String namespace, String name) throws IOException {
+ try {
+ return HexDump.hexStringToByteArray(getAttributeValue(namespace, name));
+ } catch (Exception e) {
+ throw new IOException("Invalid attribute " + name, e);
+ }
+ }
+
+ @Override
+ public byte[] getAttributeBytesBase64(String namespace, String name) throws IOException {
+ try {
+ return Base64.decode(getAttributeValue(namespace, name), Base64.NO_WRAP);
+ } catch (Exception e) {
+ throw new IOException("Invalid attribute " + name, e);
+ }
+ }
+
+ @Override
+ public int getAttributeInt(String namespace, String name) throws IOException {
+ try {
+ return Integer.parseInt(getAttributeValue(namespace, name));
+ } catch (NumberFormatException e) {
+ throw new IOException("Invalid attribute " + name, e);
+ }
+ }
+
+ @Override
+ public int getAttributeIntHex(String namespace, String name) throws IOException {
+ try {
+ return Integer.parseInt(getAttributeValue(namespace, name), 16);
+ } catch (NumberFormatException e) {
+ throw new IOException("Invalid attribute " + name, e);
+ }
+ }
+
+ @Override
+ public long getAttributeLong(String namespace, String name) throws IOException {
+ try {
+ return Long.parseLong(getAttributeValue(namespace, name));
+ } catch (NumberFormatException e) {
+ throw new IOException("Invalid attribute " + name, e);
+ }
+ }
+
+ @Override
+ public long getAttributeLongHex(String namespace, String name) throws IOException {
+ try {
+ return Long.parseLong(getAttributeValue(namespace, name), 16);
+ } catch (NumberFormatException e) {
+ throw new IOException("Invalid attribute " + name, e);
+ }
+ }
+
+ @Override
+ public float getAttributeFloat(String namespace, String name) throws IOException {
+ try {
+ return Float.parseFloat(getAttributeValue(namespace, name));
+ } catch (NumberFormatException e) {
+ throw new IOException("Invalid attribute " + name, e);
+ }
+ }
+
+ @Override
+ public double getAttributeDouble(String namespace, String name) throws IOException {
+ try {
+ return Double.parseDouble(getAttributeValue(namespace, name));
+ } catch (NumberFormatException e) {
+ throw new IOException("Invalid attribute " + name, e);
+ }
+ }
+
+ @Override
+ public boolean getAttributeBoolean(String namespace, String name) throws IOException {
+ final String value = getAttributeValue(namespace, name);
+ if ("true".equalsIgnoreCase(value)) {
+ return true;
+ } else if ("false".equalsIgnoreCase(value)) {
+ return false;
+ } else {
+ throw new IOException("Invalid attribute " + name,
+ new IllegalArgumentException("For input string: \"" + value + "\""));
+ }
+ }
+ }
+
+ /**
+ * Return a specialization of the given {@link XmlPullParser} which has
+ * explicit methods to support consistent and efficient conversion of
+ * primitive data types.
+ */
+ public static @NonNull TypedXmlPullParser makeTyped(@NonNull XmlPullParser xml) {
+ if (xml instanceof TypedXmlPullParser) {
+ return (TypedXmlPullParser) xml;
+ } else {
+ return new ForcedTypedXmlPullParser(xml);
+ }
+ }
+
@UnsupportedAppUsage
public static void skipCurrentTag(XmlPullParser parser)
throws XmlPullParserException, IOException {
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 633d6848030e..36913b729f1b 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -29,8 +29,8 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
-
import android.widget.PopupWindow;
+
import com.android.internal.R;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.widget.FloatingToolbar;
@@ -148,16 +148,21 @@ public final class FloatingActionMode extends ActionMode {
@Override
public void invalidateContentRect() {
mCallback.onGetContentRect(this, mOriginatingView, mContentRect);
- repositionToolbar();
+ updateViewLocationInWindow(/* forceRepositionToolbar= */ true);
}
public void updateViewLocationInWindow() {
+ updateViewLocationInWindow(/* forceRepositionToolbar= */ false);
+ }
+
+ private void updateViewLocationInWindow(boolean forceRepositionToolbar) {
mOriginatingView.getLocationOnScreen(mViewPositionOnScreen);
mOriginatingView.getRootView().getLocationOnScreen(mRootViewPositionOnScreen);
mOriginatingView.getGlobalVisibleRect(mViewRectOnScreen);
mViewRectOnScreen.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]);
- if (!Arrays.equals(mViewPositionOnScreen, mPreviousViewPositionOnScreen)
+ if (forceRepositionToolbar
+ || !Arrays.equals(mViewPositionOnScreen, mPreviousViewPositionOnScreen)
|| !mViewRectOnScreen.equals(mPreviousViewRectOnScreen)) {
repositionToolbar();
mPreviousViewPositionOnScreen[0] = mViewPositionOnScreen[0];
@@ -192,10 +197,15 @@ public final class FloatingActionMode extends ActionMode {
mViewRectOnScreen.bottom + mBottomAllowance));
if (!mContentRectOnScreen.equals(mPreviousContentRectOnScreen)) {
- // Content rect is moving.
- mOriginatingView.removeCallbacks(mMovingOff);
- mFloatingToolbarVisibilityHelper.setMoving(true);
- mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
+ // Content rect is moving
+ if (!mPreviousContentRectOnScreen.isEmpty()) {
+ mOriginatingView.removeCallbacks(mMovingOff);
+ mFloatingToolbarVisibilityHelper.setMoving(true);
+ mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
+ } else {
+ // mPreviousContentRectOnScreen is empty. That means we are are showing the
+ // toolbar rather than moving it. And we should show it right away.
+ }
mFloatingToolbar.setContentRect(mContentRectOnScreen);
mFloatingToolbar.updateLayout();
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index e05aa8351681..ec4fe17746ee 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -37,6 +37,7 @@ import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.SurroundingText;
import com.android.internal.inputmethod.CancellationGroup;
+import com.android.internal.inputmethod.Completable;
import com.android.internal.inputmethod.ResultCallbacks;
import java.lang.ref.WeakReference;
@@ -85,9 +86,10 @@ public class InputConnectionWrapper implements InputConnection {
}
@AnyThread
- private static int getResultOrZero(@NonNull CancellationGroup.Completable.Int value,
- @NonNull String methodName) {
- final boolean timedOut = value.await(MAX_WAIT_TIME_MILLIS, TimeUnit.MILLISECONDS);
+ private static int getResultOrZero(@NonNull Completable.Int value, @NonNull String methodName,
+ @Nullable CancellationGroup cancellationGroup) {
+ final boolean timedOut =
+ value.await(MAX_WAIT_TIME_MILLIS, TimeUnit.MILLISECONDS, cancellationGroup);
if (value.hasValue()) {
return value.getValue();
}
@@ -97,9 +99,10 @@ public class InputConnectionWrapper implements InputConnection {
@AnyThread
@Nullable
- private static <T> T getResultOrNull(@NonNull CancellationGroup.Completable.Values<T> value,
- @NonNull String methodName) {
- final boolean timedOut = value.await(MAX_WAIT_TIME_MILLIS, TimeUnit.MILLISECONDS);
+ private static <T> T getResultOrNull(@NonNull Completable.Values<T> value,
+ @NonNull String methodName, @Nullable CancellationGroup cancellationGroup) {
+ final boolean timedOut =
+ value.await(MAX_WAIT_TIME_MILLIS, TimeUnit.MILLISECONDS, cancellationGroup);
if (value.hasValue()) {
return value.getValue();
}
@@ -117,14 +120,13 @@ public class InputConnectionWrapper implements InputConnection {
return null;
}
- final CancellationGroup.Completable.CharSequence value =
- mCancellationGroup.createCompletableCharSequence();
+ final Completable.CharSequence value = Completable.createCharSequence();
try {
mIInputContext.getTextAfterCursor(length, flags, ResultCallbacks.of(value));
} catch (RemoteException e) {
return null;
}
- return getResultOrNull(value, "getTextAfterCursor()");
+ return getResultOrNull(value, "getTextAfterCursor()", mCancellationGroup);
}
/**
@@ -137,14 +139,13 @@ public class InputConnectionWrapper implements InputConnection {
return null;
}
- final CancellationGroup.Completable.CharSequence value =
- mCancellationGroup.createCompletableCharSequence();
+ final Completable.CharSequence value = Completable.createCharSequence();
try {
mIInputContext.getTextBeforeCursor(length, flags, ResultCallbacks.of(value));
} catch (RemoteException e) {
return null;
}
- return getResultOrNull(value, "getTextBeforeCursor()");
+ return getResultOrNull(value, "getTextBeforeCursor()", mCancellationGroup);
}
@AnyThread
@@ -157,14 +158,13 @@ public class InputConnectionWrapper implements InputConnection {
// This method is not implemented.
return null;
}
- final CancellationGroup.Completable.CharSequence value =
- mCancellationGroup.createCompletableCharSequence();
+ final Completable.CharSequence value = Completable.createCharSequence();
try {
mIInputContext.getSelectedText(flags, ResultCallbacks.of(value));
} catch (RemoteException e) {
return null;
}
- return getResultOrNull(value, "getSelectedText()");
+ return getResultOrNull(value, "getSelectedText()", mCancellationGroup);
}
/**
@@ -190,15 +190,14 @@ public class InputConnectionWrapper implements InputConnection {
// This method is not implemented.
return null;
}
- final CancellationGroup.Completable.SurroundingText value =
- mCancellationGroup.createCompletableSurroundingText();
+ final Completable.SurroundingText value = Completable.createSurroundingText();
try {
mIInputContext.getSurroundingText(beforeLength, afterLength, flags,
ResultCallbacks.of(value));
} catch (RemoteException e) {
return null;
}
- return getResultOrNull(value, "getSurroundingText()");
+ return getResultOrNull(value, "getSurroundingText()", mCancellationGroup);
}
@AnyThread
@@ -207,14 +206,13 @@ public class InputConnectionWrapper implements InputConnection {
return 0;
}
- final CancellationGroup.Completable.Int value =
- mCancellationGroup.createCompletableInt();
+ final Completable.Int value = Completable.createInt();
try {
mIInputContext.getCursorCapsMode(reqModes, ResultCallbacks.of(value));
} catch (RemoteException e) {
return 0;
}
- return getResultOrZero(value, "getCursorCapsMode()");
+ return getResultOrZero(value, "getCursorCapsMode()", mCancellationGroup);
}
@AnyThread
@@ -223,14 +221,13 @@ public class InputConnectionWrapper implements InputConnection {
return null;
}
- final CancellationGroup.Completable.ExtractedText value =
- mCancellationGroup.createCompletableExtractedText();
+ final Completable.ExtractedText value = Completable.createExtractedText();
try {
mIInputContext.getExtractedText(request, flags, ResultCallbacks.of(value));
} catch (RemoteException e) {
return null;
}
- return getResultOrNull(value, "getExtractedText()");
+ return getResultOrNull(value, "getExtractedText()", mCancellationGroup);
}
@AnyThread
@@ -434,14 +431,14 @@ public class InputConnectionWrapper implements InputConnection {
// This method is not implemented.
return false;
}
- final CancellationGroup.Completable.Int value = mCancellationGroup.createCompletableInt();
+ final Completable.Int value = Completable.createInt();
try {
mIInputContext.requestUpdateCursorAnchorInfo(cursorUpdateMode,
ResultCallbacks.of(value));
} catch (RemoteException e) {
return false;
}
- return getResultOrZero(value, "requestUpdateCursorAnchorInfo()") != 0;
+ return getResultOrZero(value, "requestUpdateCursorAnchorInfo()", mCancellationGroup) != 0;
}
@AnyThread
@@ -475,13 +472,13 @@ public class InputConnectionWrapper implements InputConnection {
inputMethodService.exposeContent(inputContentInfo, this);
}
- final CancellationGroup.Completable.Int value = mCancellationGroup.createCompletableInt();
+ final Completable.Int value = Completable.createInt();
try {
mIInputContext.commitContent(inputContentInfo, flags, opts, ResultCallbacks.of(value));
} catch (RemoteException e) {
return false;
}
- return getResultOrZero(value, "commitContent()") != 0;
+ return getResultOrZero(value, "commitContent()", mCancellationGroup) != 0;
}
@AnyThread
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index d7611dcd0aa0..58817a8a48a9 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -261,18 +261,14 @@ public final class FloatingToolbar {
/**
* If this is set to true, the action mode view will dismiss itself on touch events outside of
- * its window. If the toolbar is already showing, it will be re-shown so that this setting takes
- * effect immediately.
+ * its window. The setting takes effect immediately.
*
* @param outsideTouchable whether or not this action mode is "outside touchable"
* @param onDismiss optional. Sets a callback for when this action mode popup dismisses itself
*/
public void setOutsideTouchable(
boolean outsideTouchable, @Nullable PopupWindow.OnDismissListener onDismiss) {
- if (mPopup.setOutsideTouchable(outsideTouchable, onDismiss) && isShowing()) {
- dismiss();
- doShow();
- }
+ mPopup.setOutsideTouchable(outsideTouchable, onDismiss);
}
private void doShow() {
@@ -530,7 +526,6 @@ public final class FloatingToolbar {
/**
* Makes this toolbar "outside touchable" and sets the onDismissListener.
- * This will take effect the next time the toolbar is re-shown.
*
* @param outsideTouchable if true, the popup will be made "outside touchable" and
* "non focusable". The reverse will happen if false.
@@ -548,6 +543,7 @@ public final class FloatingToolbar {
if (mPopupWindow.isOutsideTouchable() ^ outsideTouchable) {
mPopupWindow.setOutsideTouchable(outsideTouchable);
mPopupWindow.setFocusable(!outsideTouchable);
+ mPopupWindow.update();
ret = true;
}
mPopupWindow.setOnDismissListener(onDismiss);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 1123f20c3e7e..8c83d7c828de 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -134,6 +134,7 @@ cc_library_shared {
"android_service_DataLoaderService.cpp",
"android_util_AssetManager.cpp",
"android_util_Binder.cpp",
+ "android_util_CharsetUtils.cpp",
"android_util_MemoryIntArray.cpp",
"android_util_Process.cpp",
"android_media_AudioDeviceAttributes.cpp",
@@ -204,6 +205,9 @@ cc_library_shared {
],
shared_libs: [
+ "audioclient-types-aidl-unstable-cpp",
+ "audioflinger-aidl-unstable-cpp",
+ "av-types-aidl-unstable-cpp",
"libandroidicu",
"libbpf_android",
"libnetdbpf",
@@ -334,9 +338,6 @@ cc_library_shared {
"libhidlbase", // libhwbinder is in here
],
},
- windows: {
- enabled: true,
- },
},
product_variables: {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 27b23bd05e1f..14e74a840b21 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -105,6 +105,7 @@ namespace android {
*/
extern int register_android_app_admin_SecurityLog(JNIEnv* env);
extern int register_android_content_AssetManager(JNIEnv* env);
+extern int register_android_util_CharsetUtils(JNIEnv* env);
extern int register_android_util_EventLog(JNIEnv* env);
extern int register_android_util_Log(JNIEnv* env);
extern int register_android_util_MemoryIntArray(JNIEnv* env);
@@ -1449,6 +1450,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
REG_JNI(register_android_os_SystemClock),
+ REG_JNI(register_android_util_CharsetUtils),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_MemoryIntArray),
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index fbdd4060d7f2..444bb668dc57 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -24,6 +24,7 @@
#include "utils/misc.h"
#include "utils/Trace.h"
+#include "android_util_AssetManager_private.h"
#include "core_jni_helpers.h"
#include "jni.h"
#include "nativehelper/ScopedUtfChars.h"
@@ -347,12 +348,17 @@ static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring fil
return 0;
}
+ const auto buffer = asset->getIncFsBuffer(true /* aligned */);
+ const size_t length = asset->getLength();
+ if (!buffer.convert<uint8_t>().verify(length)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return 0;
+ }
+
// DynamicRefTable is only needed when looking up resource references. Opening an XML file
// directly from an ApkAssets has no notion of proper resource references.
- std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
- status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
- asset.reset();
-
+ auto xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
+ status_t err = xml_tree->setTo(buffer.unsafe_ptr(), length, true);
if (err != NO_ERROR) {
jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index 7756a62df655..995bfa97ab2e 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -54,26 +54,28 @@ jobject NativeInputApplicationHandle::getInputApplicationHandleObjLocalRef(JNIEn
bool NativeInputApplicationHandle::updateInfo() {
JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject obj = env->NewLocalRef(mObjWeak);
- if (!obj) {
+ ScopedLocalRef<jobject> obj(env, env->NewLocalRef(mObjWeak));
+ if (!obj.get()) {
return false;
}
+ if (mInfo.token.get() != nullptr) {
+ // The java fields are immutable, so it doesn't need to update again.
+ return true;
+ }
- mInfo.name = getStringField(env, obj, gInputApplicationHandleClassInfo.name, "<null>");
+ mInfo.name = getStringField(env, obj.get(), gInputApplicationHandleClassInfo.name, "<null>");
mInfo.dispatchingTimeoutMillis =
- env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutMillis);
+ env->GetLongField(obj.get(), gInputApplicationHandleClassInfo.dispatchingTimeoutMillis);
- jobject tokenObj = env->GetObjectField(obj,
- gInputApplicationHandleClassInfo.token);
- if (tokenObj) {
- mInfo.token = ibinderForJavaObject(env, tokenObj);
- env->DeleteLocalRef(tokenObj);
+ ScopedLocalRef<jobject> tokenObj(env, env->GetObjectField(obj.get(),
+ gInputApplicationHandleClassInfo.token));
+ if (tokenObj.get()) {
+ mInfo.token = ibinderForJavaObject(env, tokenObj.get());
} else {
mInfo.token.clear();
}
- env->DeleteLocalRef(obj);
return mInfo.token.get() != nullptr;
}
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index b1b39f3e36ff..5f2dcdf975b6 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -39,6 +39,8 @@
#define ENCODING_E_AC3_JOC 18
#define ENCODING_DOLBY_MAT 19
#define ENCODING_OPUS 20
+#define ENCODING_PCM_24BIT_PACKED 21
+#define ENCODING_PCM_32BIT 22
#define ENCODING_INVALID 0
#define ENCODING_DEFAULT 1
@@ -92,6 +94,10 @@ static inline audio_format_t audioFormatToNative(int audioFormat)
return AUDIO_FORMAT_MAT;
case ENCODING_OPUS:
return AUDIO_FORMAT_OPUS;
+ case ENCODING_PCM_24BIT_PACKED:
+ return AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ case ENCODING_PCM_32BIT:
+ return AUDIO_FORMAT_PCM_32_BIT;
default:
return AUDIO_FORMAT_INVALID;
}
@@ -107,10 +113,15 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat)
case AUDIO_FORMAT_PCM_FLOAT:
return ENCODING_PCM_FLOAT;
- // map these to ENCODING_PCM_FLOAT
- case AUDIO_FORMAT_PCM_8_24_BIT:
+ // As of S, these extend integer precision formats now return more specific values
+ // than ENCODING_PCM_FLOAT.
case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ return ENCODING_PCM_24BIT_PACKED;
case AUDIO_FORMAT_PCM_32_BIT:
+ return ENCODING_PCM_32BIT;
+
+ // map this to ENCODING_PCM_FLOAT
+ case AUDIO_FORMAT_PCM_8_24_BIT:
return ENCODING_PCM_FLOAT;
case AUDIO_FORMAT_AC3:
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 355ef0cd6b3f..787d34822ef7 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -90,6 +90,14 @@ void recycleJavaParcelObject(JNIEnv* env, jobject parcelObj)
env->CallVoidMethod(parcelObj, gParcelOffsets.recycle);
}
+static void android_os_Parcel_markSensitive(jlong nativePtr)
+{
+ Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
+ if (parcel) {
+ parcel->markSensitive();
+ }
+}
+
static jint android_os_Parcel_dataSize(jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
@@ -252,20 +260,25 @@ static void android_os_Parcel_nativeSignalExceptionForError(JNIEnv* env, jclass
signalExceptionForError(env, clazz, err);
}
-static void android_os_Parcel_writeString8(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val)
-{
+static void android_os_Parcel_writeString8(JNIEnv *env, jclass clazz, jlong nativePtr,
+ jstring val) {
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
- if (parcel != NULL) {
- status_t err = NO_MEMORY;
+ if (parcel != nullptr) {
+ status_t err = NO_ERROR;
if (val) {
- const size_t len = env->GetStringUTFLength(val);
- const char* str = env->GetStringUTFChars(val, 0);
- if (str) {
- err = parcel->writeString8(str, len);
- env->ReleaseStringUTFChars(val, str);
+ // NOTE: Keep this logic in sync with Parcel.cpp
+ const size_t len = env->GetStringLength(val);
+ const size_t allocLen = env->GetStringUTFLength(val);
+ err = parcel->writeInt32(allocLen);
+ char *data = reinterpret_cast<char*>(parcel->writeInplace(allocLen + sizeof(char)));
+ if (data != nullptr) {
+ env->GetStringUTFRegion(val, 0, len, data);
+ *(data + allocLen) = 0;
+ } else {
+ err = NO_MEMORY;
}
} else {
- err = parcel->writeString8(NULL, 0);
+ err = parcel->writeString8(nullptr, 0);
}
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
@@ -273,21 +286,25 @@ static void android_os_Parcel_writeString8(JNIEnv* env, jclass clazz, jlong nati
}
}
-static void android_os_Parcel_writeString16(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val)
-{
+static void android_os_Parcel_writeString16(JNIEnv *env, jclass clazz, jlong nativePtr,
+ jstring val) {
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
- if (parcel != NULL) {
- status_t err = NO_MEMORY;
+ if (parcel != nullptr) {
+ status_t err = NO_ERROR;
if (val) {
- const jchar* str = env->GetStringCritical(val, 0);
- if (str) {
- err = parcel->writeString16(
- reinterpret_cast<const char16_t*>(str),
- env->GetStringLength(val));
- env->ReleaseStringCritical(val, str);
+ // NOTE: Keep this logic in sync with Parcel.cpp
+ const size_t len = env->GetStringLength(val);
+ const size_t allocLen = len * sizeof(char16_t);
+ err = parcel->writeInt32(len);
+ char *data = reinterpret_cast<char*>(parcel->writeInplace(allocLen + sizeof(char16_t)));
+ if (data != nullptr) {
+ env->GetStringRegion(val, 0, len, reinterpret_cast<jchar*>(data));
+ *reinterpret_cast<char16_t*>(data + allocLen) = 0;
+ } else {
+ err = NO_MEMORY;
}
} else {
- err = parcel->writeString16(NULL, 0);
+ err = parcel->writeString16(nullptr, 0);
}
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
@@ -732,6 +749,8 @@ static jboolean android_os_Parcel_replaceCallingWorkSourceUid(jlong nativePtr, j
static const JNINativeMethod gParcelMethods[] = {
// @CriticalNative
+ {"nativeMarkSensitive", "(J)V", (void*)android_os_Parcel_markSensitive},
+ // @CriticalNative
{"nativeDataSize", "(J)I", (void*)android_os_Parcel_dataSize},
// @CriticalNative
{"nativeDataAvail", "(J)I", (void*)android_os_Parcel_dataAvail},
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index efca33aaf520..b2c69a0aeafd 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -42,6 +42,7 @@
#include "androidfw/ResourceTypes.h"
#include "androidfw/ResourceUtils.h"
+#include "android_util_AssetManager_private.h"
#include "core_jni_helpers.h"
#include "jni.h"
#include "nativehelper/JNIPlatformHelp.h"
@@ -112,19 +113,17 @@ constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie)
return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
}
-static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
- uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
- env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
+static jint CopyValue(JNIEnv* env, const AssetManager2::SelectedValue& value,
+ jobject out_typed_value) {
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.type);
env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
- ApkAssetsCookieToJavaCookie(cookie));
+ ApkAssetsCookieToJavaCookie(value.cookie));
env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
- env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
- env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
- if (config != nullptr) {
- env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
- }
- return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, value.resid);
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, value.flags);
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, value.config.density);
+ return static_cast<jint>(ApkAssetsCookieToJavaCookie(value.cookie));
}
// ----------------------------------------------------------------------------
@@ -569,15 +568,15 @@ static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint
return 0;
}
- // May be nullptr.
- std::shared_ptr<const DynamicRefTable> dynamic_ref_table =
- assetmanager->GetDynamicRefTableForCookie(cookie);
-
- std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(
- std::move(dynamic_ref_table));
- status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
- asset.reset();
+ const incfs::map_ptr<void> buffer = asset->getIncFsBuffer(true /* aligned */);
+ const size_t length = asset->getLength();
+ if (!buffer.convert<uint8_t>().verify(length)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return 0;
+ }
+ auto xml_tree = util::make_unique<ResXMLTree>(assetmanager->GetDynamicRefTableForCookie(cookie));
+ status_t err = xml_tree->setTo(buffer.unsafe_ptr(), length, true);
if (err != NO_ERROR) {
jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
@@ -606,15 +605,15 @@ static jlong NativeOpenXmlAssetFd(JNIEnv* env, jobject /*clazz*/, jlong ptr, int
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
- // May be nullptr.
- std::shared_ptr<const DynamicRefTable> dynamic_ref_table =
- assetmanager->GetDynamicRefTableForCookie(cookie);
-
- std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(
- std::move(dynamic_ref_table));
- status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
- asset.reset();
+ const incfs::map_ptr<void> buffer = asset->getIncFsBuffer(true /* aligned */);
+ const size_t length = asset->getLength();
+ if (!buffer.convert<uint8_t>().verify(length)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return 0;
+ }
+ auto xml_tree = util::make_unique<ResXMLTree>(assetmanager->GetDynamicRefTableForCookie(cookie));
+ status_t err = xml_tree->setTo(buffer.unsafe_ptr(), length, true);
if (err != NO_ERROR) {
jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
@@ -626,67 +625,62 @@ static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin
jshort density, jobject typed_value,
jboolean resolve_references) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- ApkAssetsCookie cookie =
- assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
- static_cast<uint16_t>(density), &value, &selected_config, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
+ static_cast<uint16_t>(density));
+ if (!value.has_value()) {
+ ThrowIfIOError(env, value);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- uint32_t ref = static_cast<uint32_t>(resid);
if (resolve_references) {
- cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ auto result = assetmanager->ResolveReference(value.value());
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
}
- return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
+ return CopyValue(env, *value, typed_value);
}
static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
jint bag_entry_id, jobject typed_value) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag.has_value()) {
+ ThrowIfIOError(env, bag);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- uint32_t type_spec_flags = bag->type_spec_flags;
- ApkAssetsCookie cookie = kInvalidCookie;
- const Res_value* bag_value = nullptr;
- for (const ResolvedBag::Entry& entry : bag) {
- if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
- cookie = entry.cookie;
- bag_value = &entry.value;
-
- // Keep searching (the old implementation did that).
- }
- }
+ // The legacy would find the last entry with the target bag entry id
+ using reverse_bag_iterator = std::reverse_iterator<const ResolvedBag::Entry*>;
+ const auto rbegin = reverse_bag_iterator(end(*bag));
+ const auto rend = reverse_bag_iterator(begin(*bag));
+ auto entry = std::find_if(rbegin, rend, [bag_entry_id](auto&& e) {
+ return e.key == static_cast<uint32_t>(bag_entry_id);
+ });
- if (cookie == kInvalidCookie) {
+ if (entry == rend) {
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- Res_value value = *bag_value;
- uint32_t ref = static_cast<uint32_t>(resid);
- ResTable_config selected_config;
- cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(*bag, *entry);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
+ return CopyValue(env, attr_value, typed_value);
}
static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jintArray array = env->NewIntArray(bag->entry_count);
if (env->ExceptionCheck()) {
return nullptr;
@@ -702,42 +696,47 @@ static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong p
static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
if (array == nullptr) {
return nullptr;
}
for (uint32_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
-
// Resolve any references to their final value.
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
return nullptr;
}
- if (value.dataType == Res_value::TYPE_STRING) {
- const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
+ if (attr_value.type == Res_value::TYPE_STRING) {
+ const ApkAssets* apk_assets = assetmanager->GetApkAssets()[attr_value.cookie];
const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
jstring java_string = nullptr;
- size_t str_len;
- const char* str_utf8 = pool->string8At(value.data, &str_len);
- if (str_utf8 != nullptr) {
- java_string = env->NewStringUTF(str_utf8);
+ auto str_utf8 = pool->string8At(attr_value.data);
+ if (UNLIKELY(ThrowIfIOError(env, str_utf8))) {
+ return nullptr;
+ }
+
+ if (str_utf8.has_value()) {
+ java_string = env->NewStringUTF(str_utf8->data());
} else {
- const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
- java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
+ auto str_utf16 = pool->stringAt(attr_value.data);
+ if (!str_utf16.has_value()) {
+ ThrowIfIOError(env, str_utf16);
+ return nullptr;
+ }
+ java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16->data()),
+ str_utf16->size());
}
// Check for errors creating the strings (if malformed or no memory).
@@ -758,11 +757,13 @@ static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/,
static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jintArray array = env->NewIntArray(bag->entry_count * 2);
if (array == nullptr) {
return nullptr;
@@ -774,24 +775,20 @@ static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/,
}
for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
+ ThrowIfIOError(env, result);
return nullptr;
}
jint string_index = -1;
- if (value.dataType == Res_value::TYPE_STRING) {
- string_index = static_cast<jint>(value.data);
+ if (attr_value.type == Res_value::TYPE_STRING) {
+ string_index = static_cast<jint>(attr_value.data);
}
- buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
+ buffer[i * 2] = ApkAssetsCookieToJavaCookie(attr_value.cookie);
buffer[(i * 2) + 1] = string_index;
}
env->ReleasePrimitiveArrayCritical(array, buffer, 0);
@@ -800,11 +797,13 @@ static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/,
static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jintArray array = env->NewIntArray(bag->entry_count);
if (array == nullptr) {
return nullptr;
@@ -816,40 +815,39 @@ static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong
}
for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
+ env->ReleasePrimitiveArrayCritical(array, buffer, 0);
+ ThrowIfIOError(env, result);
return nullptr;
}
- if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
- buffer[i] = static_cast<jint>(value.data);
+ if (attr_value.type >= Res_value::TYPE_FIRST_INT &&
+ attr_value.type <= Res_value::TYPE_LAST_INT) {
+ buffer[i] = static_cast<jint>(attr_value.data);
}
}
env->ReleasePrimitiveArrayCritical(array, buffer, 0);
return array;
}
-static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
- return -1;
- }
- return static_cast<jint>(bag->entry_count);
+static jint NativeGetResourceArraySize(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag.has_value()) {
+ ThrowIfIOError(env, bag);
+ return -1;
+ }
+ return static_cast<jint>((*bag)->entry_count);
}
static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
jintArray out_data) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return -1;
}
@@ -858,8 +856,10 @@ static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin
return -1;
}
+ const ResolvedBag* bag = *bag_result;
if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Input array is not large enough");
return -1;
}
@@ -870,31 +870,26 @@ static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin
jint* cursor = buffer;
for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- selected_config.density = 0;
- uint32_t flags = bag->type_spec_flags;
- uint32_t ref = 0;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
+ ThrowIfIOError(env, bag_result);
return -1;
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
+ if (attr_value.type == Res_value::TYPE_REFERENCE && attr_value.data == 0) {
+ attr_value.type = Res_value::TYPE_NULL;
+ attr_value.data = Res_value::DATA_NULL_UNDEFINED;
}
- cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
- cursor[STYLE_DATA] = static_cast<jint>(value.data);
- cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
- cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
- cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
- cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
+ cursor[STYLE_TYPE] = static_cast<jint>(attr_value.type);
+ cursor[STYLE_DATA] = static_cast<jint>(attr_value.data);
+ cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(attr_value.cookie);
+ cursor[STYLE_RESOURCE_ID] = static_cast<jint>(attr_value.resid);
+ cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(attr_value.flags);
+ cursor[STYLE_DENSITY] = static_cast<jint>(attr_value.config.density);
cursor += STYLE_NUM_ENTRIES;
}
env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
@@ -922,60 +917,71 @@ static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr
CHECK(package_utf8.c_str() != nullptr);
package = package_utf8.c_str();
}
+
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
+ auto resid = assetmanager->GetResourceId(name_utf8.c_str(), type, package);
+ if (!resid.has_value()) {
+ ThrowIfIOError(env, resid);
+ return 0;
+ }
+
+ return static_cast<jint>(*resid);
}
static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- std::string result = ToFormattedResourceString(&name);
+ const std::string result = ToFormattedResourceString(name.value());
return env->NewStringUTF(result.c_str());
}
static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- if (name.package != nullptr) {
- return env->NewStringUTF(name.package);
+ if (name->package != nullptr) {
+ return env->NewStringUTF(name->package);
}
return nullptr;
}
static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- if (name.type != nullptr) {
- return env->NewStringUTF(name.type);
- } else if (name.type16 != nullptr) {
- return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
+ if (name->type != nullptr) {
+ return env->NewStringUTF(name->type);
+ } else if (name->type16 != nullptr) {
+ return env->NewString(reinterpret_cast<const jchar*>(name->type16), name->type_len);
}
return nullptr;
}
static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- if (name.entry != nullptr) {
- return env->NewStringUTF(name.entry);
- } else if (name.entry16 != nullptr) {
- return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
+ if (name->entry != nullptr) {
+ return env->NewStringUTF(name->entry);
+ } else if (name->entry16 != nullptr) {
+ return env->NewString(reinterpret_cast<const jchar*>(name->entry16), name->entry_len);
}
return nullptr;
}
@@ -1039,17 +1045,21 @@ static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config&
static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- std::set<ResTable_config> configurations =
- assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
+ auto configurations = assetmanager->GetResourceConfigurations(true /*exclude_system*/,
+ false /*exclude_mipmap*/);
+ if (!configurations.has_value()) {
+ ThrowIfIOError(env, configurations);
+ return nullptr;
+ }
jobjectArray array =
- env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
+ env->NewObjectArray(configurations->size(), gConfigurationOffsets.classObject, nullptr);
if (array == nullptr) {
return nullptr;
}
size_t idx = 0;
- for (const ResTable_config& configuration : configurations) {
+ for (const ResTable_config& configuration : *configurations) {
jobject java_configuration = ConstructConfigurationObject(env, configuration);
if (java_configuration == nullptr) {
return nullptr;
@@ -1072,13 +1082,10 @@ static jintArray NativeAttributeResolutionStack(
(void) assetmanager;
// Load default style from attribute, if specified...
- uint32_t def_style_flags = 0u;
if (def_style_attr != 0) {
- Res_value value;
- if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- def_style_resid = value.data;
- }
+ auto value = theme->GetAttribute(def_style_attr);
+ if (value.has_value() && value->type == Res_value::TYPE_REFERENCE) {
+ def_style_resid = value->data;
}
}
@@ -1119,10 +1126,11 @@ static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong the
return;
}
- ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
- static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
- out_values, out_indices);
+ auto result = ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
+ static_cast<uint32_t>(def_style_resid),
+ reinterpret_cast<uint32_t*>(attrs), attrs_len, out_values, out_indices);
env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+ ThrowIfIOError(env, result);
}
static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
@@ -1183,11 +1191,12 @@ static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlo
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
-
- bool result = ResolveAttrs(
- theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
- reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
- attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
+ auto result =
+ ResolveAttrs(theme, static_cast<uint32_t>(def_style_attr),
+ static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(values),
+ values_len, reinterpret_cast<uint32_t*>(attrs), attrs_len,
+ reinterpret_cast<uint32_t*>(out_values),
+ reinterpret_cast<uint32_t*>(out_indices));
if (out_indices != nullptr) {
env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
}
@@ -1196,8 +1205,13 @@ static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlo
if (values != nullptr) {
env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
}
+
env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- return result ? JNI_TRUE : JNI_FALSE;
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
}
static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
@@ -1238,18 +1252,22 @@ static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong pt
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
-
- bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
- reinterpret_cast<uint32_t*>(attrs), attrs_len,
- reinterpret_cast<uint32_t*>(out_values),
- reinterpret_cast<uint32_t*>(out_indices));
+ auto result =
+ RetrieveAttributes(assetmanager.get(), xml_parser, reinterpret_cast<uint32_t*>(attrs),
+ attrs_len, reinterpret_cast<uint32_t*>(out_values),
+ reinterpret_cast<uint32_t*>(out_indices));
if (out_indices != nullptr) {
env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
}
+
env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- return result ? JNI_TRUE : JNI_FALSE;
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
}
static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
@@ -1268,7 +1286,9 @@ static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlon
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
- theme->ApplyStyle(static_cast<uint32_t>(resid), force);
+
+ auto result = theme->ApplyStyle(static_cast<uint32_t>(resid), force);
+ ThrowIfIOError(env, result);
// TODO(adamlesinski): Consider surfacing exception when result is failure.
// CTS currently expects no exceptions from this method.
@@ -1281,19 +1301,22 @@ static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manag
Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
+ ScopedLock<AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
+ CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
+ (void) src_assetmanager;
+
if (dst_asset_manager_ptr != src_asset_manager_ptr) {
ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
(void) dst_assetmanager;
- ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
- CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
- (void) src_assetmanager;
-
- dst_theme->SetTo(*src_theme);
- } else {
- dst_theme->SetTo(*src_theme);
+ auto result = dst_theme->SetTo(*src_theme);
+ ThrowIfIOError(env, result);
+ return;
}
+
+ auto result = dst_theme->SetTo(*src_theme);
+ ThrowIfIOError(env, result);
}
static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
@@ -1308,23 +1331,21 @@ static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong pt
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = theme->GetAttribute(static_cast<uint32_t>(resid));
+ if (!value.has_value()) {
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- uint32_t ref = 0u;
- if (resolve_references) {
- ResTable_config selected_config;
- cookie =
- theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- return ApkAssetsCookieToJavaCookie(kInvalidCookie);
- }
+ if (!resolve_references) {
+ return CopyValue(env, *value, typed_value);
+ }
+
+ auto result = theme->GetAssetManager()->ResolveReference(*value);
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
+ return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
+ return CopyValue(env, *value, typed_value);
}
static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
diff --git a/core/jni/android_util_AssetManager_private.h b/core/jni/android_util_AssetManager_private.h
new file mode 100644
index 000000000000..153509b98db5
--- /dev/null
+++ b/core/jni/android_util_AssetManager_private.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_UTIL_ASSETMANAGER_PRIVATE_H
+#define ANDROID_UTIL_ASSETMANAGER_PRIVATE_H
+
+#include <optional>
+
+#include <androidfw/Errors.h>
+#include <android-base/expected.h>
+
+#include "core_jni_helpers.h"
+#include "jni.h"
+#include "nativehelper/JNIHelp.h"
+
+namespace android {
+
+constexpr const char* kResourcesNotFound = "android/content/res/Resources$NotFoundException";
+constexpr const static char* kIOErrorMessage = "failed to read resources.arsc data";
+
+template <typename T, typename E>
+static bool ThrowIfIOError(JNIEnv* env, const base::expected<T, E>& result) {
+ if constexpr (std::is_same<NullOrIOError, E>::value) {
+ if (IsIOError(result)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return true;
+ }
+ return false;
+ } else {
+ if (!result.has_value()) {
+ static_assert(std::is_same<IOError, E>::value, "Unknown result error type");
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return true;
+ }
+ return false;
+ }
+}
+
+} // namespace android
+
+#endif //ANDROID_UTIL_ASSETMANAGER_PRIVATE_H
diff --git a/core/jni/android_util_CharsetUtils.cpp b/core/jni/android_util_CharsetUtils.cpp
new file mode 100644
index 000000000000..7ab6e8f27fb2
--- /dev/null
+++ b/core/jni/android_util_CharsetUtils.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "core_jni_helpers.h"
+#include "nativehelper/scoped_primitive_array.h"
+
+namespace android {
+
+static jint android_util_CharsetUtils_toModifiedUtf8Bytes(JNIEnv *env, jobject clazz,
+ jstring src, jint srcLen, jlong dest, jint destOff, jint destLen) {
+ char *destPtr = reinterpret_cast<char*>(dest);
+
+ // Quickly check if destination has plenty of room for worst-case
+ // 4-bytes-per-char encoded size
+ const size_t worstLen = (srcLen * 4);
+ if (destOff >= 0 && destOff + worstLen < destLen) {
+ env->GetStringUTFRegion(src, 0, srcLen, destPtr + destOff);
+ return strlen(destPtr + destOff + srcLen) + srcLen;
+ }
+
+ // String still might fit in destination, but we need to measure
+ // its actual encoded size to be sure
+ const size_t encodedLen = env->GetStringUTFLength(src);
+ if (destOff >= 0 && destOff + encodedLen < destLen) {
+ env->GetStringUTFRegion(src, 0, srcLen, destPtr + destOff);
+ return encodedLen;
+ }
+
+ return -encodedLen;
+}
+
+static jstring android_util_CharsetUtils_fromModifiedUtf8Bytes(JNIEnv *env, jobject clazz,
+ jlong src, jint srcOff, jint srcLen) {
+ char *srcPtr = reinterpret_cast<char*>(src);
+
+ // This is funky, but we need to temporarily swap a null byte so that
+ // JNI knows where the string ends; we'll put it back, we promise
+ char tmp = srcPtr[srcOff + srcLen];
+ srcPtr[srcOff + srcLen] = '\0';
+ jstring res = env->NewStringUTF(srcPtr + srcOff);
+ srcPtr[srcOff + srcLen] = tmp;
+ return res;
+}
+
+static const JNINativeMethod methods[] = {
+ // @FastNative
+ {"toModifiedUtf8Bytes", "(Ljava/lang/String;IJII)I",
+ (void*)android_util_CharsetUtils_toModifiedUtf8Bytes},
+ // @FastNative
+ {"fromModifiedUtf8Bytes", "(JII)Ljava/lang/String;",
+ (void*)android_util_CharsetUtils_fromModifiedUtf8Bytes},
+};
+
+int register_android_util_CharsetUtils(JNIEnv *env) {
+ return RegisterMethodsOrDie(env, "android/util/CharsetUtils", methods, NELEM(methods));
+}
+
+}
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
index 760f9e36ed3d..45f6b72b3727 100644
--- a/core/jni/android_util_StringBlock.cpp
+++ b/core/jni/android_util_StringBlock.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "StringBlock"
+#include "android_util_AssetManager_private.h"
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include <utils/misc.h>
@@ -31,10 +32,8 @@ namespace android {
// ----------------------------------------------------------------------------
-static jlong android_content_StringBlock_nativeCreate(JNIEnv* env, jobject clazz,
- jbyteArray bArray,
- jint off, jint len)
-{
+static jlong android_content_StringBlock_nativeCreate(JNIEnv* env, jobject clazz, jbyteArray bArray,
+ jint off, jint len) {
if (bArray == NULL) {
jniThrowNullPointerException(env, NULL);
return 0;
@@ -59,9 +58,7 @@ static jlong android_content_StringBlock_nativeCreate(JNIEnv* env, jobject clazz
return reinterpret_cast<jlong>(osb);
}
-static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz,
- jlong token)
-{
+static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz, jlong token) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);
@@ -71,76 +68,84 @@ static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz
return osb->size();
}
-static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject clazz,
- jlong token, jint idx)
-{
+static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject clazz, jlong token,
+ jint idx) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);
return 0;
}
- size_t len;
- const char* str8 = osb->string8At(idx, &len);
- if (str8 != NULL) {
- return env->NewStringUTF(str8);
+ auto str8 = osb->string8At(idx);
+ if (UNLIKELY(ThrowIfIOError(env, str8))) {
+ return 0;
+ } else if (str8.has_value()) {
+ return env->NewStringUTF(str8->data());
}
- const char16_t* str = osb->stringAt(idx, &len);
- if (str == NULL) {
+ auto str = osb->stringAt(idx);
+ if (UNLIKELY(ThrowIfIOError(env, str))) {
+ return 0;
+ } else if (UNLIKELY(!str.has_value())) {
jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
return 0;
}
- return env->NewString((const jchar*)str, len);
+ return env->NewString((const jchar*)str->data(), str->size());
}
-static jintArray android_content_StringBlock_nativeGetStyle(JNIEnv* env, jobject clazz,
- jlong token, jint idx)
-{
+static jintArray android_content_StringBlock_nativeGetStyle(JNIEnv* env, jobject clazz, jlong token,
+ jint idx) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);
return NULL;
}
- const ResStringPool_span* spans = osb->styleAt(idx);
- if (spans == NULL) {
+ auto spans = osb->styleAt(idx);
+ if (!spans.has_value()) {
+ ThrowIfIOError(env, spans);
return NULL;
}
- const ResStringPool_span* pos = spans;
- int num = 0;
- while (pos->name.index != ResStringPool_span::END) {
- num++;
- pos++;
+ jintArray array;
+ {
+ int num = 0;
+ auto pos = *spans;
+ while (true) {
+ if (UNLIKELY(!pos)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return NULL;
+ }
+ if (pos->name.index == ResStringPool_span::END) {
+ break;
+ }
+ num++;
+ pos++;
+ }
+
+ if (num == 0) {
+ return NULL;
+ }
+
+ array = env->NewIntArray((num * sizeof(ResStringPool_span)) / sizeof(jint));
+ if (array == NULL) { // NewIntArray already threw OutOfMemoryError.
+ return NULL;
+ }
}
-
- if (num == 0) {
- return NULL;
+ {
+ int num = 0;
+ static const int numInts = sizeof(ResStringPool_span) / sizeof(jint);
+ while ((*spans)->name.index != ResStringPool_span::END) {
+ env->SetIntArrayRegion(array, num * numInts, numInts, (jint*)spans->unsafe_ptr());
+ (*spans)++;
+ num++;
+ }
}
-
- jintArray array = env->NewIntArray((num*sizeof(ResStringPool_span))/sizeof(jint));
- if (array == NULL) { // NewIntArray already threw OutOfMemoryError.
- return NULL;
- }
-
- num = 0;
- static const int numInts = sizeof(ResStringPool_span)/sizeof(jint);
- while (spans->name.index != ResStringPool_span::END) {
- env->SetIntArrayRegion(array,
- num*numInts, numInts,
- (jint*)spans);
- spans++;
- num++;
- }
-
return array;
}
-static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz,
- jlong token)
-{
+static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz, jlong token) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index cbce38e12d25..12d8bc6835e1 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -162,7 +162,7 @@ static jchar nativeGetDisplayLabel(JNIEnv *env, jobject clazz, jlong ptr, jint k
static jint nativeGetKeyboardType(JNIEnv *env, jobject clazz, jlong ptr) {
NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
- return map->getMap()->getKeyboardType();
+ return static_cast<jint>(map->getMap()->getKeyboardType());
}
static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr,
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index f791cb105b21..6ffafc16b89c 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -787,10 +787,14 @@ static void PrepareDirIfNotPresent(const std::string& dir, mode_t mode, uid_t ui
PrepareDir(dir, mode, uid, gid, fail_fn);
}
+static bool BindMount(const std::string& source_dir, const std::string& target_dir) {
+ return !(TEMP_FAILURE_RETRY(mount(source_dir.c_str(), target_dir.c_str(), nullptr,
+ MS_BIND | MS_REC, nullptr)) == -1);
+}
+
static void BindMount(const std::string& source_dir, const std::string& target_dir,
fail_fn_t fail_fn) {
- if (TEMP_FAILURE_RETRY(mount(source_dir.c_str(), target_dir.c_str(), nullptr,
- MS_BIND | MS_REC, nullptr)) == -1) {
+ if (!BindMount(source_dir, target_dir)) {
fail_fn(CREATE_ERROR("Failed to mount %s to %s: %s",
source_dir.c_str(), target_dir.c_str(), strerror(errno)));
}
@@ -1168,9 +1172,9 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
// Create an app data directory over tmpfs overlayed CE / DE storage, and bind mount it
// from the actual app data directory in data mirror.
-static void createAndMountAppData(std::string_view package_name,
+static bool createAndMountAppData(std::string_view package_name,
std::string_view mirror_pkg_dir_name, std::string_view mirror_data_path,
- std::string_view actual_data_path, fail_fn_t fail_fn) {
+ std::string_view actual_data_path, fail_fn_t fail_fn, bool call_fail_fn) {
char mirrorAppDataPath[PATH_MAX];
char actualAppDataPath[PATH_MAX];
@@ -1181,6 +1185,29 @@ static void createAndMountAppData(std::string_view package_name,
PrepareDir(actualAppDataPath, 0700, AID_ROOT, AID_ROOT, fail_fn);
// Bind mount from original app data directory in mirror.
+ if (call_fail_fn) {
+ BindMount(mirrorAppDataPath, actualAppDataPath, fail_fn);
+ } else if(!BindMount(mirrorAppDataPath, actualAppDataPath)) {
+ ALOGW("Failed to mount %s to %s: %s",
+ mirrorAppDataPath, actualAppDataPath, strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+// There is an app data directory over tmpfs overlaid CE / DE storage
+// bind mount it from the actual app data directory in data mirror.
+static void mountAppData(std::string_view package_name,
+ std::string_view mirror_pkg_dir_name, std::string_view mirror_data_path,
+ std::string_view actual_data_path, fail_fn_t fail_fn) {
+
+ char mirrorAppDataPath[PATH_MAX];
+ char actualAppDataPath[PATH_MAX];
+ snprintf(mirrorAppDataPath, PATH_MAX, "%s/%s", mirror_data_path.data(),
+ mirror_pkg_dir_name.data());
+ snprintf(actualAppDataPath, PATH_MAX, "%s/%s", actual_data_path.data(), package_name.data());
+
+ // Bind mount from original app data directory in mirror.
BindMount(mirrorAppDataPath, actualAppDataPath, fail_fn);
}
@@ -1258,10 +1285,17 @@ static void isolateAppDataPerPackage(int userId, std::string_view package_name,
snprintf(mirrorCePath, PATH_MAX, "%s/%d", mirrorCeParent, userId);
snprintf(mirrorDePath, PATH_MAX, "/data_mirror/data_de/%s/%d", volume_uuid.data(), userId);
- createAndMountAppData(package_name, package_name, mirrorDePath, actualDePath, fail_fn);
+ createAndMountAppData(package_name, package_name, mirrorDePath, actualDePath, fail_fn,
+ true /*call_fail_fn*/);
std::string ce_data_path = getAppDataDirName(mirrorCePath, package_name, ce_data_inode, fail_fn);
- createAndMountAppData(package_name, ce_data_path, mirrorCePath, actualCePath, fail_fn);
+ if (!createAndMountAppData(package_name, ce_data_path, mirrorCePath, actualCePath, fail_fn,
+ false /*call_fail_fn*/)) {
+ // CE might unlocks and the name is decrypted
+ // get the name and mount again
+ ce_data_path=getAppDataDirName(mirrorCePath, package_name, ce_data_inode, fail_fn);
+ mountAppData(package_name, ce_data_path, mirrorCePath, actualCePath, fail_fn);
+ }
}
// Relabel directory
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 68e01f6da99d..06a71cb22672 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -33,17 +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.i18n/javalib/core-icu4j.jar",
- "/apex/com.android.media/javalib/updatable-media.jar",
- "/apex/com.android.mediaprovider/javalib/framework-mediaprovider.jar",
- "/apex/com.android.os.statsd/javalib/framework-statsd.jar",
- "/apex/com.android.permission/javalib/framework-permission.jar",
- "/apex/com.android.sdkext/javalib/framework-sdkextensions.jar",
- "/apex/com.android.wifi/javalib/framework-wifi.jar",
- "/apex/com.android.tethering/javalib/framework-tethering.jar",
"/dev/null",
"/dev/socket/zygote",
"/dev/socket/zygote_secondary",
@@ -103,11 +92,12 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
}
}
- // Jars from the ART APEX are allowed.
- static const char* kArtApexPrefix = "/apex/com.android.art/javalib/";
- if (android::base::StartsWith(path, kArtApexPrefix)
- && android::base::EndsWith(path, kJarSuffix)) {
- return true;
+ // Jars from APEXes are allowed. This matches /apex/**/javalib/*.jar.
+ static const char* kApexPrefix = "/apex/";
+ static const char* kApexJavalibPathSuffix = "/javalib";
+ if (android::base::StartsWith(path, kApexPrefix) && android::base::EndsWith(path, kJarSuffix) &&
+ android::base::EndsWith(android::base::Dirname(path), kApexJavalibPathSuffix)) {
+ return true;
}
// the in-memory file created by ART through memfd_create is allowed.
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 45f64f9a92af..a2a7649645f5 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -779,6 +779,26 @@ enum Action {
// CATEGORY: SETTINGS
// OS: S
ACTION_COLUMBUS_ACTION_NOTIFICATION_SHADE = 1746;
+
+ // ACTION: Settings > System > Gestures > Double tap > Require harder taps
+ // CATEGORY: SETTINGS
+ // OS: S
+ ACTION_COLUMBUS_LOW_SENSITIVITY = 1747;
+
+ // OPEN: Columbus Gesture training intro in Settings
+ // CATEGORY: SETTINGS
+ // OS: S
+ SETTINGS_COLUMBUS_GESTURE_TRAINING_INTRO = 1748;
+
+ // OPEN: Columbus Gesture training enrolling in Settings
+ // CATEGORY: SETTINGS
+ // OS: S
+ SETTINGS_COLUMBUS_GESTURE_TRAINING_ENROLLING = 1749;
+
+ // OPEN: Columbus Gesture training finished in Settings
+ // CATEGORY: SETTINGS
+ // OS: S
+ SETTINGS_COLUMBUS_GESTURE_TRAINING_FINISHED = 1750;
}
/**
@@ -2766,4 +2786,9 @@ enum PageId {
// CATEGORY: SETTINGS
// OS: S
LOCATION_TIME_ZONE_DETECTION = 1854;
+
+ // OPEN: Settings > Developer options > Media transcode settings
+ // CATEGORY: SETTINGS
+ // OS: S
+ TRANSCODE_SETTINGS = 1855;
}
diff --git a/core/proto/android/app/tvsettings_enums.proto b/core/proto/android/app/tvsettings_enums.proto
index 4a3c59477f2f..77bf98f1c15e 100644
--- a/core/proto/android/app/tvsettings_enums.proto
+++ b/core/proto/android/app/tvsettings_enums.proto
@@ -149,6 +149,34 @@ enum ItemId {
ACCOUNT_SLICE_REG_ACCOUNT = 0x12100000;
// TvSettings > Account & Sign In (Slice) > [A regular account] >
+ // Services
+ ACCOUNT_SLICE_REG_ACCOUNT_SERVICES = 0x12110000;
+
+ // TvSettings > Account & Sign In (Slice) > [A regular account] >
+ // Payment & Purchases
+ ACCOUNT_SLICE_REG_ACCOUNT_PAYMENT = 0x12120000;
+
+ // TvSettings > Account & Sign In (Slice) > [A regular account] >
+ // Payment & Purchases >
+ // Require authentication for purchases (reauth interval)
+ ACCOUNT_SLICE_REG_ACCOUNT_PAYMENT_REAUTH = 0x12121000;
+
+ // TvSettings > Account & Sign In (Slice) > [A regular account] >
+ // Payment & Purchases >
+ // Require authentication for purchases (reauth interval) > Always
+ ACCOUNT_SLICE_REG_ACCOUNT_PAYMENT_REAUTH_ALWAYS = 0x12121100;
+
+ // TvSettings > Account & Sign In (Slice) > [A regular account] >
+ // Payment & Purchases >
+ // Require authentication for purchases (reauth interval) > Every 30 minutes
+ ACCOUNT_SLICE_REG_ACCOUNT_PAYMENT_REAUTH_30MINS = 0x12121200;
+
+ // TvSettings > Account & Sign In (Slice) > [A regular account] >
+ // Payment & Purchases >
+ // Require authentication for purchases (reauth interval) > Never
+ ACCOUNT_SLICE_REG_ACCOUNT_PAYMENT_REAUTH_NEVER = 0x12121300;
+
+ // TvSettings > Account & Sign In (Slice) > [A regular account] >
// Google Assistant
ACCOUNT_SLICE_REG_ACCOUNT_ASSISTANT = 0x12130000;
@@ -220,6 +248,48 @@ enum ItemId {
// TvSettings > Account & Sign In (Classic) > Add account
ACCOUNT_CLASSIC_ADD_ACCOUNT = 0x13A00000;
+ // TvSettings > Privacy
+ PRIVACY = 0x14000000;
+
+ // TvSettings > Privacy > Location
+ PRIVACY_LOCATION = 0x14100000;
+
+ // TvSettings > Privacy > Location > Location status (radio button)
+ PRIVACY_LOCATION_STATUS = 0x14110000;
+
+ // TvSettings > Privacy > Location > Location status (radio button) >
+ // Use Wi-Fi to estimate location
+ PRIVACY_LOCATION_STATUS_USE_WIFI = 0x14111000;
+
+ // TvSettings > Privacy > Location > Location status (radio button) > Off
+ PRIVACY_LOCATION_STATUS_OFF = 0x14112000;
+
+ // TvSettings > Privacy > Location > Scanning always available (toggle)
+ PRIVACY_LOCATION_ALWAYS_SCANNING_NETWORKS = 0x14120000;
+
+ // TvSettings > Privacy > Location > [An app that had recent requests]
+ PRIVACY_LOCATION_REQUESTED_APP = 0x14130000;
+
+ // TvSettings > Privacy > Usage & Diagnostics
+ PRIVACY_DIAGNOSTICS = 0x14200000;
+
+ // TvSettings > Privacy > Usage & Diagnostics > On (Toggle)
+ PRIVACY_DIAGNOSTICS_ON_OFF = 0x14210000;
+
+ // TvSettings > Privacy > Ads
+ PRIVACY_ADS = 0x14300000;
+
+ // The following three IDs may not actually be logged as they are within a
+ // GMSCore Activity but we reserve IDs for them.
+ // TvSettings > Privacy > Ads > Reset advertising ID
+ PRIVACY_ADS_RESET_AD_ID = 0x14310000;
+
+ // TvSettings > Privacy > Ads > Opt out of Ads Personalization
+ PRIVACY_ADS_OPT_OUT_PERSONALIZATION = 0x14320000;
+
+ // TvSettings > Privacy > Ads > Ads by Google (WebView)
+ PRIVACY_ADS_ADS_BY_GOOGLE = 0x14330000;
+
// TvSettings > Display & Sound
DISPLAY_SOUND = 0x15000000;
@@ -540,6 +610,123 @@ enum ItemId {
// Cached data (brings up "Clear cached data?" dialog upon click)
SYSTEM_STORAGE_INTERNAL_STORAGE_CACHED = 0x17512000;
+ // TvSettings > System > Ambient mode
+ SYSTEM_AMBIENT = 0x17600000;
+
+ // TvSettings > System > Ambient mode > Start now
+ SYSTEM_AMBIENT_START = 0x17610000;
+
+ // TvSettings > System > Ambient mode > Settings
+ SYSTEM_AMBIENT_SETTINGS = 0x17620000;
+
+ // TvSettings > System > Ambient mode > Settings > Google Photos (Channels)
+ SYSTEM_AMBIENT_SETTINGS_CHANNEL_GP = 0x17621000;
+
+ // TvSettings > System > Ambient mode > Settings > Art gallery (Channels)
+ SYSTEM_AMBIENT_SETTINGS_CHANNEL_AG = 0x17622000;
+
+ // TvSettings > System > Ambient mode > Settings >
+ // Cinematic videos (Channels)
+ SYSTEM_AMBIENT_SETTINGS_CHANNEL_CV = 0x17623000;
+
+ // TvSettings > System > Ambient mode > Settings > Experimental (Channels)
+ SYSTEM_AMBIENT_SETTINGS_CHANNEL_EXP = 0x17624000;
+
+ // TvSettings > System > Ambient mode > Settings > Weather
+ SYSTEM_AMBIENT_SETTINGS_WEATHER = 0x17625000;
+
+ // TvSettings > System > Ambient mode > Settings > Weather > Hide
+ SYSTEM_AMBIENT_SETTINGS_WEATHER_HIDE = 0x17625100;
+
+ // TvSettings > System > Ambient mode > Settings > Weather > Celsius (Unit)
+ SYSTEM_AMBIENT_SETTINGS_WEATHER_UNIT_C = 0x17625200;
+
+ // TvSettings > System > Ambient mode > Settings > Weather >
+ // Fahrenheit (Unit)
+ SYSTEM_AMBIENT_SETTINGS_WEATHER_UNIT_F = 0x17625300;
+
+ // TvSettings > System > Ambient mode > Settings > Weather > Both (Unit)
+ SYSTEM_AMBIENT_SETTINGS_WEATHER_UNIT_BOTH = 0x17625400;
+
+ // TvSettings > System > Ambient mode > Settings > Time
+ SYSTEM_AMBIENT_SETTINGS_TIME = 0x17626000;
+
+ // TvSettings > System > Ambient mode > Settings > Time > Hide
+ SYSTEM_AMBIENT_SETTINGS_TIME_HIDE = 0x17626100;
+
+ // TvSettings > System > Ambient mode > Settings > Time > Show
+ SYSTEM_AMBIENT_SETTINGS_TIME_SHOW = 0x17626200;
+
+ // TvSettings > System > Ambient mode > Settings > Device information
+ SYSTEM_AMBIENT_SETTINGS_DEVICE_INFO = 0x17627000;
+
+ // TvSettings > System > Ambient mode > Settings > Device information > Hide
+ SYSTEM_AMBIENT_SETTINGS_DEVICE_INFO_HIDE = 0x17627100;
+
+ // TvSettings > System > Ambient mode > Settings > Device information > Show
+ SYSTEM_AMBIENT_SETTINGS_DEVICE_INFO_SHOW = 0x17627200;
+
+ // TvSettings > System > Ambient mode > Settings > Personal photo data
+ SYSTEM_AMBIENT_SETTINGS_PPD = 0x17628000;
+
+ // TvSettings > System > Ambient mode > Settings > Personal photo data >
+ // Hide
+ SYSTEM_AMBIENT_SETTINGS_PPD_HIDE = 0x17628100;
+
+ // TvSettings > System > Ambient mode > Settings > Personal photo data >
+ // Show
+ SYSTEM_AMBIENT_SETTINGS_PPD_SHOW = 0x17628200;
+
+ // TvSettings > System > Ambient mode > Settings > Portrait Google Photos
+ SYSTEM_AMBIENT_SETTINGS_PGP = 0x17629000;
+
+ // TvSettings > System > Ambient mode > Settings > Portrait Google Photos >
+ // Hide
+ SYSTEM_AMBIENT_SETTINGS_PGP_HIDE = 0x17629100;
+
+ // TvSettings > System > Ambient mode > Settings > Portrait Google Photos >
+ // Show
+ SYSTEM_AMBIENT_SETTINGS_PGP_SHOW = 0x17629200;
+
+ // TvSettings > System > Ambient mode > Settings > Portrait Google Photos >
+ // Show pairs
+ SYSTEM_AMBIENT_SETTINGS_PGP_SHOW_PAIRS = 0x17629300;
+
+ // TvSettings > System > Ambient mode > Settings > Personal photo curation
+ SYSTEM_AMBIENT_SETTINGS_PPC = 0x1762A000;
+
+ // TvSettings > System > Ambient mode > Settings > Personal photo curation >
+ // All albums
+ SYSTEM_AMBIENT_SETTINGS_PPC_ALL_ALBUMS = 0x1762A100;
+
+ // TvSettings > System > Ambient mode > Settings > Personal photo curation >
+ // Live albums only
+ SYSTEM_AMBIENT_SETTINGS_PPC_LIVE_ALBUMS = 0x1762A200;
+
+ // TvSettings > System > Ambient mode > Settings > Slideshow speed
+ SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED = 0x1762B000;
+
+ // TvSettings > System > Ambient mode > Settings > Slideshow speed > 5s
+ SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_5S = 0x1762B100;
+
+ // TvSettings > System > Ambient mode > Settings > Slideshow speed > 10s
+ SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_10S = 0x1762B200;
+
+ // TvSettings > System > Ambient mode > Settings > Slideshow speed > 30s
+ SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_30S = 0x1762B300;
+
+ // TvSettings > System > Ambient mode > Settings > Slideshow speed > 1m
+ SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_1M = 0x1762B400;
+
+ // TvSettings > System > Ambient mode > Settings > Slideshow speed > 3m
+ SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_3M = 0x1762B500;
+
+ // TvSettings > System > Ambient mode > Settings > Slideshow speed > 5m
+ SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_5M = 0x1762B600;
+
+ // TvSettings > System > Ambient mode > Settings > Slideshow speed > 10m
+ SYSTEM_AMBIENT_SETTINGS_SLIDE_SPEED_10M = 0x1762B700;
+
// TvSettings > System > Energy saver
SYSTEM_ENERGYSAVER = 0x17700000;
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 1ea1bafd4d2f..abbe25de0f26 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -535,7 +535,7 @@ message GlobalSettingsProto {
// If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link
// Secure#LOCATION_MODE_OFF} temporarily for all users.
optional SettingProto global_kill_switch = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto gnss_satellite_blacklist = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto gnss_satellite_blocklist = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto gnss_hal_location_request_duration_millis = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Packages that are whitelisted for ignoring location settings (during emergencies)
optional SettingProto ignore_settings_package_whitelist = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/proto/android/server/alarm/alarmmanagerservice.proto b/core/proto/android/server/alarm/alarmmanagerservice.proto
index e1240245d20f..8fe1bfc81702 100644
--- a/core/proto/android/server/alarm/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarm/alarmmanagerservice.proto
@@ -144,6 +144,8 @@ message AlarmManagerServiceDumpProto {
repeated IdleDispatchEntryProto allow_while_idle_dispatches = 40;
repeated WakeupEventProto recent_wakeup_history = 41;
+
+ repeated AlarmProto pending_alarms = 42;
}
// This is a soft wrapper for alarm clock information. It is not representative
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 76b7fc028a98..0e2bd2605836 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -527,7 +527,8 @@ message StateControllerProto {
optional bool is_idle = 1;
optional bool is_screen_on = 2;
optional bool is_dock_idle = 3;
- optional bool in_car_mode = 4;
+ reserved 4; // in_car_mode
+ optional bool projection_active = 5;
}
oneof active_tracker {
diff --git a/core/proto/android/stats/mediametrics/mediametrics.proto b/core/proto/android/stats/mediametrics/mediametrics.proto
index 9f0ff591a506..9d491263f8e0 100644
--- a/core/proto/android/stats/mediametrics/mediametrics.proto
+++ b/core/proto/android/stats/mediametrics/mediametrics.proto
@@ -237,3 +237,107 @@ message RecorderData {
optional int32 video_bitrate = 20;
optional int32 iframe_interval = 21;
}
+
+enum StreamType {
+ STREAM_TYPE_UNKNOWN = 0;
+ STREAM_TYPE_OTHER = 1;
+ STREAM_TYPE_PROGRESSIVE = 2;
+ STREAM_TYPE_DASH = 3;
+ STREAM_TYPE_HLS = 4;
+ STREAM_TYPE_SS = 5;
+}
+
+enum DrmType {
+ DRM_TYPE_NONE = 0;
+ DRM_TYPE_OTHER = 1;
+ DRM_TYPE_PLAY_READY = 2;
+ DRM_TYPE_WV_L1 = 3;
+ DRM_TYPE_WV_L3 = 4;
+}
+
+enum PlaybackType {
+ PLAYBACK_TYPE_VOD = 0;
+ PLAYBACK_TYPE_LIVE = 1;
+ PLAYBACK_TYPE_OTHER = 2;
+}
+
+enum ContentType {
+ CONTENT_TYPE_MAIN = 0;
+ CONTENT_TYPE_AD = 1;
+ CONTENT_TYPE_OTHER = 2;
+}
+
+enum StreamSourceType {
+ STREAM_SOURCE_UNKNOWN = 0;
+ STREAM_SOURCE_NETWORK = 1;
+ STREAM_SOURCE_DEVICE = 2;
+ STREAM_SOURCE_MIXED = 3;
+}
+enum NetworkType {
+ NETWORK_TYPE_NONE = 0;
+ NETWORK_TYPE_OTHER = 1;
+ NETWORK_TYPE_WIFI = 2;
+ NETWORK_TYPE_ETHERNET = 3;
+ NETWORK_TYPE_2G = 4;
+ NETWORK_TYPE_3G = 5;
+ NETWORK_TYPE_4G = 6;
+ NETWORK_TYPE_5G_NSA = 7;
+ NETWORK_TYPE_5G_SA = 8;
+}
+
+enum PlaybackState {
+ // Playback has not started (initial state)
+ NOT_STARTED = 0;
+ // Playback is buffering in the background for initial playback start
+ JOINING_BACKGROUND = 1;
+ // Playback is buffering in the foreground for initial playback start
+ JOINING_FOREGROUND = 2;
+ // Playback is actively playing
+ PLAYING = 3;
+ // Playback is paused but ready to play
+ PAUSED = 4;
+ // Playback is handling a seek
+ SEEKING = 5;
+ // Playback is buffering to resume active playback
+ BUFFERING = 6;
+ // Playback is buffering while paused
+ PAUSED_BUFFERING = 7;
+ // Playback is suppressed (e.g. due to audio focus loss)
+ SUPPRESSED = 8;
+ // Playback is suppressed (e.g. due to audio focus loss) while buffering to resume a
+ // playback
+ SUPPRESSED_BUFFERING = 9;
+ // Playback has reached the end of the media
+ ENDED = 10;
+ // Playback is stopped and can be restarted
+ STOPPED = 11;
+ // Playback is stopped due a fatal error and can be retried
+ FAILED = 12;
+ // Playback is interrupted by an ad
+ INTERRUPTED_BY_AD = 13;
+ // Playback is abandoned before reaching the end of the media
+ ABANDONED = 14;
+}
+
+enum PlaybackErrorCode {
+ ERROR_CODE_UNKNOWN = 0;
+ ERROR_CODE_OTHER = 1;
+ ERROR_CODE_RUNTIME = 2;
+}
+
+enum TrackType {
+ AUDIO = 0;
+ VIDEO = 1;
+ TEXT = 2;
+}
+enum TrackState {
+ OFF = 0;
+ ON = 1;
+}
+enum TrackChangeReason {
+ REASON_UNKNOWN = 0;
+ REASON_OTHER = 1;
+ REASON_INITIAL = 2;
+ REASON_MANUAL = 3;
+ REASON_ADAPTIVE = 4;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4df7d589d707..ea667277efee 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -349,7 +349,6 @@
<protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" />
<protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
<protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" />
- <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_DISPATCH" />
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
<protected-broadcast android:name="com.android.internal.action.EUICC_FACTORY_RESET" />
@@ -669,6 +668,10 @@
<!-- For tether entitlement recheck-->
<protected-broadcast
android:name="com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM" />
+
+ <!-- Made protected in S (was added in R) -->
+ <protected-broadcast android:name="com.android.internal.intent.action.BUGREPORT_REQUESTED" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -2659,6 +2662,14 @@
android:description="@string/permdesc_useDataInBackground"
android:protectionLevel="normal" />
+ <!-- Allows app to request to be associated with a device via
+ {@link android.companion.CompanionDeviceManager}
+ as a "watch"
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.REQUEST_COMPANION_PROFILE_WATCH"
+ android:protectionLevel="normal" />
+
<!-- Allows a companion app to associate to Wi-Fi.
<p>Only for use by a single pre-approved app.
@hide
@@ -2667,6 +2678,21 @@
<permission android:name="android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an app to read and listen to projection state.
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.READ_PROJECTION_STATE"
+ android:protectionLevel="signature" />
+
+ <!-- Allows an app to set and release automotive projection.
+ <p>Once permissions can be granted via role-only, this needs to be changed to
+ protectionLevel="role" and added to the SYSTEM_AUTOMOTIVE_PROJECTION role.
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION"
+ android:protectionLevel="signature|privileged" />
<!-- ================================== -->
<!-- Permissions affecting the system wallpaper -->
@@ -3401,6 +3427,12 @@
<permission android:name="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE"
android:protectionLevel="signature" />
+ <!-- Must be required by any
+ {@link android.companion.CompanionDeviceService}s
+ to ensure that only the system can bind to it. -->
+ <permission android:name="android.permission.BIND_COMPANION_DEVICE_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Must be required by the RuntimePermissionPresenterService to ensure
that only the system can bind to it.
@hide -->
@@ -5167,6 +5199,13 @@
<permission android:name="android.permission.CONTROL_DEVICE_STATE"
android:protectionLevel="signature" />
+ <!-- Must be required by an {@link android.service.attestation.ImpressionAttestationService}
+ to ensure that only the system can bind to it.
+ @hide This is not a third-party API (intended for OEMs and system apps).
+ -->
+ <permission android:name="android.permission.BIND_IMPRESSION_ATTESTATION_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index df447afca7eb..4d45791c9bdc 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -954,7 +954,7 @@
<string name="autofill_district" msgid="6428712062213557327">"Districte"</string>
<string name="autofill_department" msgid="9047276226873531529">"Departament"</string>
<string name="autofill_prefecture" msgid="7267397763720241872">"Prefectura"</string>
- <string name="autofill_parish" msgid="6847960518334530198">"Districte"</string>
+ <string name="autofill_parish" msgid="6847960518334530198">"Parròquia"</string>
<string name="autofill_area" msgid="8289022370678448983">"Àrea"</string>
<string name="autofill_emirate" msgid="2544082046790551168">"Emirat"</string>
<string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"lectura dels marcadors i l\'historial web"</string>
@@ -1228,8 +1228,8 @@
<string name="volume_music" msgid="7727274216734955095">"Volum de multimèdia"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"S\'està reproduint per Bluetooth"</string>
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"S\'ha establert el so de silenci"</string>
- <string name="volume_call" msgid="7625321655265747433">"Volum en trucada"</string>
- <string name="volume_bluetooth_call" msgid="2930204618610115061">"Volum en trucada per Bluetooth"</string>
+ <string name="volume_call" msgid="7625321655265747433">"Volum a la trucada"</string>
+ <string name="volume_bluetooth_call" msgid="2930204618610115061">"Volum a la trucada per Bluetooth"</string>
<string name="volume_alarm" msgid="4486241060751798448">"Volum d\'alarma"</string>
<string name="volume_notification" msgid="6864412249031660057">"Volum de notificacions"</string>
<string name="volume_unknown" msgid="4041914008166576293">"Volum"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 69d1526845b8..7a0a0ed005aa 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1225,7 +1225,7 @@
<string name="dump_heap_ready_text" msgid="5849618132123045516">"Protsessi <xliff:g id="PROC">%1$s</xliff:g> mälutõmmis on jagamiseks saadaval. Olge ettevaatlik: see mälutõmmis võib sisaldada tundlikke isiklikke andmeid, millele protsessil on juurdepääs. See võib hõlmata teie sisestatud teavet."</string>
<string name="sendText" msgid="493003724401350724">"Valige teksti jaoks toiming"</string>
<string name="volume_ringtone" msgid="134784084629229029">"Helina helitugevus"</string>
- <string name="volume_music" msgid="7727274216734955095">"Meediumi helitugevus"</string>
+ <string name="volume_music" msgid="7727274216734955095">"Meedia helitugevus"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Esitatakse Bluetoothi kaudu"</string>
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Valitud on hääletu märguanne"</string>
<string name="volume_call" msgid="7625321655265747433">"Kõne helitugevus"</string>
@@ -1236,7 +1236,7 @@
<string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Bluetoothi maht"</string>
<string name="volume_icon_description_ringer" msgid="2187800636867423459">"Helina tugevus"</string>
<string name="volume_icon_description_incall" msgid="4491255105381227919">"Kõne helitugevus"</string>
- <string name="volume_icon_description_media" msgid="4997633254078171233">"Meediumi helitugevus"</string>
+ <string name="volume_icon_description_media" msgid="4997633254078171233">"Meedia helitugevus"</string>
<string name="volume_icon_description_notification" msgid="579091344110747279">"Teatise helitugevus"</string>
<string name="ringtone_default" msgid="9118299121288174597">"Vaikehelin"</string>
<string name="ringtone_default_with_actual" msgid="2709686194556159773">"Vaikimisi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6783b7700a67..fb0ec661b2cb 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -596,9 +596,9 @@
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"لطفاً چهره‌تان را مجدداً ثبت کنید."</string>
<string name="face_acquired_too_different" msgid="4699657338753282542">"دیگر چهره را تشخیص نمی‌دهد. دوباره امتحان کنید."</string>
<string name="face_acquired_too_similar" msgid="7684650785108399370">"بسیار شبیه قبلی است، لطفاً قیافه دیگری بگیرید."</string>
- <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"سرتان را کمی پایین آورید."</string>
- <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"سرتان را کمی پایین آورید."</string>
- <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"سرتان را کمی پایین آورید."</string>
+ <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"سرتان را کمی صاف بگیرید."</string>
+ <string name="face_acquired_tilt_too_extreme" msgid="8119978324129248059">"سرتان را کمی صاف بگیرید."</string>
+ <string name="face_acquired_roll_too_extreme" msgid="1442830503572636825">"سرتان را کمی صاف بگیرید."</string>
<string name="face_acquired_obscured" msgid="4917643294953326639">"هرچیزی را که حائل چهره‌تان است بردارید."</string>
<string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"بالای صفحه و همچنین نوار مشکی را تمیز کنید."</string>
<string-array name="face_acquired_vendor">
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 893433b7b8a2..7dd89aa93702 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1593,7 +1593,7 @@
<string name="kg_pattern_instructions" msgid="8366024510502517748">"Debuxa o teu padrón"</string>
<string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Introduce o PIN da tarxeta SIM"</string>
<string name="kg_pin_instructions" msgid="7355933174673539021">"Introduce o PIN"</string>
- <string name="kg_password_instructions" msgid="7179782578809398050">"Insire o teu contrasinal"</string>
+ <string name="kg_password_instructions" msgid="7179782578809398050">"Escribe o teu contrasinal"</string>
<string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"Agora a tarxeta SIM está desactivada. Introduce o código PUK para continuar. Ponte en contacto co operador para obter información detallada."</string>
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Introduce o código PIN desexado"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Confirma o código PIN desexado"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index f7f6214cc2b2..6ace38db11ff 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -189,7 +189,7 @@
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"આ ઉપકરણ પર તમારી કાર્યાલયની પ્રોફાઇલ હવે ઉપલબ્ધ નથી"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"પાસવર્ડના ઘણા વધુ પ્રયત્નો"</string>
<string name="device_ownership_relinquished" msgid="4080886992183195724">"વ્યવસ્થાપકે ડિવાઇસ વ્યક્તિગત ઉપયોગ માટે આપી દીધું છે"</string>
- <string name="network_logging_notification_title" msgid="554983187553845004">"ઉપકરણ સંચાલિત છે"</string>
+ <string name="network_logging_notification_title" msgid="554983187553845004">"ડિવાઇસ મેનેજ થયેલ છે"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"તમારી સંસ્થા આ ઉપકરણનું સંચાલન કરે છે અને નેટવર્ક ટ્રાફિફનું નિયમન કરી શકે છે. વિગતો માટે ટૅપ કરો."</string>
<string name="location_changed_notification_title" msgid="3620158742816699316">"ઍપ તમારા સ્થાનને ઍક્સેસ કરી શકે છે"</string>
<string name="location_changed_notification_text" msgid="7158423339982706912">"વધુ જાણવા માટે તમારા IT વ્યવસ્થાપકનો સંપર્ક કરો"</string>
@@ -314,7 +314,7 @@
<string name="permgrouplab_calllog" msgid="7926834372073550288">"કૉલ લૉગ"</string>
<string name="permgroupdesc_calllog" msgid="2026996642917801803">"ફોન કૉલ લૉગ વાંચો અને લખો"</string>
<string name="permgrouplab_phone" msgid="570318944091926620">"ફોન"</string>
- <string name="permgroupdesc_phone" msgid="270048070781478204">"ફોન કૉલ કરો અને સંચાલિત કરો"</string>
+ <string name="permgroupdesc_phone" msgid="270048070781478204">"ફોન કૉલ કરો અને મેનેજ કરો"</string>
<string name="permgrouplab_sensors" msgid="9134046949784064495">"બૉડી સેન્સર"</string>
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"તમારા મહત્વપૂર્ણ ચિહ્નો વિશે સેન્સર ડેટા ઍક્સેસ કરો"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"વિંડો કન્ટેન્ટ પુનઃપ્રાપ્ત કરો"</string>
@@ -365,7 +365,7 @@
<string name="permdesc_receiveWapPush" msgid="1638677888301778457">"એપ્લિકેશનને WAP સંદેશા પ્રાપ્ત કરવાની અને તેના પર પ્રક્રિયા કરવાની મંજૂરી આપે છે. આ પરવાનગીમાં તમને દર્શાવ્યા વિના તમને મોકલેલ સંદેશાઓનું નિરીક્ષણ કરવાની અને કાઢી નાખવાની ક્ષમતાનો સમાવેશ થાય છે."</string>
<string name="permlab_getTasks" msgid="7460048811831750262">"ચાલુ ઍપ્લિકેશનો પુનઃપ્રાપ્ત કરો"</string>
<string name="permdesc_getTasks" msgid="7388138607018233726">"એપ્લિકેશનને વર્તમાનમાં અને તાજેતરમાં ચાલી રહેલ Tasks વિશેની વિગતવાર માહિતી પુનઃપ્રાપ્ત કરવાની મંજૂરી આપે છે. આ એપ્લિકેશનને ઉપકરણ પર કઈ એપ્લિકેશન્સનો ઉપયોગ થાય છે તેના વિશેની માહિતી શોધવાની મંજૂરી આપી શકે છે."</string>
- <string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"પ્રોફાઇલ અને ઉપકરણ માલિકોને સંચાલિત કરો"</string>
+ <string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"પ્રોફાઇલ અને ડિવાઇસ માલિકોને મેનેજ કરો"</string>
<string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"એપ્લિકેશન્સને પ્રોફાઇલ માલિકો અને ઉપકરણ માલિકો સેટ કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_reorderTasks" msgid="7598562301992923804">"ચાલુ એપ્લિકેશન્સને ફરી ગોઠવો"</string>
<string name="permdesc_reorderTasks" msgid="8796089937352344183">"ઍપ્લિકેશનને અગ્રભૂમિ અને પૃષ્ટભૂમિમાં Tasks ખસેડવાની મંજૂરી આપે છે. તમારા ઇનપુટ વિના ઍપ્લિકેશન આ કરી શકે છે."</string>
@@ -530,7 +530,7 @@
<string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"ઍપને સ્ક્રીન લૉકની જટિલતાનું લેવલ (ઊંચું, મધ્યમ, નીચું અથવા કોઈ નહીં) જાણવાની મંજૂરી આપે છે, જે સ્ક્રીન લૉકના પ્રકાર અને લંબાઈની સંભવિત શ્રેણી સૂચવે છે. ઍપ વપરાશકર્તાઓને સ્ક્રીન લૉકને ચોક્કસ લેવલ સુધી અપડેટ કરવાનું સૂચન પણ કરી શકે છે, પરંતુ વપરાશકર્તાઓ મુક્ત રીતે અવગણીને નૅવિગેટ કરી શકે છે. નોંધી લો કે સ્ક્રીન લૉકનો plaintextમાં સંગ્રહ કરવામાં આવતો નથી, તેથી ઍપને ચોક્કસ પાસવર્ડની જાણ હોતી નથી."</string>
<string name="permlab_useBiometric" msgid="6314741124749633786">"બાયોમેટ્રિક હાર્ડવેરનો ઉપયોગ કરો"</string>
<string name="permdesc_useBiometric" msgid="7502858732677143410">"ઍપને પ્રમાણીકરણ માટે બાયોમેટ્રિક હાર્ડવેરનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
- <string name="permlab_manageFingerprint" msgid="7432667156322821178">"ફિંગરપ્રિન્ટ હાર્ડવેરને સંચાલિત કરો"</string>
+ <string name="permlab_manageFingerprint" msgid="7432667156322821178">"ફિંગરપ્રિન્ટ હાર્ડવેરને મેનેજ કરો"</string>
<string name="permdesc_manageFingerprint" msgid="2025616816437339865">"ઍપને ઉપયોગ માટે ફિંગરપ્રિન્ટ નમૂના ઉમેરવા અને કાઢી નાખવા માટે પદ્ધતિઓની વિનંતી કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_useFingerprint" msgid="1001421069766751922">"ફિંગરપ્રિન્ટ હાર્ડવેરનો ઉપયોગ કરો"</string>
<string name="permdesc_useFingerprint" msgid="412463055059323742">"ઍપને પ્રમાણીકરણ માટે ફિંગરપ્રિન્ટ હાર્ડવેરનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
@@ -634,8 +634,8 @@
<string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"એપ્લિકેશનને નવા ટેલિકોમ સિમ કનેક્શન્સની નોંધણી કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_register_call_provider" msgid="6135073566140050702">"નવા ટેલિકોમ કનેક્શન્સની નોંધણી કરો"</string>
<string name="permdesc_register_call_provider" msgid="4201429251459068613">"એપ્લિકેશનને નવા ટેલિકોમ કનેક્શન્સની નોંધણી કરવાની મંજૂરી આપે છે."</string>
- <string name="permlab_connection_manager" msgid="3179365584691166915">"ટેલિકોમ કનેક્શન્સ સંચાલિત કરો"</string>
- <string name="permdesc_connection_manager" msgid="1426093604238937733">"એપ્લિકેશનને ટેલીકોમ કનેક્શન્સને સંચાલિત કરવાની મંજૂરી આપે છે."</string>
+ <string name="permlab_connection_manager" msgid="3179365584691166915">"ટેલિકોમ કનેક્શનને મેનેજ કરો"</string>
+ <string name="permdesc_connection_manager" msgid="1426093604238937733">"ઍપને ટેલિકોમ કનેક્શનને મેનેજ કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_bind_incall_service" msgid="5990625112603493016">"ઇન-કૉલ સ્ક્રીન વડે ક્રિયાપ્રતિક્રિયા કરો"</string>
<string name="permdesc_bind_incall_service" msgid="4124917526967765162">"વપરાશકર્તા ઇન-કૉલ સ્ર્કીન ક્યારે અને કેવી રીતે જુએ છે તે નિયંત્રિત કરવાની એપ્લિકેશનને મંજૂરી આપે છે."</string>
<string name="permlab_bind_connection_service" msgid="5409268245525024736">"ટેલિફોની સેવાઓ સાથે વાર્તાલાપ કરો"</string>
@@ -644,8 +644,8 @@
<string name="permdesc_control_incall_experience" msgid="5896723643771737534">"એપ્લિકેશનને કૉલમાં વપરાશકર્તા અનુભવ પ્રદાન કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_readNetworkUsageHistory" msgid="8470402862501573795">"ઐતિહાસિક નેટવર્ક ઉપયોગ વાંચો"</string>
<string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"એપ્લિકેશનને ચોક્કસ નેટવર્ક્સ અને ઍપ્લિકેશનો માટે ઐતિહાસિક નેટવર્ક વપરાશ વાંચવાની મંજૂરી આપે છે."</string>
- <string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"નેટવર્ક નીતિ સંચાલિત કરો"</string>
- <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"ઍપ્લિકેશનને નેટવર્ક નીતિઓ સંચાલિત કરવાની અને ઍપ્લિકેશન-વિશિષ્ટ નિયમો નિર્ધારિત કરવાની મંજૂરી આપે છે."</string>
+ <string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"નેટવર્ક નીતિ મેનેજ કરો"</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"ઍપને નેટવર્ક નીતિઓ મેનેજ કરવાની અને ઍપ-વિશિષ્ટ નિયમો નિર્ધારિત કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"નેટવર્ક વપરાશ એકાઉન્ટિંગ સંશોધિત કરો"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"એપ્લિકેશનને કેવી રીતે ઍપ્લિકેશનો સામે નેટવર્ક વપરાશ ગણવામાં આવે છે તે સંશોધિત કરવાની મંજૂરી આપે છે. સામાન્ય ઍપ્લિકેશનો દ્વારા ઉપયોગમાં લેવા માટે નથી."</string>
<string name="permlab_accessNotifications" msgid="7130360248191984741">"ઍક્સેસ સૂચનાઓ"</string>
@@ -1435,8 +1435,8 @@
<string name="notification_ranker_binding_label" msgid="432708245635563763">"સૂચના રેંકર સેવા"</string>
<string name="vpn_title" msgid="5906991595291514182">"VPN સક્રિય કર્યું"</string>
<string name="vpn_title_long" msgid="6834144390504619998">"<xliff:g id="APP">%s</xliff:g> દ્વારા VPN સક્રિય થયું"</string>
- <string name="vpn_text" msgid="2275388920267251078">"નેટવર્કને સંચાલિત કરવા માટે ટૅપ કરો."</string>
- <string name="vpn_text_long" msgid="278540576806169831">"<xliff:g id="SESSION">%s</xliff:g> થી કનેક્ટ થયાં. નેટવર્કને સંચાલિત કરવા માટે ટૅપ કરો."</string>
+ <string name="vpn_text" msgid="2275388920267251078">"નેટવર્કને મેનેજ કરવા માટે ટૅપ કરો."</string>
+ <string name="vpn_text_long" msgid="278540576806169831">"<xliff:g id="SESSION">%s</xliff:g> થી કનેક્ટ થયાં. નેટવર્કને મેનેજ કરવા માટે ટૅપ કરો."</string>
<string name="vpn_lockdown_connecting" msgid="6096725311950342607">"હંમેશા-ચાલુ VPN કનેક્ટ થઈ રહ્યું છે…"</string>
<string name="vpn_lockdown_connected" msgid="2853127976590658469">"હંમેશા-ચાલુ VPN કનેક્ટ થયું"</string>
<string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"હંમેશાં-ચાલુ VPN થી ડિસ્કનેક્ટ થયું"</string>
@@ -1911,7 +1911,7 @@
<string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g>ને પિન કરો"</string>
<string name="unpin_target" msgid="3963318576590204447">"અનપિન કરો"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g>ને અનપિન કરો"</string>
- <string name="app_info" msgid="6113278084877079851">"ઍપ્લિકેશન માહિતી"</string>
+ <string name="app_info" msgid="6113278084877079851">"ઍપની માહિતી"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"ડેમો પ્રારંભ કરી રહ્યાં છે…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"ઉપકરણ ફરીથી સેટ કરી રહ્યાં છે…"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index b1fe76e760e2..a85ed708faba 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1228,7 +1228,7 @@
<string name="volume_music" msgid="7727274216734955095">"Մեդիա ձայնի բարձրություն"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Նվագարկում է Bluetooth-ի միջոցով"</string>
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Սահմանվել է անձայն զանգերանգ"</string>
- <string name="volume_call" msgid="7625321655265747433">"Մուտքային զանգի ձայնի ուժգնությունը"</string>
+ <string name="volume_call" msgid="7625321655265747433">"Խոսակցություն"</string>
<string name="volume_bluetooth_call" msgid="2930204618610115061">"Bluetooth-ի ներզանգի բարձրություն"</string>
<string name="volume_alarm" msgid="4486241060751798448">"Զարթուցիչի ձայնը"</string>
<string name="volume_notification" msgid="6864412249031660057">"Ծանուցումների ձայնի ուժգնությունը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index cc8071bf7b9a..cbcb131a64b0 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1228,7 +1228,7 @@
<string name="volume_music" msgid="7727274216734955095">"Volume media"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Memutar melalui Bluetooth"</string>
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Nada dering senyap disetel"</string>
- <string name="volume_call" msgid="7625321655265747433">"Volume saat-memanggil"</string>
+ <string name="volume_call" msgid="7625321655265747433">"Volume dalam panggilan"</string>
<string name="volume_bluetooth_call" msgid="2930204618610115061">"Volume saat-memanggil bluetooth"</string>
<string name="volume_alarm" msgid="4486241060751798448">"Volume alarm"</string>
<string name="volume_notification" msgid="6864412249031660057">"Volume pemberitahuan"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 093daf1c0069..3139dcee7482 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -61,7 +61,7 @@
<string name="ColpMmi" msgid="4736462893284419302">"Қосылған желі идентификаторы"</string>
<string name="ColrMmi" msgid="5889782479745764278">"Қосылған желі идентификаторын шектеу"</string>
<string name="CfMmi" msgid="8390012691099787178">"Қоңырауды басқа нөмірге бағыттау"</string>
- <string name="CwMmi" msgid="3164609577675404761">"Күтудегі қоңырау"</string>
+ <string name="CwMmi" msgid="3164609577675404761">"Қоңырауды ұстап тұру"</string>
<string name="BaMmi" msgid="7205614070543372167">"Қоңырауды бөгеу"</string>
<string name="PwdMmi" msgid="3360991257288638281">"Құпия сөз өзгерту"</string>
<string name="PinMmi" msgid="7133542099618330959">"PIN өзгерту"</string>
@@ -1228,9 +1228,9 @@
<string name="volume_music" msgid="7727274216734955095">"Mультимeдиа дыбыс деңгейі"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Bluetooth арқылы ойнату"</string>
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Үнсіз қоңырау әуенін орнату"</string>
- <string name="volume_call" msgid="7625321655265747433">"Келетін қоңырау дыбысының қаттылығы"</string>
+ <string name="volume_call" msgid="7625321655265747433">"Сөйлесу кезіндегі дыбыс деңгейі"</string>
<string name="volume_bluetooth_call" msgid="2930204618610115061">"Bluetooth қоңырауының қаттылығы"</string>
- <string name="volume_alarm" msgid="4486241060751798448">"Дабыл дыбысының қаттылығы"</string>
+ <string name="volume_alarm" msgid="4486241060751798448">"Дабыл дыбысының деңгейі"</string>
<string name="volume_notification" msgid="6864412249031660057">"Хабар дыбысының қаттылығы"</string>
<string name="volume_unknown" msgid="4041914008166576293">"Дыбыс қаттылығы"</string>
<string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Bluetooth дыбысының қаттылығы"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 53c92af2da3f..cc7c72abc180 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1228,8 +1228,8 @@
<string name="volume_music" msgid="7727274216734955095">"កម្រិត​សំឡេង​មេឌៀ"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"ចាក់​តាម​ប៊្លូធូស"</string>
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"កំណត់​សំឡេង​រោទ៍​ស្ងាត់"</string>
- <string name="volume_call" msgid="7625321655265747433">"កម្រិត​សំឡេង​ហៅ​ចូល"</string>
- <string name="volume_bluetooth_call" msgid="2930204618610115061">"កម្រិត​សំឡេង​ហៅ​ចូល​តាម​ប៊្លូធូស"</string>
+ <string name="volume_call" msgid="7625321655265747433">"កម្រិត​សំឡេង​ក្នុងពេលនិយាយទូរសព្ទ"</string>
+ <string name="volume_bluetooth_call" msgid="2930204618610115061">"កម្រិត​សំឡេង​ក្នុងពេលនិយាយទូរសព្ទ​តាម​ប៊្លូធូស"</string>
<string name="volume_alarm" msgid="4486241060751798448">"កម្រិត​សំឡេងម៉ោងរោទ៍"</string>
<string name="volume_notification" msgid="6864412249031660057">"កម្រិត​សំឡេង​ការ​ជូន​ដំណឹង"</string>
<string name="volume_unknown" msgid="4041914008166576293">"កម្រិត​សំឡេង"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 811973b205d5..d3a314859a88 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1230,7 +1230,7 @@
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"ಶಾಂತ ರಿಂಗ್‌ಟೋನ್ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
<string name="volume_call" msgid="7625321655265747433">"ಒಳ-ಕರೆಯ ವಾಲ್ಯೂಮ್"</string>
<string name="volume_bluetooth_call" msgid="2930204618610115061">"ಬ್ಲೂಟೂತ್‌‌ ಒಳ-ಕರೆಯ ವಾಲ್ಯೂಮ್"</string>
- <string name="volume_alarm" msgid="4486241060751798448">"ಅಲಾರಮ್ ವಾಲ್ಯೂಮ್"</string>
+ <string name="volume_alarm" msgid="4486241060751798448">"ಅಲಾರಂ ವಾಲ್ಯೂಮ್"</string>
<string name="volume_notification" msgid="6864412249031660057">"ಅಧಿಸೂಚನೆಯ ವಾಲ್ಯೂಮ್"</string>
<string name="volume_unknown" msgid="4041914008166576293">"ವಾಲ್ಯೂಮ್"</string>
<string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"ಬ್ಲೂಟೂತ್‌‌ ವಾಲ್ಯೂಮ್"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index b2e2c1df8226..9e2e0a29544c 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -864,12 +864,12 @@
<string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Колдонуучунун нускамасын караңыз же Кардарларды тейлөө борборуна кайрылыңыз."</string>
<string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"SIM-карта бөгөттөлгөн."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"SIM-карта бөгөттөн чыгарылууда…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"Кулпуну ачуу үлгүсүн <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"Сырсөзүңүздү <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"PIN-кодуңузду <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"Кулпуну ачуу үлгүсүн <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес тартсаңыз, планшетиңиздин кулпусун Google\'га кирип ачууга туура келет.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес тартсаңыз, планшетиңиздин кулпусун Google\'га кирип ачууга туура келет.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"Графикалык ачкычыңызды <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес чийдиңиз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, Android TV түзмөгүңүздүн кулпусун Google аккаунтуңузга кирип ачышыңыз керек болот.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайталап көрүңүз."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"Кулпуну ачуу үлгүсүн <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес тартсаңыз, телефонуңуздун кулпусун Google\'га кирип ачууга туура келет.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес тартсаңыз, телефонуңуздун кулпусун Google\'га кирип ачууга туура келет.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин дагы аракет кылып көрүңүз."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"Сиз планшетиңизди бөгөттөн чыгарууга <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> аракеттен кийин, планшет баштапкы абалына келтирилет жана бардык маалыматтар өчүрүлөт."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"Android TV түзмөгүңүздүн кулпусун <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин, Android TV түзмөгүңүз демейки жөндөөлөргө кайтарылып, бардык колдонуучу дайындары жоголот."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"Сиз телефонуңузду бөгөттөн чыгарууга <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> аракеттен кийин, телефон баштапкы абалына келтирилет жана бардык маалыматтар өчүрүлөт."</string>
@@ -1228,7 +1228,7 @@
<string name="volume_music" msgid="7727274216734955095">"Мультимедианын катуулугу"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Bluetooth аркылуу ойнотулууда"</string>
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Үнсүз рингтон орнотулду"</string>
- <string name="volume_call" msgid="7625321655265747433">"Чалуудагы үн көлөмү"</string>
+ <string name="volume_call" msgid="7625321655265747433">"Сүйлөшүүнүн катуулугу"</string>
<string name="volume_bluetooth_call" msgid="2930204618610115061">"Bluetooth чалуудагы үн көлөмү"</string>
<string name="volume_alarm" msgid="4486241060751798448">"Ойготкучтун катуулугу"</string>
<string name="volume_notification" msgid="6864412249031660057">"Эскертме үн көлөмү"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index bbcfc63b3a38..6523784a42e4 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -275,7 +275,7 @@
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Машины горим"</string>
<string name="notification_channel_account" msgid="6436294521740148173">"Бүртгэлийн төлөв"</string>
<string name="notification_channel_developer" msgid="1691059964407549150">"Хөгжүүлэгчийн мессеж"</string>
- <string name="notification_channel_developer_important" msgid="7197281908918789589">"Хөгжүүлэгчийн чухал зурвас"</string>
+ <string name="notification_channel_developer_important" msgid="7197281908918789589">"Хөгжүүлэгчийн чухал мессеж"</string>
<string name="notification_channel_updates" msgid="7907863984825495278">"Шинэчлэлтүүд"</string>
<string name="notification_channel_network_status" msgid="2127687368725272809">"Сүлжээний төлөв"</string>
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"Сүлжээний сануулга"</string>
@@ -358,9 +358,9 @@
<string name="permlab_sendSms" msgid="7757368721742014252">"SMS мессежийг илгээх, харах"</string>
<string name="permdesc_sendSms" msgid="6757089798435130769">"Апп нь SMS мессеж илгээх боломжтой. Энэ нь санаандгүй төлбөрт оруулж болзошгүй. Хортой апп нь таны зөвшөөрөлгүйгээр мессеж илгээн таныг төлбөрт оруулж болзошгүй."</string>
<string name="permlab_readSms" msgid="5164176626258800297">"таны текст мессежийг унших(SMS эсвэл MMS)"</string>
- <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"Энэ апп таны таблетад хадгалсан бүх SMS (текст) зурвасыг унших боломжтой."</string>
+ <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"Энэ апп таны таблетад хадгалсан бүх SMS (текст) мессежийг унших боломжтой."</string>
<string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"Энэ апп таны Android TV төхөөрөмжид хадгалсан бүх SMS (текст) мессежийг уншиж чадна."</string>
- <string name="permdesc_readSms" product="default" msgid="774753371111699782">"Энэ апп таны утсанд хадгалсан бүх SMS (текст) зурвасыг унших боломжтой."</string>
+ <string name="permdesc_readSms" product="default" msgid="774753371111699782">"Энэ апп таны утсанд хадгалсан бүх SMS (текст) мессежийг унших боломжтой."</string>
<string name="permlab_receiveWapPush" msgid="4223747702856929056">"текст мессеж(WAP) хүлээн авах"</string>
<string name="permdesc_receiveWapPush" msgid="1638677888301778457">"Апп нь WAP мессежийг хүлээн авах болон биелүүлэх боломжтой. Энэ зөвшөөрөл нь танд илгээсэн мессежийг танд харуулалгүйгээр хянах эсвэл устгах боломжийг агуулна."</string>
<string name="permlab_getTasks" msgid="7460048811831750262">"ажиллаж байгаа апп-г дуудах"</string>
@@ -418,9 +418,9 @@
<string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Энэ апп таны Android TV төхөөрөмжид хадгалсан календарийн бүх арга хэмжээг унших болон таны календарийн өгөгдлийг хуваалцах эсвэл хадгалах боломжтой."</string>
<string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Энэ апп таны утсанд хадгалсан хуанлийн бүх арга хэмжээг унших, хуанлийн өгөгдлийг хуваалцах, хадгалах боломжтой."</string>
<string name="permlab_writeCalendar" msgid="6422137308329578076">"календарын хуваарийг нэмэх эсвэл өөрчлөх болон эзэмшигчид мэдэгдэлгүйгээр зочидруу имэйл илгээх"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Энэ апп таны таблет дээр хуанлийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь хуанли эзэмшигчээс зурвас илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Энэ апп таны таблет дээр хуанлийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь хуанли эзэмшигчээс мессеж илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
<string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"Энэ апп таны Android TV төхөөрөмжид календарийн арга хэмжээ нэмэх, үүнийг устгах, эсвэл өөрчлөх боломжтой. Энэ апп календарийн өмчлөгчөөс ирсэн мэт харагдаж болох мессеж илгээх эсвэл арга хэмжээг өмчлөгчид нь мэдэгдэлгүйгээр өөрчлөх боломжтой."</string>
- <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Энэ апп таны утсанд хуанлийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь хуанли эзэмшигчээс зурвас илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Энэ апп таны утсанд хуанлийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь хуанли эзэмшигчээс мессеж илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
<string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"байршил нийлүүлэгчийн нэмэлт тушаалд хандах"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Апп нь байршил нийлүүлэгчийн нэмэлт тушаалд хандах боломжтой. Энэ нь апп-д GPS эсвэл бусад байршлын үйлчилгээний ажиллагаанд нөлөөлөх боломжийг олгоно."</string>
<string name="permlab_accessFineLocation" msgid="6426318438195622966">"нарийвчилсан байршилд зөвхөн нүүр хэсэгт хандах"</string>
@@ -668,8 +668,8 @@
<string name="permdesc_handoverStatus" msgid="3842269451732571070">"Одоогийн Андройд Бийм дамжуулалтын мэдээллийг хүлээн авахыг аппликейшнд зөвшөөрөх"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"DRM сертификатыг устгах"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Аппликейшнд DRM сертификатыг устгахыг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
- <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"зөөгч зурвасын үйлчилгээнд холбох"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Эзэмшигчид зөөгч зурвасын үйлчилгээний түвшний интерфэйст холбогдохыг зөвшөөрдөг. Энгийн апп-д шаардлагагүй."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"зөөгч мессежийн үйлчилгээнд холбох"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Эзэмшигчид зөөгч мессежийн үйлчилгээний түвшний интерфэйст холбогдохыг зөвшөөрдөг. Энгийн апп-д шаардлагагүй."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"Үүрэн холбооны үйлчилгээ үзүүлэгчтэй холбогдох"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"Аливаа эзэмшигчийг үүрэн холбооны үйлчилгээ үзүүлэгчтэй холбодог. Энгийн аппд шаардлагагүй."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"Бүү саад бол тохируулгад хандалт хийх"</string>
@@ -966,7 +966,7 @@
<string name="permlab_setAlarm" msgid="1158001610254173567">"сэрүүлэг тохируулах"</string>
<string name="permdesc_setAlarm" msgid="2185033720060109640">"Апп нь суулгагдсан сэрүүлэгний апп дээр сэрүүлэг тохируулах боломжтой. Зарим сэрүүлэгний апп нь энэ функцийг дэмжихгүй байж болзошгүй."</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"дуут шуудан нэмэх"</string>
- <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Таны дуут шуудангийн ирсэн мэйлд зурвас нэмэхийг апп-д зөвшөөрөх."</string>
+ <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Таны дуут шуудангийн ирсэн мэйлд мессеж нэмэхийг апп-д зөвшөөрөх."</string>
<string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"Хөтчийн геобайршлын зөвшөөрлийг өөрчлөх"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Апп нь Хөтчийн гео байршлын зөвшөөрлийг өөрчлөх боломжтой. Хортой апп нь энийг ашиглан дурын веб хуудасруу байршлын мэдээллийг илгээх боломжтой."</string>
<string name="save_password_message" msgid="2146409467245462965">"Та хөтчид энэ нууц үгийг сануулах уу?"</string>
@@ -1900,7 +1900,7 @@
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> яг одоо боломжгүй байна."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Энэ аппыг Андройдын хуучин хувилбарт зориулсан бөгөөд буруу ажиллаж болзошгүй. Шинэчлэлтийг шалгаж эсвэл хөгжүүлэгчтэй холбогдоно уу."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Шинэчлэлтийг шалгах"</string>
- <string name="new_sms_notification_title" msgid="6528758221319927107">"Танд шинэ зурвасууд байна"</string>
+ <string name="new_sms_notification_title" msgid="6528758221319927107">"Танд шинэ мессежүүд байна"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"Үзэхийн тулд SMS аппыг нээх"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"Зарим функцийг хязгаарласан байж болзошгүй"</string>
<string name="profile_encrypted_detail" msgid="5279730442756849055">"Ажлын профайлыг түгжсэн"</string>
@@ -1968,7 +1968,7 @@
<string name="etws_primary_default_message_earthquake" msgid="8401079517718280669">"Тайван байж, ойролцоох нуугдах газар хайна уу."</string>
<string name="etws_primary_default_message_tsunami" msgid="5828171463387976279">"Эргийн бүс, голын эргийн бүсээс өндөрлөг газар зэрэг аюулгүй газар руу нэн даруй шилжинэ үү."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="4888224011071875068">"Тайван байж, ойролцоох нуугдах газар хайна уу."</string>
- <string name="etws_primary_default_message_test" msgid="4583367373909549421">"Онцгой байдлын зурвасын тест"</string>
+ <string name="etws_primary_default_message_test" msgid="4583367373909549421">"Онцгой байдлын мессежийн тест"</string>
<string name="notification_reply_button_accessibility" msgid="5235776156579456126">"Хариу бичих"</string>
<string name="etws_primary_default_message_others" msgid="7958161706019130739"></string>
<string name="mmcc_authentication_reject" msgid="4891965994643876369">"SIM-г дуу хоолойд зөвшөөрдөггүй"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 1dec3f977f00..11559f39565f 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1225,18 +1225,18 @@
<string name="dump_heap_ready_text" msgid="5849618132123045516">"ਸਾਂਝਾ ਕਰਨ ਲਈ <xliff:g id="PROC">%1$s</xliff:g> ਦੀ ਪ੍ਰਕਿਰਿਆ ਦਾ ਹੀਪ ਡੰਪ ਤੁਹਾਡੇ ਲਈ ਉਪਲਬਧ ਹੈ। ਸਾਵਧਾਨ ਰਹੋ: ਸ਼ਾਇਦ ਇਸ ਹੀਪ ਡੰਪ ਵਿੱਚ ਕੋਈ ਵੀ ਸੰਵੇਦਨਸ਼ੀਲ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋਵੇ, ਜਿਸ \'ਤੇ ਪ੍ਰਕਿਰਿਆ ਦੀ ਪਹੁੰਚ ਹੈ, ਜਿਸ ਵਿੱਚ ਸ਼ਾਇਦ ਤੁਹਾਡੇ ਵੱਲੋਂ ਟਾਈਪ ਕੀਤੀਆਂ ਚੀਜ਼ਾਂ ਸ਼ਾਮਲ ਹੋਣ।"</string>
<string name="sendText" msgid="493003724401350724">"ਲਿਖਤ ਲਈ ਕੋਈ ਕਾਰਵਾਈ ਚੁਣੋ"</string>
<string name="volume_ringtone" msgid="134784084629229029">"ਰਿੰਗਰ ਵੌਲਿਊਮ"</string>
- <string name="volume_music" msgid="7727274216734955095">"ਮੀਡੀਆ ਵੌਲਿਊਮ"</string>
+ <string name="volume_music" msgid="7727274216734955095">"ਮੀਡੀਆ ਦੀ ਅਵਾਜ਼"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Bluetooth ਰਾਹੀਂ ਪਲੇ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"ਖਾਮੋਸ਼ ਰਿੰਗਟੋਨ ਸੈੱਟ ਕੀਤੀ"</string>
<string name="volume_call" msgid="7625321655265747433">"ਇਨ-ਕਾਲ ਅਵਾਜ਼"</string>
<string name="volume_bluetooth_call" msgid="2930204618610115061">"ਬਲੂਟੁੱਥ ਇਨ-ਕਾਲ ਅਵਾਜ਼"</string>
- <string name="volume_alarm" msgid="4486241060751798448">"ਅਲਾਰਮ ਵੌਲਿਊਮ"</string>
+ <string name="volume_alarm" msgid="4486241060751798448">"ਅਲਾਰਮ ਦੀ ਅਵਾਜ਼"</string>
<string name="volume_notification" msgid="6864412249031660057">"ਸੂਚਨਾ ਵੌਲਿਊਮ"</string>
<string name="volume_unknown" msgid="4041914008166576293">"ਵੌਲਿਊਮ"</string>
<string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Bluetooth ਵੌਲਿਊਮ"</string>
<string name="volume_icon_description_ringer" msgid="2187800636867423459">"ਰਿੰਗਟੋਨ ਵੌਲਿਊਮ"</string>
<string name="volume_icon_description_incall" msgid="4491255105381227919">"ਕਾਲ ਅਵਾਜ਼"</string>
- <string name="volume_icon_description_media" msgid="4997633254078171233">"ਮੀਡੀਆ ਵੌਲਿਊਮ"</string>
+ <string name="volume_icon_description_media" msgid="4997633254078171233">"ਮੀਡੀਆ ਦੀ ਅਵਾਜ਼"</string>
<string name="volume_icon_description_notification" msgid="579091344110747279">"ਸੂਚਨਾ ਵੌਲਿਊਮ"</string>
<string name="ringtone_default" msgid="9118299121288174597">"ਪੂਰਵ-ਨਿਰਧਾਰਤ ਰਿੰਗਟੋਨ"</string>
<string name="ringtone_default_with_actual" msgid="2709686194556159773">"ਪੂਰਵ-ਨਿਰਧਾਰਤ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 3a8b28b8c7bf..35bf873dc5a6 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1270,7 +1270,7 @@
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Выбран режим \"Без звука\""</string>
<string name="volume_call" msgid="7625321655265747433">"Громкость при разговоре"</string>
<string name="volume_bluetooth_call" msgid="2930204618610115061">"Громкость при разговоре"</string>
- <string name="volume_alarm" msgid="4486241060751798448">"Громкость сигнала предупреждения"</string>
+ <string name="volume_alarm" msgid="4486241060751798448">"Громкость будильника"</string>
<string name="volume_notification" msgid="6864412249031660057">"Громкость уведомления"</string>
<string name="volume_unknown" msgid="4041914008166576293">"Громкость"</string>
<string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Громкость Bluetooth-устройства"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 9124c1231988..1ca8fb8bc482 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -307,7 +307,7 @@
<string name="permgroupdesc_storage" msgid="6351503740613026600">"ifikie picha, maudhui na faili kwenye kifaa chako"</string>
<string name="permgrouplab_microphone" msgid="2480597427667420076">"Maikrofoni"</string>
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"irekodi sauti"</string>
- <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Shughuli za kimwili"</string>
+ <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Mazoezi ya mwili"</string>
<string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"ifikie shughuli zako za kimwili"</string>
<string name="permgrouplab_camera" msgid="9090413408963547706">"Kamera"</string>
<string name="permgroupdesc_camera" msgid="7585150538459320326">"ipige picha na kurekodi video"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 2d56fb18d323..d959a37d8f3d 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -829,12 +829,12 @@
<string name="keyguard_password_enter_password_code" msgid="2751130557661643482">"అన్‌లాక్ చేయడానికి పాస్‌వర్డ్‌ను టైప్ చేయండి"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7792964196473964340">"అన్‌లాక్ చేయడానికి పిన్‌ను టైప్ చేయండి"</string>
<string name="keyguard_password_wrong_pin_code" msgid="8583732939138432793">"చెల్లని పిన్‌ కోడ్."</string>
- <string name="keyguard_label_text" msgid="3841953694564168384">"అన్‌లాక్ చేయడానికి, మెను ఆపై 0ని నొక్కండి."</string>
+ <string name="keyguard_label_text" msgid="3841953694564168384">"అన్‌లాక్ చేయడానికి, మెనూ ఆపై 0ని నొక్కండి."</string>
<string name="emergency_call_dialog_number_for_display" msgid="2978165477085612673">"అత్యవసర నంబర్"</string>
<string name="lockscreen_carrier_default" msgid="6192313772955399160">"సేవ లేదు"</string>
<string name="lockscreen_screen_locked" msgid="7364905540516041817">"స్క్రీన్ లాక్ చేయబడింది."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"అన్‌లాక్ చేయడానికి లేదా అత్యవసర కాల్ చేయడానికి మెను నొక్కండి."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"అన్‌లాక్ చేయడానికి మెను నొక్కండి."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"అన్‌లాక్ చేయడానికి లేదా అత్యవసర కాల్ చేయడానికి మెనూ నొక్కండి."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"అన్‌లాక్ చేయడానికి మెనూ నొక్కండి."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"అన్‌లాక్ చేయడానికి నమూనాను గీయండి"</string>
<string name="lockscreen_emergency_call" msgid="7549683825868928636">"ఎమర్జెన్సీ కాల్"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"కాల్‌కు తిరిగి వెళ్లు"</string>
@@ -977,7 +977,7 @@
<string name="text_copied" msgid="2531420577879738860">"వచనం క్లిప్‌బోర్డ్‌కు కాపీ చేయబడింది."</string>
<string name="copied" msgid="4675902854553014676">"కాపీ చేయబడింది"</string>
<string name="more_item_label" msgid="7419249600215749115">"ఎక్కువ"</string>
- <string name="prepend_shortcut_label" msgid="1743716737502867951">"మెను+"</string>
+ <string name="prepend_shortcut_label" msgid="1743716737502867951">"మెనూ+"</string>
<string name="menu_meta_shortcut_label" msgid="1623390163674762478">"Meta+"</string>
<string name="menu_ctrl_shortcut_label" msgid="131911133027196485">"Ctrl+"</string>
<string name="menu_alt_shortcut_label" msgid="343761069945250991">"Alt+"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 6a15ffc38432..4112fa5c4ff1 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1798,8 +1798,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Na-update ng iyong admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Na-delete ng iyong admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n\n• I-on ang Madilim na tema\n• I-off o paghihigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”\n\n"<annotation id="url">"Matuto pa"</annotation></string>
- <string name="battery_saver_description" msgid="6794188153647295212">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n\n• I-on ang Madilim na tema\n• I-off o paghihigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Para patagalin ang baterya, ginagawa ng Pantipid ng Baterya na:\n\n• I-on ang Madilim na tema\n• I-off o paghihigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”\n\n"<annotation id="url">"Matuto pa"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Para patagalin ang baterya, ginagawa ng Pantipid ng Baterya na:\n\n• I-on ang Madilim na tema\n• I-off o paghihigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Upang makatulong na mabawasan ang paggamit ng data, pinipigilan ng Data Saver ang ilang app na magpadala o makatanggap ng data sa background. Maaaring mag-access ng data ang isang app na ginagamit mo sa kasalukuyan, ngunit mas bihira na nito magagawa iyon. Halimbawa, maaaring hindi lumabas ang mga larawan hangga\'t hindi mo nata-tap ang mga ito."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"I-on ang Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"I-on"</string>
@@ -2007,9 +2007,9 @@
<string name="notification_feedback_indicator" msgid="663476517711323016">"Magbigay ng Feedback"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification ng impormasyon ng Routine Mode"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Maaaring maubos ang baterya bago ang karaniwang pag-charge"</string>
- <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Na-activate ang Pangtipid sa Baterya para patagalin ang buhay ng baterya"</string>
- <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Pangtipid sa Baterya"</string>
- <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Na-off ang Pangtipid sa Baterya"</string>
+ <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Na-activate ang Pantipid ng Baterya para patagalin ang buhay ng baterya"</string>
+ <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Pantipid ng Baterya"</string>
+ <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Na-off ang Pantipid ng Baterya"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"May sapat na charge ang telepono. Hindi na pinaghihigpitan ang mga feature."</string>
<string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"May sapat na charge ang tablet. Hindi na pinaghihigpitan ang mga feature."</string>
<string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"May sapat na charge ang device. Hindi na pinaghihigpitan ang mga feature."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5ad2ea188200..778e4a5789fb 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1268,9 +1268,9 @@
<string name="volume_music" msgid="7727274216734955095">"Гучність медіа"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Відтвор. через Bluetooth"</string>
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Установлено сигнал дзвінка без звуку"</string>
- <string name="volume_call" msgid="7625321655265747433">"Обсяг вхідних"</string>
- <string name="volume_bluetooth_call" msgid="2930204618610115061">"Обсяг вхідних Bluetooth"</string>
- <string name="volume_alarm" msgid="4486241060751798448">"Гучн. сповіщ."</string>
+ <string name="volume_call" msgid="7625321655265747433">"Гучність під час розмови"</string>
+ <string name="volume_bluetooth_call" msgid="2930204618610115061">"Гучність у викликах Bluetooth"</string>
+ <string name="volume_alarm" msgid="4486241060751798448">"Гучність будильника"</string>
<string name="volume_notification" msgid="6864412249031660057">"Гучність сповіщень"</string>
<string name="volume_unknown" msgid="4041914008166576293">"Гучність"</string>
<string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"Гучність Bluetooth"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 229e225ab63d..683a9115ce25 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1228,7 +1228,7 @@
<string name="volume_music" msgid="7727274216734955095">"Multimedia tovushi"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="2614142915948898228">"Bluetooth orqali ijro etilmoqda"</string>
<string name="volume_music_hint_silent_ringtone_selected" msgid="1514829655029062233">"Ovozsiz rejim tanlandi"</string>
- <string name="volume_call" msgid="7625321655265747433">"Suhbat vaqtidagi tovush balandligi"</string>
+ <string name="volume_call" msgid="7625321655265747433">"Suhbat tovushi"</string>
<string name="volume_bluetooth_call" msgid="2930204618610115061">"Kiruvchi bluetooth tovushi"</string>
<string name="volume_alarm" msgid="4486241060751798448">"Signal tovushi"</string>
<string name="volume_notification" msgid="6864412249031660057">"Eslatma tovushi"</string>
@@ -1240,7 +1240,7 @@
<string name="volume_icon_description_notification" msgid="579091344110747279">"Eslatma tovushi"</string>
<string name="ringtone_default" msgid="9118299121288174597">"Standart rington"</string>
<string name="ringtone_default_with_actual" msgid="2709686194556159773">"Standart (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
- <string name="ringtone_silent" msgid="397111123930141876">"Yo‘q"</string>
+ <string name="ringtone_silent" msgid="397111123930141876">"Hech qanday"</string>
<string name="ringtone_picker_title" msgid="667342618626068253">"Ringtonlar"</string>
<string name="ringtone_picker_title_alarm" msgid="7438934548339024767">"Signal ovozlari"</string>
<string name="ringtone_picker_title_notification" msgid="6387191794719608122">"Bildirishnoma ovozlari"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6e03398283ac..3295df1122d0 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -817,6 +817,30 @@
<!-- B y-intercept --> <item>-0.198650895</item>
</string-array>
+ <string-array name="config_reduceBrightColorsCoefficientsNative">
+ <!-- R a-coefficient --> <item>-0.691218457</item>
+ <!-- R b-coefficient --> <item>0.050135153</item>
+ <!-- R y-intercept --> <item>0.917684143</item>
+ <!-- G a-coefficient --> <item>-0.691218457</item>
+ <!-- G b-coefficient --> <item>0.050135153</item>
+ <!-- G y-intercept --> <item>0.917684143</item>
+ <!-- B a-coefficient --> <item>-0.691218457</item>
+ <!-- B b-coefficient --> <item>0.050135153</item>
+ <!-- B y-intercept --> <item>0.917684143</item>
+ </string-array>
+
+ <string-array name="config_reduceBrightColorsCoefficients">
+ <!-- R a-coefficient --> <item>0.00000000000000154</item>
+ <!-- R b-coefficient --> <item>-1.0</item>
+ <!-- R y-intercept --> <item>1.045977011</item>
+ <!-- G a-coefficient --> <item>0.00000000000000224</item>
+ <!-- G b-coefficient --> <item>-1.0</item>
+ <!-- G y-intercept --> <item>1.045977011</item>
+ <!-- B a-coefficient --> <item>0.0000000000000022</item>
+ <!-- B b-coefficient --> <item>-1.0</item>
+ <!-- B y-intercept --> <item>1.045977011</item>
+ </string-array>
+
<!-- Boolean indicating whether display white balance is supported. -->
<bool name="config_displayWhiteBalanceAvailable">false</bool>
@@ -1671,6 +1695,13 @@
<item>com.android.location.fused</item>
</string-array>
+ <!-- Gnss Psds Servers -->
+ <string name="config_longterm_psds_server_1" translatable="false"></string>
+ <string name="config_longterm_psds_server_2" translatable="false"></string>
+ <string name="config_longterm_psds_server_3" translatable="false"></string>
+ <string name="config_normal_psds_server" translatable="false"></string>
+ <string name="config_realtime_psds_server" translatable="false"></string>
+
<!-- This string array can be overriden to enable test location providers initially. -->
<!-- Array of "[locationProviderName],[requiresNetwork],
[requiresSatellite],[requiresCell],[hasMonetaryCost],
@@ -4479,4 +4510,7 @@
activity-level letterboxing (size-compat mode). Therefore this override can control the
maximum screen area that can be occupied by the app in the letterbox mode. -->
<item name="config_taskLetterboxAspectRatio" format="float" type="dimen">0.0</item>
+
+ <!-- If true, hide the display cutout with display area -->
+ <bool name="config_hideDisplayCutoutWithDisplayArea">false</bool>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a294c9d1e537..fba431c66f53 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1861,6 +1861,11 @@
<java-symbol type="array" name="config_locationProviderPackageNames" />
<java-symbol type="array" name="config_locationExtraPackageNames" />
<java-symbol type="array" name="config_testLocationProviders" />
+ <java-symbol type="string" name="config_longterm_psds_server_1" />
+ <java-symbol type="string" name="config_longterm_psds_server_2" />
+ <java-symbol type="string" name="config_longterm_psds_server_3" />
+ <java-symbol type="string" name="config_normal_psds_server" />
+ <java-symbol type="string" name="config_realtime_psds_server" />
<java-symbol type="array" name="config_defaultNotificationVibePattern" />
<java-symbol type="array" name="config_notificationFallbackVibePattern" />
<java-symbol type="bool" name="config_enableServerNotificationEffectsForAutomotive" />
@@ -3158,6 +3163,8 @@
<java-symbol type="integer" name="config_nightDisplayColorTemperatureMax" />
<java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficients" />
<java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />
+ <java-symbol type="array" name="config_reduceBrightColorsCoefficients" />
+ <java-symbol type="array" name="config_reduceBrightColorsCoefficientsNative" />
<java-symbol type="array" name="config_availableColorModes" />
<java-symbol type="integer" name="config_accessibilityColorMode" />
<java-symbol type="array" name="config_displayCompositionColorModes" />
@@ -4088,4 +4095,6 @@
<java-symbol type="dimen" name="controls_thumbnail_image_max_width" />
<java-symbol type="dimen" name="config_taskLetterboxAspectRatio" />
+
+ <java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" />
</resources>
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index 9246a2335050..f4a454bcebd6 100644
--- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -311,6 +311,7 @@ public class BugreportManagerTest {
final File f = File.createTempFile(prefix, extension);
f.setReadable(true, true);
f.setWritable(true, true);
+
f.deleteOnExit();
return f;
}
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 400b05c09fa5..4fe68cd5a27a 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -73,6 +73,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
/**
* Test for verifying {@link android.app.ActivityThread} class.
@@ -173,29 +174,41 @@ public class ActivityThreadTest {
@Test
public void testHandleActivity_assetsChanged() {
+ relaunchActivityAndAssertPreserveWindow(activity -> {
+ // Relaunches all activities.
+ activity.getActivityThread().handleApplicationInfoChanged(
+ activity.getApplicationInfo());
+ });
+ }
+
+ @Test
+ public void testRecreateActivity() {
+ relaunchActivityAndAssertPreserveWindow(Activity::recreate);
+ }
+
+ private void relaunchActivityAndAssertPreserveWindow(Consumer<Activity> relaunch) {
final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+ final ActivityThread activityThread = activity.getActivityThread();
final IBinder[] token = new IBinder[1];
final View[] decorView = new View[1];
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- final ActivityThread activityThread = activity.getActivityThread();
-
token[0] = activity.getActivityToken();
decorView[0] = activity.getWindow().getDecorView();
- // Relaunches all activities
- activityThread.handleApplicationInfoChanged(activity.getApplicationInfo());
+ relaunch.accept(activity);
});
final View[] newDecorView = new View[1];
- InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- final ActivityThread activityThread = activity.getActivityThread();
+ final Activity[] newActivity = new Activity[1];
- final Activity newActivity = activityThread.getActivity(token[0]);
- newDecorView[0] = activity.getWindow().getDecorView();
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ newActivity[0] = activityThread.getActivity(token[0]);
+ newDecorView[0] = newActivity[0].getWindow().getDecorView();
});
+ assertNotEquals("Activity must be relaunched", activity, newActivity[0]);
assertEquals("Window must be preserved", decorView[0], newDecorView[0]);
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 7766b575c156..5871e2e04687 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -672,5 +672,11 @@ public class TransactionParcelTests {
public void notifyContentProviderPublishStatus(ContentProviderHolder holder, String auth,
int userId, boolean published) {
}
+
+ @Override
+ public void instrumentWithoutRestart(ComponentName instrumentationName,
+ Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
+ IUiAutomationConnection instrumentationUiConnection, ApplicationInfo targetInfo) {
+ }
}
}
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index 2d16f826b243..cfed2cef9ce6 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -17,6 +17,7 @@
package android.graphics;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.content.Context;
@@ -34,6 +35,9 @@ import com.android.frameworks.coretests.R;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
import java.util.Random;
@RunWith(AndroidJUnit4.class)
@@ -171,4 +175,27 @@ public class TypefaceTest {
}
+ @SmallTest
+ @Test
+ public void testSerialize() throws Exception {
+ int size = Typeface.writeTypefaces(null, Arrays.asList(mFaces));
+ ByteBuffer buffer = ByteBuffer.allocateDirect(size);
+ Typeface.writeTypefaces(buffer, Arrays.asList(mFaces));
+ List<Typeface> copiedTypefaces = Typeface.readTypefaces(buffer);
+ assertNotNull(copiedTypefaces);
+ assertEquals(mFaces.length, copiedTypefaces.size());
+ for (int i = 0; i < mFaces.length; i++) {
+ Typeface original = mFaces[i];
+ Typeface copied = copiedTypefaces.get(i);
+ assertEquals(original.getStyle(), copied.getStyle());
+ assertEquals(original.getWeight(), copied.getWeight());
+ assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6);
+ }
+ }
+
+ private static float measureText(Typeface typeface, String text) {
+ Paint paint = new Paint();
+ paint.setTypeface(typeface);
+ return paint.measureText(text);
+ }
}
diff --git a/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java b/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java
index faa67a8bbd62..6955ca84103e 100644
--- a/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java
+++ b/core/tests/coretests/src/android/os/CombinedVibrationEffectTest.java
@@ -26,22 +26,128 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.Arrays;
+
@Presubmit
@RunWith(JUnit4.class)
public class CombinedVibrationEffectTest {
+ private static final VibrationEffect VALID_EFFECT = VibrationEffect.createOneShot(10, 255);
+ private static final VibrationEffect INVALID_EFFECT = new VibrationEffect.OneShot(-1, -1);
+
@Test
public void testValidateMono() {
- CombinedVibrationEffect.createSynced(VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
+ CombinedVibrationEffect.createSynced(VALID_EFFECT);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> CombinedVibrationEffect.createSynced(INVALID_EFFECT));
+ }
+
+ @Test
+ public void testValidateStereo() {
+ CombinedVibrationEffect.startSynced()
+ .addVibrator(0, VALID_EFFECT)
+ .addVibrator(1, VibrationEffect.get(VibrationEffect.EFFECT_TICK))
+ .combine();
+ CombinedVibrationEffect.startSynced()
+ .addVibrator(0, INVALID_EFFECT)
+ .addVibrator(0, VALID_EFFECT)
+ .combine();
assertThrows(IllegalArgumentException.class,
- () -> CombinedVibrationEffect.createSynced(new VibrationEffect.OneShot(-1, -1)));
+ () -> CombinedVibrationEffect.startSynced()
+ .addVibrator(0, INVALID_EFFECT)
+ .combine());
+ }
+
+ @Test
+ public void testValidateSequential() {
+ CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT)
+ .addNext(CombinedVibrationEffect.createSynced(VALID_EFFECT))
+ .combine();
+ CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT)
+ .addNext(0, VALID_EFFECT, 100)
+ .combine();
+ CombinedVibrationEffect.startSequential()
+ .addNext(CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT)
+ .combine())
+ .combine();
+
+ assertThrows(IllegalArgumentException.class,
+ () -> CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT, -1)
+ .combine());
+ assertThrows(IllegalArgumentException.class,
+ () -> CombinedVibrationEffect.startSequential()
+ .addNext(0, INVALID_EFFECT)
+ .combine());
+ }
+
+ @Test
+ public void testNestedSequentialAccumulatesDelays() {
+ CombinedVibrationEffect.Sequential combined =
+ (CombinedVibrationEffect.Sequential) CombinedVibrationEffect.startSequential()
+ .addNext(CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT, /* delay= */ 100)
+ .addNext(1, VALID_EFFECT, /* delay= */ 100)
+ .combine(),
+ /* delay= */ 10)
+ .addNext(CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT, /* delay= */ 100)
+ .combine())
+ .addNext(CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT)
+ .addNext(0, VALID_EFFECT, /* delay= */ 100)
+ .combine(),
+ /* delay= */ 10)
+ .combine();
+
+ assertEquals(Arrays.asList(110, 100, 100, 10, 100), combined.getDelays());
+ }
+
+ @Test
+ public void testCombineEmptyFails() {
+ assertThrows(IllegalStateException.class,
+ () -> CombinedVibrationEffect.startSynced().combine());
+ assertThrows(IllegalStateException.class,
+ () -> CombinedVibrationEffect.startSequential().combine());
}
@Test
public void testSerializationMono() {
- CombinedVibrationEffect original = CombinedVibrationEffect.createSynced(
- VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
+ CombinedVibrationEffect original = CombinedVibrationEffect.createSynced(VALID_EFFECT);
+
+ Parcel parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ CombinedVibrationEffect restored = CombinedVibrationEffect.CREATOR.createFromParcel(parcel);
+ assertEquals(original, restored);
+ }
+
+ @Test
+ public void testSerializationStereo() {
+ CombinedVibrationEffect original = CombinedVibrationEffect.startSynced()
+ .addVibrator(0, VibrationEffect.get(VibrationEffect.EFFECT_CLICK))
+ .addVibrator(1, VibrationEffect.createOneShot(10, 255))
+ .combine();
+
+ Parcel parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ CombinedVibrationEffect restored = CombinedVibrationEffect.CREATOR.createFromParcel(parcel);
+ assertEquals(original, restored);
+ }
+
+ @Test
+ public void testSerializationSequential() {
+ CombinedVibrationEffect original = CombinedVibrationEffect.startSequential()
+ .addNext(0, VALID_EFFECT)
+ .addNext(CombinedVibrationEffect.createSynced(VALID_EFFECT))
+ .addNext(0, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), 100)
+ .combine();
Parcel parcel = Parcel.obtain();
original.writeToParcel(parcel, 0);
diff --git a/core/tests/coretests/src/android/util/BinaryXmlTest.java b/core/tests/coretests/src/android/util/BinaryXmlTest.java
new file mode 100644
index 000000000000..be63a0ecc65f
--- /dev/null
+++ b/core/tests/coretests/src/android/util/BinaryXmlTest.java
@@ -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.
+ */
+
+package android.util;
+
+import static android.util.XmlTest.assertNext;
+import static android.util.XmlTest.buildPersistableBundle;
+import static android.util.XmlTest.doPersistableBundleRead;
+import static android.util.XmlTest.doPersistableBundleWrite;
+
+import static org.junit.Assert.assertEquals;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
+import android.os.PersistableBundle;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+
+@RunWith(AndroidJUnit4.class)
+public class BinaryXmlTest {
+ /**
+ * Verify that we can write and read large numbers of interned
+ * {@link String} values.
+ */
+ @Test
+ public void testLargeInterned_Binary() throws Exception {
+ // We're okay with the tag itself being interned
+ final int count = (1 << 16) - 2;
+
+ final TypedXmlSerializer out = Xml.newBinarySerializer();
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ out.setOutput(os, StandardCharsets.UTF_8.name());
+ out.startTag(null, "tag");
+ for (int i = 0; i < count; i++) {
+ out.attribute(null, "name" + i, "value");
+ }
+ out.endTag(null, "tag");
+ out.flush();
+
+ final TypedXmlPullParser in = Xml.newBinaryPullParser();
+ final ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
+ in.setInput(is, StandardCharsets.UTF_8.name());
+ assertNext(in, START_TAG, "tag", 1);
+ assertEquals(count, in.getAttributeCount());
+ }
+
+ @Test
+ public void testTranscode_FastToBinary() throws Exception {
+ doTranscode(Xml.newFastSerializer(), Xml.newFastPullParser(),
+ Xml.newBinarySerializer(), Xml.newBinaryPullParser());
+ }
+
+ @Test
+ public void testTranscode_BinaryToFast() throws Exception {
+ doTranscode(Xml.newBinarySerializer(), Xml.newBinaryPullParser(),
+ Xml.newFastSerializer(), Xml.newFastPullParser());
+ }
+
+ /**
+ * Verify that a complex {@link PersistableBundle} can be transcoded using
+ * the two given formats with the original structure intact.
+ */
+ private static void doTranscode(TypedXmlSerializer firstOut, TypedXmlPullParser firstIn,
+ TypedXmlSerializer secondOut, TypedXmlPullParser secondIn) throws Exception {
+ final PersistableBundle expected = buildPersistableBundle();
+ final byte[] firstRaw = doPersistableBundleWrite(firstOut, expected);
+
+ // Perform actual transcoding between the two formats
+ final ByteArrayInputStream is = new ByteArrayInputStream(firstRaw);
+ firstIn.setInput(is, StandardCharsets.UTF_8.name());
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ secondOut.setOutput(os, StandardCharsets.UTF_8.name());
+ Xml.copy(firstIn, secondOut);
+
+ // Yes, this string-based check is fragile, but kindofEquals() is broken
+ // when working with nested objects and arrays
+ final PersistableBundle actual = doPersistableBundleRead(secondIn, os.toByteArray());
+ assertEquals(expected.toString(), actual.toString());
+ }
+}
diff --git a/core/tests/coretests/src/android/util/CharsetUtilsTest.java b/core/tests/coretests/src/android/util/CharsetUtilsTest.java
new file mode 100644
index 000000000000..c29545168758
--- /dev/null
+++ b/core/tests/coretests/src/android/util/CharsetUtilsTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.HexDump;
+
+import dalvik.system.VMRuntime;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CharsetUtilsTest {
+ private byte[] dest;
+ private long destPtr;
+
+ @Before
+ public void setUp() {
+ dest = (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, 8);
+ destPtr = VMRuntime.getRuntime().addressOf(dest);
+ }
+
+ @Test
+ public void testModifiedUtf8_Empty() {
+ assertEquals(0, CharsetUtils.toModifiedUtf8Bytes("", destPtr, 0, dest.length));
+ assertEquals("0000000000000000", HexDump.toHexString(dest));
+ assertEquals("", CharsetUtils.fromModifiedUtf8Bytes(destPtr, 0, 0));
+ }
+
+ @Test
+ public void testModifiedUtf8_Null() {
+ assertEquals(4, CharsetUtils.toModifiedUtf8Bytes("!\0!", destPtr, 0, dest.length));
+ assertEquals("21C0802100000000", HexDump.toHexString(dest));
+ assertEquals("!\0!", CharsetUtils.fromModifiedUtf8Bytes(destPtr, 0, 4));
+ }
+
+ @Test
+ public void testModifiedUtf8_Simple() {
+ assertEquals(7, CharsetUtils.toModifiedUtf8Bytes("example", destPtr, 0, dest.length));
+ assertEquals("6578616D706C6500", HexDump.toHexString(dest));
+ assertEquals("example", CharsetUtils.fromModifiedUtf8Bytes(destPtr, 0, 7));
+ }
+
+ @Test
+ public void testModifiedUtf8_Complex() {
+ assertEquals(3, CharsetUtils.toModifiedUtf8Bytes("☃", destPtr, 4, dest.length));
+ assertEquals("00000000E2988300", HexDump.toHexString(dest));
+ assertEquals("☃", CharsetUtils.fromModifiedUtf8Bytes(destPtr, 4, 3));
+ }
+
+ @Test
+ public void testModifiedUtf8_Bounds() {
+ assertEquals(-3, CharsetUtils.toModifiedUtf8Bytes("foo", destPtr, 0, 0));
+ assertEquals(-3, CharsetUtils.toModifiedUtf8Bytes("foo", destPtr, 0, 2));
+ assertEquals(-3, CharsetUtils.toModifiedUtf8Bytes("foo", destPtr, -2, 8));
+ assertEquals(-3, CharsetUtils.toModifiedUtf8Bytes("foo", destPtr, 6, 8));
+ assertEquals(-3, CharsetUtils.toModifiedUtf8Bytes("foo", destPtr, 10, 8));
+ }
+
+ @Test
+ public void testModifiedUtf8_Overwrite() {
+ assertEquals(5, CharsetUtils.toModifiedUtf8Bytes("!!!!!", destPtr, 0, dest.length));
+ assertEquals(3, CharsetUtils.toModifiedUtf8Bytes("...", destPtr, 0, dest.length));
+ assertEquals(1, CharsetUtils.toModifiedUtf8Bytes("?", destPtr, 0, dest.length));
+ assertEquals("3F002E0021000000", HexDump.toHexString(dest));
+ }
+}
diff --git a/core/tests/coretests/src/android/util/XmlTest.java b/core/tests/coretests/src/android/util/XmlTest.java
new file mode 100644
index 000000000000..a30381afcd6d
--- /dev/null
+++ b/core/tests/coretests/src/android/util/XmlTest.java
@@ -0,0 +1,305 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.START_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import static org.xmlpull.v1.XmlPullParser.TEXT;
+
+import android.os.PersistableBundle;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.XmlUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+public class XmlTest {
+ @Test
+ public void testLargeValues_Normal() throws Exception {
+ doLargeValues(XmlUtils.makeTyped(Xml.newSerializer()),
+ XmlUtils.makeTyped(Xml.newPullParser()));
+ }
+
+ @Test
+ public void testLargeValues_Fast() throws Exception {
+ doLargeValues(Xml.newFastSerializer(),
+ Xml.newFastPullParser());
+ }
+
+ @Test
+ public void testLargeValues_Binary() throws Exception {
+ doLargeValues(Xml.newBinarySerializer(),
+ Xml.newBinaryPullParser());
+ }
+
+ /**
+ * Verify that we can write and read large {@link String} and {@code byte[]}
+ * without issues.
+ */
+ private static void doLargeValues(TypedXmlSerializer out, TypedXmlPullParser in)
+ throws Exception {
+ final char[] chars = new char[65_534];
+ Arrays.fill(chars, '!');
+
+ final String string = new String(chars);
+ final byte[] bytes = string.getBytes();
+ assertEquals(chars.length, bytes.length);
+
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ out.setOutput(os, StandardCharsets.UTF_8.name());
+ out.startTag(null, "tag");
+ out.attribute(null, "string", string);
+ out.attributeBytesBase64(null, "bytes", bytes);
+ out.endTag(null, "tag");
+ out.flush();
+
+ final ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
+ in.setInput(is, StandardCharsets.UTF_8.name());
+ assertNext(in, START_TAG, "tag", 1);
+ assertEquals(2, in.getAttributeCount());
+ assertEquals(string, in.getAttributeValue(null, "string"));
+ assertArrayEquals(bytes, in.getAttributeBytesBase64(null, "bytes"));
+ }
+
+ @Test
+ public void testPersistableBundle_Normal() throws Exception {
+ doPersistableBundle(XmlUtils.makeTyped(Xml.newSerializer()),
+ XmlUtils.makeTyped(Xml.newPullParser()));
+ }
+
+ @Test
+ public void testPersistableBundle_Fast() throws Exception {
+ doPersistableBundle(Xml.newFastSerializer(),
+ Xml.newFastPullParser());
+ }
+
+ @Test
+ public void testPersistableBundle_Binary() throws Exception {
+ doPersistableBundle(Xml.newBinarySerializer(),
+ Xml.newBinaryPullParser());
+ }
+
+ /**
+ * Verify that a complex {@link PersistableBundle} can be serialized out and
+ * then parsed in with the original structure intact.
+ */
+ private static void doPersistableBundle(TypedXmlSerializer out, TypedXmlPullParser in)
+ throws Exception {
+ final PersistableBundle expected = buildPersistableBundle();
+ final byte[] raw = doPersistableBundleWrite(out, expected);
+
+ // Yes, this string-based check is fragile, but kindofEquals() is broken
+ // when working with nested objects and arrays
+ final PersistableBundle actual = doPersistableBundleRead(in, raw);
+ assertEquals(expected.toString(), actual.toString());
+ }
+
+ static PersistableBundle buildPersistableBundle() {
+ final PersistableBundle outer = new PersistableBundle();
+
+ outer.putBoolean("boolean", true);
+ outer.putInt("int", 42);
+ outer.putLong("long", 43L);
+ outer.putDouble("double", 44d);
+ outer.putString("string", "com.example <and></and> &amp; more");
+
+ outer.putBooleanArray("boolean[]", new boolean[] { true, false, true });
+ outer.putIntArray("int[]", new int[] { 42, 43, 44 });
+ outer.putLongArray("long[]", new long[] { 43L, 44L, 45L });
+ outer.putDoubleArray("double[]", new double[] { 43d, 44d, 45d });
+ outer.putStringArray("string[]", new String[] { "foo", "bar", "baz" });
+
+ final PersistableBundle nested = new PersistableBundle();
+ nested.putString("nested_key", "nested_value");
+ outer.putPersistableBundle("nested", nested);
+
+ return outer;
+ }
+
+ static byte[] doPersistableBundleWrite(TypedXmlSerializer out, PersistableBundle bundle)
+ throws Exception {
+ // We purposefully omit START/END_DOCUMENT events here to verify correct
+ // behavior of what PersistableBundle does internally
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ out.setOutput(os, StandardCharsets.UTF_8.name());
+ out.startTag(null, "bundle");
+ bundle.saveToXml(out);
+ out.endTag(null, "bundle");
+ out.flush();
+ return os.toByteArray();
+ }
+
+ static PersistableBundle doPersistableBundleRead(TypedXmlPullParser in, byte[] raw)
+ throws Exception {
+ final ByteArrayInputStream is = new ByteArrayInputStream(raw);
+ in.setInput(is, StandardCharsets.UTF_8.name());
+ in.next();
+ return PersistableBundle.restoreFromXml(in);
+ }
+
+ @Test
+ public void testVerify_Normal() throws Exception {
+ doVerify(XmlUtils.makeTyped(Xml.newSerializer()),
+ XmlUtils.makeTyped(Xml.newPullParser()));
+ }
+
+ @Test
+ public void testVerify_Fast() throws Exception {
+ doVerify(Xml.newFastSerializer(),
+ Xml.newFastPullParser());
+ }
+
+ @Test
+ public void testVerify_Binary() throws Exception {
+ doVerify(Xml.newBinarySerializer(),
+ Xml.newBinaryPullParser());
+ }
+
+ /**
+ * Verify that example test data is correctly serialized and parsed
+ * end-to-end using the given objects.
+ */
+ private static void doVerify(TypedXmlSerializer out, TypedXmlPullParser in) throws Exception {
+ final ByteArrayOutputStream os = new ByteArrayOutputStream();
+ out.setOutput(os, StandardCharsets.UTF_8.name());
+ doVerifyWrite(out);
+ out.flush();
+
+ final ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
+ in.setInput(is, StandardCharsets.UTF_8.name());
+ doVerifyRead(in);
+ }
+
+ private static final String TEST_STRING = "com.example";
+ private static final byte[] TEST_BYTES = new byte[] { 0, 1, 2, 3, 4, 3, 2, 1, 0 };
+
+ private static void doVerifyWrite(TypedXmlSerializer out) throws Exception {
+ out.startDocument(StandardCharsets.UTF_8.name(), true);
+ out.startTag(null, "one");
+ {
+ out.startTag(null, "two");
+ {
+ out.attribute(null, "string", TEST_STRING);
+ out.attribute(null, "stringNumber", "49");
+ out.attributeBytesHex(null, "bytesHex", TEST_BYTES);
+ out.attributeBytesBase64(null, "bytesBase64", TEST_BYTES);
+ out.attributeInt(null, "int", 43);
+ out.attributeIntHex(null, "intHex", 44);
+ out.attributeLong(null, "long", 45L);
+ out.attributeLongHex(null, "longHex", 46L);
+ out.attributeFloat(null, "float", 47f);
+ out.attributeDouble(null, "double", 48d);
+ out.attributeBoolean(null, "boolean", true);
+ }
+ out.endTag(null, "two");
+
+ out.startTag(null, "three");
+ {
+ out.text("foo");
+ out.startTag(null, "four");
+ {
+ }
+ out.endTag(null, "four");
+ out.text("bar");
+ out.text("baz");
+ }
+ out.endTag(null, "three");
+ }
+ out.endTag(null, "one");
+ out.endDocument();
+ }
+
+ private static void doVerifyRead(TypedXmlPullParser in) throws Exception {
+ assertEquals(START_DOCUMENT, in.getEventType());
+ assertNext(in, START_TAG, "one", 1);
+ {
+ assertNext(in, START_TAG, "two", 2);
+ {
+ assertEquals(11, in.getAttributeCount());
+ assertEquals(TEST_STRING, in.getAttributeValue(null, "string"));
+ assertArrayEquals(TEST_BYTES, in.getAttributeBytesHex(null, "bytesHex"));
+ assertArrayEquals(TEST_BYTES, in.getAttributeBytesBase64(null, "bytesBase64"));
+ assertEquals(43, in.getAttributeInt(null, "int"));
+ assertEquals(44, in.getAttributeIntHex(null, "intHex"));
+ assertEquals(45L, in.getAttributeLong(null, "long"));
+ assertEquals(46L, in.getAttributeLongHex(null, "longHex"));
+ assertEquals(47f, in.getAttributeFloat(null, "float"), 0.01);
+ assertEquals(48d, in.getAttributeDouble(null, "double"), 0.01);
+ assertEquals(true, in.getAttributeBoolean(null, "boolean"));
+
+ // Also verify that typed values are available as strings
+ assertEquals("000102030403020100", in.getAttributeValue(null, "bytesHex"));
+ assertEquals("AAECAwQDAgEA", in.getAttributeValue(null, "bytesBase64"));
+ assertEquals("43", in.getAttributeValue(null, "int"));
+ assertEquals("2c", in.getAttributeValue(null, "intHex"));
+ assertEquals("45", in.getAttributeValue(null, "long"));
+ assertEquals("2e", in.getAttributeValue(null, "longHex"));
+ assertEquals("true", in.getAttributeValue(null, "boolean"));
+
+ // And that raw strings can be parsed too
+ assertEquals("49", in.getAttributeValue(null, "stringNumber"));
+ assertEquals(49, in.getAttributeInt(null, "stringNumber"));
+ }
+ assertNext(in, END_TAG, "two", 2);
+
+ assertNext(in, START_TAG, "three", 2);
+ {
+ assertNext(in, TEXT);
+ assertEquals("foo", in.getText().trim());
+ assertNext(in, START_TAG, "four", 3);
+ {
+ assertEquals(0, in.getAttributeCount());
+ }
+ assertNext(in, END_TAG, "four", 3);
+ assertNext(in, TEXT);
+ assertEquals("barbaz", in.getText().trim());
+ }
+ assertNext(in, END_TAG, "three", 2);
+ }
+ assertNext(in, END_TAG, "one", 1);
+ assertNext(in, END_DOCUMENT);
+ }
+
+ static void assertNext(TypedXmlPullParser in, int token) throws Exception {
+ // We're willing to skip over empty text regions, which some
+ // serializers emit transparently
+ int event;
+ while ((event = in.next()) == TEXT && in.getText().trim().length() == 0) {
+ }
+ assertEquals("next", token, event);
+ assertEquals("getEventType", token, in.getEventType());
+ }
+
+ static void assertNext(TypedXmlPullParser in, int token, String name, int depth)
+ throws Exception {
+ assertNext(in, token);
+ assertEquals("getName", name, in.getName());
+ assertEquals("getDepth", depth, in.getDepth());
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
index 8efd3b4f0135..7b9283b41ff0 100644
--- a/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewOnReceiveContentTest.java
@@ -16,12 +16,11 @@
package android.widget;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_AUTOFILL;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_CLIPBOARD;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_DRAG_AND_DROP;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_INPUT_METHOD;
-import static android.view.OnReceiveContentCallback.Payload.SOURCE_PROCESS_TEXT;
-import static android.widget.TextViewOnReceiveContentCallback.canReuse;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_AUTOFILL;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_CLIPBOARD;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_DRAG_AND_DROP;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_INPUT_METHOD;
+import static android.view.OnReceiveContentListener.Payload.SOURCE_PROCESS_TEXT;
import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
import static androidx.test.espresso.Espresso.onView;
@@ -42,8 +41,7 @@ import android.content.ClipData;
import android.content.ClipDescription;
import android.net.Uri;
import android.os.Bundle;
-import android.util.ArraySet;
-import android.view.OnReceiveContentCallback;
+import android.view.OnReceiveContentListener;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;
import android.view.inputmethod.InputContentInfo;
@@ -62,7 +60,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mockito;
/**
- * Tests for {@link TextViewOnReceiveContentCallback}. Most of the test cases are in the CTS test
+ * Tests for {@link TextViewOnReceiveContentListener}. Most of the test cases are in the CTS test
* {@link android.widget.cts.TextViewOnReceiveContentTest}. This class tests some internal
* implementation details, e.g. fallback to the keyboard image API.
*/
@@ -78,35 +76,34 @@ public class TextViewOnReceiveContentTest {
private Instrumentation mInstrumentation;
private Activity mActivity;
private CustomInputConnectionEditText mEditText;
- private TextViewOnReceiveContentCallback mDefaultCallback;
+ private TextViewOnReceiveContentListener mDefaultReceiver;
@Before
public void before() {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
mActivity = mActivityRule.getActivity();
mEditText = mActivity.findViewById(R.id.edittext2);
- mDefaultCallback = mEditText.getEditorForTesting().getDefaultOnReceiveContentCallback();
+ mDefaultReceiver = mEditText.getEditorForTesting().getDefaultOnReceiveContentListener();
}
@Test
- public void testGetSupportedMimeTypes_fallbackToCommitContent() throws Throwable {
+ public void testGetEditorInfoMimeTypes_fallbackToCommitContent() throws Throwable {
// Configure the EditText with an EditorInfo/InputConnection that supports some image MIME
// types.
- mEditText.setContentMimeTypes(new String[] {"image/gif", "image/png"});
+ String[] mimeTypes = {"image/gif", "image/png"};
+ mEditText.setContentMimeTypes(mimeTypes);
MyInputConnection ic = new MyInputConnection();
mEditText.setInputConnectionWrapper(ic);
// Focus into the EditText.
onView(withId(mEditText.getId())).perform(clickOnTextAtIndex(0));
- // Assert that the callback returns the MIME types declared in the EditorInfo in addition to
- // the default.
- assertThat(mDefaultCallback.getMimeTypes(mEditText)).containsExactly(
- "text/*", "image/gif", "image/png");
+ // Assert that the default listener returns the MIME types declared in the EditorInfo.
+ assertThat(mDefaultReceiver.getEditorInfoMimeTypes(mEditText)).isEqualTo(mimeTypes);
}
@Test
- public void testGetSupportedMimeTypes_fallbackToCommitContent_noMimeTypesInEditorInfo()
+ public void testGetEditorInfoMimeTypes_fallbackToCommitContent_noMimeTypesInEditorInfo()
throws Throwable {
// Configure the EditText with an EditorInfo/InputConnection that doesn't declare any MIME
// types.
@@ -117,8 +114,8 @@ public class TextViewOnReceiveContentTest {
// Focus into the EditText.
onView(withId(mEditText.getId())).perform(clickOnTextAtIndex(0));
- // Assert that the callback returns the default MIME types.
- assertThat(mDefaultCallback.getMimeTypes(mEditText)).containsExactly("text/*");
+ // Assert that the default listener returns null as the MIME types.
+ assertThat(mDefaultReceiver.getEditorInfoMimeTypes(mEditText)).isNull();
}
@Test
@@ -132,13 +129,13 @@ public class TextViewOnReceiveContentTest {
// Focus into the EditText.
onView(withId(mEditText.getId())).perform(clickOnTextAtIndex(0));
- // Invoke the callback with SOURCE_AUTOFILL and assert that it triggers a call to
+ // Invoke the listener with SOURCE_AUTOFILL and assert that it triggers a call to
// InputConnection.commitContent.
ClipDescription description = new ClipDescription("", new String[] {"image/gif"});
ClipData clip = new ClipData(description, new ClipData.Item(SAMPLE_CONTENT_URI));
- OnReceiveContentCallback.Payload payload =
- new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_AUTOFILL).build();
- mDefaultCallback.onReceiveContent(mEditText, payload);
+ OnReceiveContentListener.Payload payload =
+ new OnReceiveContentListener.Payload.Builder(clip, SOURCE_AUTOFILL).build();
+ mDefaultReceiver.onReceiveContent(mEditText, payload);
verify(ic.mMock, times(1))
.commitContent(any(InputContentInfo.class), eq(0), eq(null));
verifyNoMoreInteractions(ic.mMock);
@@ -155,12 +152,12 @@ public class TextViewOnReceiveContentTest {
// Focus into the EditText.
onView(withId(mEditText.getId())).perform(clickOnTextAtIndex(0));
- // Invoke the callback and assert that the InputConnection is not invoked.
+ // Invoke the listener and assert that the InputConnection is not invoked.
ClipDescription description = new ClipDescription("", new String[] {"image/gif"});
ClipData clip = new ClipData(description, new ClipData.Item(SAMPLE_CONTENT_URI));
- OnReceiveContentCallback.Payload payload =
- new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_AUTOFILL).build();
- mDefaultCallback.onReceiveContent(mEditText, payload);
+ OnReceiveContentListener.Payload payload =
+ new OnReceiveContentListener.Payload.Builder(clip, SOURCE_AUTOFILL).build();
+ mDefaultReceiver.onReceiveContent(mEditText, payload);
verifyZeroInteractions(ic.mMock);
}
@@ -175,71 +172,28 @@ public class TextViewOnReceiveContentTest {
// Focus into the EditText.
onView(withId(mEditText.getId())).perform(clickOnTextAtIndex(0));
- // Invoke the callback with sources other than SOURCE_AUTOFILL and assert that it does NOT
+ // Invoke the listener with sources other than SOURCE_AUTOFILL and assert that it does NOT
// trigger calls to InputConnection.commitContent.
ClipDescription description = new ClipDescription("", new String[] {"image/gif"});
ClipData clip = new ClipData(description, new ClipData.Item(SAMPLE_CONTENT_URI));
- OnReceiveContentCallback.Payload payload =
- new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_CLIPBOARD).build();
- mDefaultCallback.onReceiveContent(mEditText, payload);
+ OnReceiveContentListener.Payload payload =
+ new OnReceiveContentListener.Payload.Builder(clip, SOURCE_CLIPBOARD).build();
+ mDefaultReceiver.onReceiveContent(mEditText, payload);
verifyZeroInteractions(ic.mMock);
- payload = new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_INPUT_METHOD).build();
- mDefaultCallback.onReceiveContent(mEditText, payload);
+ payload = new OnReceiveContentListener.Payload.Builder(clip, SOURCE_INPUT_METHOD).build();
+ mDefaultReceiver.onReceiveContent(mEditText, payload);
verifyZeroInteractions(ic.mMock);
- payload = new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_DRAG_AND_DROP).build();
- mDefaultCallback.onReceiveContent(mEditText, payload);
+ payload = new OnReceiveContentListener.Payload.Builder(clip, SOURCE_DRAG_AND_DROP).build();
+ mDefaultReceiver.onReceiveContent(mEditText, payload);
verifyZeroInteractions(ic.mMock);
- payload = new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_PROCESS_TEXT).build();
- mDefaultCallback.onReceiveContent(mEditText, payload);
+ payload = new OnReceiveContentListener.Payload.Builder(clip, SOURCE_PROCESS_TEXT).build();
+ mDefaultReceiver.onReceiveContent(mEditText, payload);
verifyZeroInteractions(ic.mMock);
}
- @Test
- public void testCanReuse() throws Throwable {
- ArraySet<String> mimeTypes = null;
- String[] editorContentMimeTypes = new String[0];
- assertThat(canReuse(mimeTypes, editorContentMimeTypes)).isFalse();
-
- mimeTypes = new ArraySet<>();
- editorContentMimeTypes = new String[0];
- assertThat(canReuse(mimeTypes, editorContentMimeTypes)).isTrue();
-
- mimeTypes = newArraySet("text/*");
- editorContentMimeTypes = new String[0];
- assertThat(canReuse(mimeTypes, editorContentMimeTypes)).isTrue();
-
- mimeTypes = newArraySet("text/*");
- editorContentMimeTypes = new String[] {"text/*"};
- assertThat(canReuse(mimeTypes, editorContentMimeTypes)).isTrue();
-
- mimeTypes = newArraySet("image/gif", "image/png", "text/*");
- editorContentMimeTypes = new String[] {"image/gif", "image/png"};
- assertThat(canReuse(mimeTypes, editorContentMimeTypes)).isTrue();
-
- mimeTypes = newArraySet("image/gif", "image/png", "text/*");
- editorContentMimeTypes = new String[] {"image/gif", "image/png", "text/*"};
- assertThat(canReuse(mimeTypes, editorContentMimeTypes)).isTrue();
-
- mimeTypes = newArraySet("image/gif", "image/png", "text/*");
- editorContentMimeTypes = new String[] {"image/gif"};
- assertThat(canReuse(mimeTypes, editorContentMimeTypes)).isFalse();
-
- mimeTypes = newArraySet("image/gif", "image/png", "text/*");
- editorContentMimeTypes = new String[] {"image/gif", "image/png", "image/jpg"};
- assertThat(canReuse(mimeTypes, editorContentMimeTypes)).isFalse();
-
- mimeTypes = newArraySet("image/gif", "image/png", "text/*");
- editorContentMimeTypes = new String[] {"image/gif", "image/jpg"};
- assertThat(canReuse(mimeTypes, editorContentMimeTypes)).isFalse();
-
- mimeTypes = newArraySet("image/gif", "image/png", "text/*");
- editorContentMimeTypes = new String[] {"image/gif", "image/jpg", "text/*"};
- assertThat(canReuse(mimeTypes, editorContentMimeTypes)).isFalse();
- }
-
private static class MyInputConnection extends InputConnectionWrapper {
public final InputConnection mMock;
@@ -254,9 +208,4 @@ public class TextViewOnReceiveContentTest {
return true;
}
}
-
- @SafeVarargs
- private static <T> ArraySet<T> newArraySet(T ... elements) {
- return new ArraySet<>(elements);
- }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
index dc9208de7198..7306b45aaa98 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelWakelockReaderTest.java
@@ -16,14 +16,14 @@
package com.android.internal.os;
+import android.system.suspend.internal.WakeLockInfo;
+
import androidx.test.filters.SmallTest;
import junit.framework.TestCase;
import java.nio.charset.Charset;
-import android.system.suspend.WakeLockInfo;
-
public class KernelWakelockReaderTest extends TestCase {
/**
* Helper class that builds the mock Kernel module file /d/wakeup_sources.
diff --git a/core/tests/coretests/src/com/android/internal/util/FastDataTest.java b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java
new file mode 100644
index 000000000000..81fb39fed026
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java
@@ -0,0 +1,407 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.annotation.NonNull;
+import android.util.ExceptionUtils;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+@RunWith(AndroidJUnit4.class)
+public class FastDataTest {
+ private static final String TEST_SHORT_STRING = "a";
+ private static final String TEST_LONG_STRING = "com☃example☃typical☃package☃name";
+ private static final byte[] TEST_BYTES = TEST_LONG_STRING.getBytes(StandardCharsets.UTF_16LE);
+
+ @Test
+ public void testEndOfFile_Int() throws Exception {
+ try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+ new byte[] { 1 }), 1000)) {
+ assertThrows(EOFException.class, () -> in.readInt());
+ }
+ try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+ new byte[] { 1, 1, 1, 1 }), 1000)) {
+ assertEquals(1, in.readByte());
+ assertThrows(EOFException.class, () -> in.readInt());
+ }
+ }
+
+ @Test
+ public void testEndOfFile_String() throws Exception {
+ try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+ new byte[] { 1 }), 1000)) {
+ assertThrows(EOFException.class, () -> in.readUTF());
+ }
+ try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+ new byte[] { 1, 1, 1, 1 }), 1000)) {
+ assertThrows(EOFException.class, () -> in.readUTF());
+ }
+ }
+
+ @Test
+ public void testEndOfFile_Bytes_Small() throws Exception {
+ try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+ new byte[] { 1, 1, 1, 1 }), 1000)) {
+ final byte[] tmp = new byte[10];
+ assertThrows(EOFException.class, () -> in.readFully(tmp));
+ }
+ try (FastDataInput in = new FastDataInput(new ByteArrayInputStream(
+ new byte[] { 1, 1, 1, 1 }), 1000)) {
+ final byte[] tmp = new byte[10_000];
+ assertThrows(EOFException.class, () -> in.readFully(tmp));
+ }
+ }
+
+ @Test
+ public void testUTF_Bounds() throws Exception {
+ final char[] buf = new char[65_534];
+ try (FastDataOutput out = new FastDataOutput(new ByteArrayOutputStream(), BOUNCE_SIZE)) {
+ // Writing simple string will fit fine
+ Arrays.fill(buf, '!');
+ final String simple = new String(buf);
+ out.writeUTF(simple);
+ out.writeInternedUTF(simple);
+
+ // Just one complex char will cause it to overflow
+ buf[0] = '☃';
+ final String complex = new String(buf);
+ assertThrows(IOException.class, () -> out.writeUTF(complex));
+ assertThrows(IOException.class, () -> out.writeInternedUTF(complex));
+ }
+ }
+
+ @Test
+ public void testTranscode() throws Exception {
+ // Verify that upstream data can be read by fast
+ {
+ final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ final DataOutputStream out = new DataOutputStream(outStream);
+ doTranscodeWrite(out);
+ out.flush();
+
+ final FastDataInput in = new FastDataInput(
+ new ByteArrayInputStream(outStream.toByteArray()), BOUNCE_SIZE);
+ doTransodeRead(in);
+ }
+
+ // Verify that fast data can be read by upstream
+ {
+ final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ final FastDataOutput out = new FastDataOutput(outStream, BOUNCE_SIZE);
+ doTranscodeWrite(out);
+ out.flush();
+
+ final DataInputStream in = new DataInputStream(
+ new ByteArrayInputStream(outStream.toByteArray()));
+ doTransodeRead(in);
+ }
+ }
+
+ private static void doTranscodeWrite(DataOutput out) throws IOException {
+ out.writeBoolean(true);
+ out.writeBoolean(false);
+ out.writeByte(1);
+ out.writeShort(2);
+ out.writeInt(4);
+ out.writeUTF("foo\0bar");
+ out.writeUTF(TEST_SHORT_STRING);
+ out.writeUTF(TEST_LONG_STRING);
+ out.writeLong(8L);
+ out.writeFloat(16f);
+ out.writeDouble(32d);
+ }
+
+ private static void doTransodeRead(DataInput in) throws IOException {
+ assertEquals(true, in.readBoolean());
+ assertEquals(false, in.readBoolean());
+ assertEquals(1, in.readByte());
+ assertEquals(2, in.readShort());
+ assertEquals(4, in.readInt());
+ assertEquals("foo\0bar", in.readUTF());
+ assertEquals(TEST_SHORT_STRING, in.readUTF());
+ assertEquals(TEST_LONG_STRING, in.readUTF());
+ assertEquals(8L, in.readLong());
+ assertEquals(16f, in.readFloat(), 0.01);
+ assertEquals(32d, in.readDouble(), 0.01);
+ }
+
+ @Test
+ public void testBounce_Char() throws Exception {
+ doBounce((out) -> {
+ out.writeChar('\0');
+ out.writeChar('☃');
+ }, (in) -> {
+ assertEquals('\0', in.readChar());
+ assertEquals('☃', in.readChar());
+ });
+ }
+
+ @Test
+ public void testBounce_Short() throws Exception {
+ doBounce((out) -> {
+ out.writeShort(0);
+ out.writeShort((short) 0x0f0f);
+ out.writeShort((short) 0xf0f0);
+ out.writeShort(Short.MIN_VALUE);
+ out.writeShort(Short.MAX_VALUE);
+ }, (in) -> {
+ assertEquals(0, in.readShort());
+ assertEquals((short) 0x0f0f, in.readShort());
+ assertEquals((short) 0xf0f0, in.readShort());
+ assertEquals(Short.MIN_VALUE, in.readShort());
+ assertEquals(Short.MAX_VALUE, in.readShort());
+ });
+ }
+
+ @Test
+ public void testBounce_Int() throws Exception {
+ doBounce((out) -> {
+ out.writeInt(0);
+ out.writeInt(0x0f0f0f0f);
+ out.writeInt(0xf0f0f0f0);
+ out.writeInt(Integer.MIN_VALUE);
+ out.writeInt(Integer.MAX_VALUE);
+ }, (in) -> {
+ assertEquals(0, in.readInt());
+ assertEquals(0x0f0f0f0f, in.readInt());
+ assertEquals(0xf0f0f0f0, in.readInt());
+ assertEquals(Integer.MIN_VALUE, in.readInt());
+ assertEquals(Integer.MAX_VALUE, in.readInt());
+ });
+ }
+
+ @Test
+ public void testBounce_Long() throws Exception {
+ doBounce((out) -> {
+ out.writeLong(0);
+ out.writeLong(0x0f0f0f0f0f0f0f0fL);
+ out.writeLong(0xf0f0f0f0f0f0f0f0L);
+ out.writeLong(Long.MIN_VALUE);
+ out.writeLong(Long.MAX_VALUE);
+ }, (in) -> {
+ assertEquals(0, in.readLong());
+ assertEquals(0x0f0f0f0f0f0f0f0fL, in.readLong());
+ assertEquals(0xf0f0f0f0f0f0f0f0L, in.readLong());
+ assertEquals(Long.MIN_VALUE, in.readLong());
+ assertEquals(Long.MAX_VALUE, in.readLong());
+ });
+ }
+
+ @Test
+ public void testBounce_UTF() throws Exception {
+ doBounce((out) -> {
+ out.writeUTF("");
+ out.writeUTF("☃");
+ out.writeUTF("example");
+ }, (in) -> {
+ assertEquals("", in.readUTF());
+ assertEquals("☃", in.readUTF());
+ assertEquals("example", in.readUTF());
+ });
+ }
+
+ @Test
+ public void testBounce_UTF_Exact() throws Exception {
+ final char[] expectedBuf = new char[BOUNCE_SIZE];
+ Arrays.fill(expectedBuf, '!');
+ final String expected = new String(expectedBuf);
+
+ doBounce((out) -> {
+ out.writeUTF(expected);
+ }, (in) -> {
+ final String actual = in.readUTF();
+ assertEquals(expected.length(), actual.length());
+ assertEquals(expected, actual);
+ });
+ }
+
+ @Test
+ public void testBounce_UTF_Maximum() throws Exception {
+ final char[] expectedBuf = new char[65_534];
+ Arrays.fill(expectedBuf, '!');
+ final String expected = new String(expectedBuf);
+
+ doBounce((out) -> {
+ out.writeUTF(expected);
+ }, (in) -> {
+ final String actual = in.readUTF();
+ assertEquals(expected.length(), actual.length());
+ assertEquals(expected, actual);
+ }, 1);
+ }
+
+ @Test
+ public void testBounce_InternedUTF() throws Exception {
+ doBounce((out) -> {
+ out.writeInternedUTF("foo");
+ out.writeInternedUTF("bar");
+ out.writeInternedUTF("baz");
+ out.writeInternedUTF("bar");
+ out.writeInternedUTF("foo");
+ }, (in) -> {
+ assertEquals("foo", in.readInternedUTF());
+ assertEquals("bar", in.readInternedUTF());
+ assertEquals("baz", in.readInternedUTF());
+ assertEquals("bar", in.readInternedUTF());
+ assertEquals("foo", in.readInternedUTF());
+ });
+ }
+
+ /**
+ * Verify that when we overflow the maximum number of interned string
+ * references, we still transport the raw string values successfully.
+ */
+ @Test
+ public void testBounce_InternedUTF_Maximum() throws Exception {
+ final int num = 70_000;
+ doBounce((out) -> {
+ for (int i = 0; i < num; i++) {
+ out.writeInternedUTF("foo" + i);
+ }
+ }, (in) -> {
+ for (int i = 0; i < num; i++) {
+ assertEquals("foo" + i, in.readInternedUTF());
+ }
+ }, 1);
+ }
+
+ @Test
+ public void testBounce_Bytes() throws Exception {
+ doBounce((out) -> {
+ out.write(TEST_BYTES, 8, 32);
+ out.writeInt(64);
+ }, (in) -> {
+ final byte[] tmp = new byte[128];
+ in.readFully(tmp, 8, 32);
+ assertArrayEquals(Arrays.copyOfRange(TEST_BYTES, 8, 8 + 32),
+ Arrays.copyOfRange(tmp, 8, 8 + 32));
+ assertEquals(64, in.readInt());
+ });
+ }
+
+ @Test
+ public void testBounce_Mixed() throws Exception {
+ doBounce((out) -> {
+ out.writeBoolean(true);
+ out.writeBoolean(false);
+ out.writeByte(1);
+ out.writeShort(2);
+ out.writeInt(4);
+ out.writeUTF(TEST_SHORT_STRING);
+ out.writeUTF(TEST_LONG_STRING);
+ out.writeLong(8L);
+ out.writeFloat(16f);
+ out.writeDouble(32d);
+ }, (in) -> {
+ assertEquals(true, in.readBoolean());
+ assertEquals(false, in.readBoolean());
+ assertEquals(1, in.readByte());
+ assertEquals(2, in.readShort());
+ assertEquals(4, in.readInt());
+ assertEquals(TEST_SHORT_STRING, in.readUTF());
+ assertEquals(TEST_LONG_STRING, in.readUTF());
+ assertEquals(8L, in.readLong());
+ assertEquals(16f, in.readFloat(), 0.01);
+ assertEquals(32d, in.readDouble(), 0.01);
+ });
+ }
+
+ /**
+ * Buffer size to use for {@link #doBounce}; purposefully chosen to be a
+ * small prime number to help uncover edge cases.
+ */
+ private static final int BOUNCE_SIZE = 11;
+
+ /**
+ * Number of times to repeat message when bouncing; repeating is used to
+ * help uncover edge cases.
+ */
+ private static final int BOUNCE_REPEAT = 1_000;
+
+ /**
+ * Verify that some common data can be written and read back, effectively
+ * "bouncing" it through a serialized representation.
+ */
+ private static void doBounce(@NonNull ThrowingConsumer<FastDataOutput> out,
+ @NonNull ThrowingConsumer<FastDataInput> in) throws Exception {
+ doBounce(out, in, BOUNCE_REPEAT);
+ }
+
+ private static void doBounce(@NonNull ThrowingConsumer<FastDataOutput> out,
+ @NonNull ThrowingConsumer<FastDataInput> in, int count) throws Exception {
+ final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ final FastDataOutput outData = new FastDataOutput(outStream, BOUNCE_SIZE);
+ for (int i = 0; i < count; i++) {
+ out.accept(outData);
+ }
+ outData.flush();
+
+ final ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
+ final FastDataInput inData = new FastDataInput(inStream, BOUNCE_SIZE);
+ for (int i = 0; i < count; i++) {
+ in.accept(inData);
+ }
+ }
+
+ private static <T extends Exception> void assertThrows(Class<T> clazz, ThrowingRunnable r)
+ throws Exception {
+ try {
+ r.run();
+ fail("Expected " + clazz + " to be thrown");
+ } catch (Exception e) {
+ if (!clazz.isAssignableFrom(e.getClass())) {
+ throw e;
+ }
+ }
+ }
+
+ public interface ThrowingRunnable {
+ void run() throws Exception;
+ }
+
+ public interface ThrowingConsumer<T> extends Consumer<T> {
+ void acceptOrThrow(T t) throws Exception;
+
+ @Override
+ default void accept(T t) {
+ try {
+ acceptOrThrow(t);
+ } catch (Exception ex) {
+ throw ExceptionUtils.propagate(ex);
+ }
+ }
+ }
+}
diff --git a/packages/CarSystemUI/samples/sample2/rro/Android.bp b/core/tests/devicestatetests/Android.bp
index bf68e414ca1c..409b77bc399e 100644
--- a/packages/CarSystemUI/samples/sample2/rro/Android.bp
+++ b/core/tests/devicestatetests/Android.bp
@@ -1,4 +1,3 @@
-//
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,16 +11,16 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
-android_app {
- name: "CarSystemUISampleTwoRRO",
- resource_dirs: ["res"],
- certificate: "platform",
+android_test {
+ name: "FrameworksCoreDeviceStateManagerTests",
+ // Include all test java files
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "frameworks-base-testutils",
+ ],
+ libs: ["android.test.runner"],
platform_apis: true,
- manifest: "AndroidManifest.xml",
- aaptflags: [
- "--no-resource-deduping",
- "--no-resource-removal",
- ]
-} \ No newline at end of file
+ certificate: "platform",
+}
diff --git a/packages/CarSystemUI/res/drawable/car_add_circle_round.xml b/core/tests/devicestatetests/AndroidManifest.xml
index 13c7dd12f940..acd6e7b2759a 100644
--- a/packages/CarSystemUI/res/drawable/car_add_circle_round.xml
+++ b/core/tests/devicestatetests/AndroidManifest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,17 +13,17 @@
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">
- <item>
- <shape android:shape="oval">
- <solid
- android:color="@color/car_user_switcher_add_user_background_color"/>
- <size
- android:width="@dimen/car_user_switcher_image_avatar_size"
- android:height="@dimen/car_user_switcher_image_avatar_size"/>
- </shape>
- </item>
- <item
- android:drawable="@drawable/car_ic_add_white"
- android:gravity="center"/>
-</layer-list> \ No newline at end of file
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.devicestate"
+ android:sharedUserId="android.uid.system" >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.coretests.devicestate"
+ android:label="Device State Manager Tests"/>
+
+</manifest>
diff --git a/core/tests/devicestatetests/AndroidTest.xml b/core/tests/devicestatetests/AndroidTest.xml
new file mode 100644
index 000000000000..9e38afddbd96
--- /dev/null
+++ b/core/tests/devicestatetests/AndroidTest.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.
+-->
+
+<configuration description="Runs Device State Manager Tests.">
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-suite-tag" value="apct-instrumentation"/>
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="FrameworksCoreDeviceStateManagerTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.frameworks.coretests.devicestate" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+</configuration>
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
new file mode 100644
index 000000000000..36f01f9a951d
--- /dev/null
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.devicestate;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.annotation.Nullable;
+import android.os.RemoteException;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.ConcurrentUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Unit tests for {@link DeviceStateManagerGlobal}.
+ * <p/>
+ * Run with <code>atest DeviceStateManagerGlobalTest</code>.
+ */
+@RunWith(JUnit4.class)
+@SmallTest
+public final class DeviceStateManagerGlobalTest {
+ private TestDeviceStateManagerService mService;
+ private DeviceStateManagerGlobal mDeviceStateManagerGlobal;
+
+ @Before
+ public void setUp() {
+ mService = new TestDeviceStateManagerService();
+ mDeviceStateManagerGlobal = new DeviceStateManagerGlobal(mService);
+ }
+
+ @Test
+ public void registerListener() {
+ mService.setDeviceState(0);
+
+ TestDeviceStateListener listener1 = new TestDeviceStateListener();
+ TestDeviceStateListener listener2 = new TestDeviceStateListener();
+
+ mDeviceStateManagerGlobal.registerDeviceStateListener(listener1,
+ ConcurrentUtils.DIRECT_EXECUTOR);
+ mDeviceStateManagerGlobal.registerDeviceStateListener(listener2,
+ ConcurrentUtils.DIRECT_EXECUTOR);
+ assertEquals(0, listener1.getLastReportedState().intValue());
+ assertEquals(0, listener2.getLastReportedState().intValue());
+
+ mService.setDeviceState(1);
+ assertEquals(1, listener1.getLastReportedState().intValue());
+ assertEquals(1, listener2.getLastReportedState().intValue());
+ }
+
+ @Test
+ public void unregisterListener() {
+ mService.setDeviceState(0);
+
+ TestDeviceStateListener listener = new TestDeviceStateListener();
+
+ mDeviceStateManagerGlobal.registerDeviceStateListener(listener,
+ ConcurrentUtils.DIRECT_EXECUTOR);
+ assertEquals(0, listener.getLastReportedState().intValue());
+
+ mDeviceStateManagerGlobal.unregisterDeviceStateListener(listener);
+
+ mService.setDeviceState(1);
+ assertEquals(0, listener.getLastReportedState().intValue());
+ }
+
+ private final class TestDeviceStateListener implements DeviceStateManager.DeviceStateListener {
+ @Nullable
+ private Integer mLastReportedDeviceState;
+
+ @Override
+ public void onDeviceStateChanged(int deviceState) {
+ mLastReportedDeviceState = deviceState;
+ }
+
+ @Nullable
+ public Integer getLastReportedState() {
+ return mLastReportedDeviceState;
+ }
+ }
+
+ private final class TestDeviceStateManagerService extends IDeviceStateManager.Stub {
+ private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
+ private Set<IDeviceStateManagerCallback> mCallbacks = new HashSet<>();
+
+ @Override
+ public void registerCallback(IDeviceStateManagerCallback callback) {
+ if (mCallbacks.contains(callback)) {
+ throw new SecurityException("Callback is already registered.");
+ }
+
+ mCallbacks.add(callback);
+ try {
+ callback.onDeviceStateChanged(mDeviceState);
+ } catch (RemoteException e) {
+ // Do nothing. Should never happen.
+ }
+ }
+
+ public void setDeviceState(int deviceState) {
+ boolean stateChanged = mDeviceState != deviceState;
+ mDeviceState = deviceState;
+ if (stateChanged) {
+ for (IDeviceStateManagerCallback callback : mCallbacks) {
+ try {
+ callback.onDeviceStateChanged(mDeviceState);
+ } catch (RemoteException e) {
+ // Do nothing. Should never happen.
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index cc68bb6333cb..4094f836ff5a 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -381,17 +381,31 @@ public class HdmiAudioSystemClientTest {
}
@Override
- public List<String> getAllowedCecSettingValues(String name) {
+ public List<String> getAllowedCecSettingStringValues(String name) {
return new ArrayList<>();
}
@Override
- public String getCecSettingValue(String name) {
+ public int[] getAllowedCecSettingIntValues(String name) {
+ return new int[0];
+ }
+
+ @Override
+ public String getCecSettingStringValue(String name) {
return "";
}
@Override
- public void setCecSettingValue(String name, String value) {
+ public void setCecSettingStringValue(String name, String value) {
+ }
+
+ @Override
+ public int getCecSettingIntValue(String name) {
+ return 0;
+ }
+
+ @Override
+ public void setCecSettingIntValue(String name, int value) {
}
}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index d266cdbccf79..46695d2764dd 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -26,15 +26,16 @@ import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.after;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -52,7 +53,7 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
-import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
@@ -200,9 +201,9 @@ public class ActivityThreadClientTest {
private void recreateAndVerifyNoRelaunch(ActivityThread activityThread, TestActivity activity) {
clearInvocations(activityThread);
getInstrumentation().runOnMainSync(() -> activity.recreate());
+ getInstrumentation().waitForIdleSync();
- verify(activityThread, after(WAIT_TIMEOUT_MS).never())
- .handleRelaunchActivity(any(), any());
+ verify(activityThread, never()).handleRelaunchActivity(any(), any());
}
private void recreateAndVerifyRelaunched(ActivityThread activityThread, TestActivity activity,
@@ -292,7 +293,7 @@ public class ActivityThreadClientTest {
spyOn(packageInfo);
doNothing().when(packageInfo).updateApplicationInfo(any(), any());
- return new ActivityClientRecord(new Binder(), Intent.makeMainActivity(component),
+ return new ActivityClientRecord(mock(IBinder.class), Intent.makeMainActivity(component),
0 /* ident */, info, new Configuration(),
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* referrer */,
null /* voiceInteractor */, null /* state */, null /* persistentState */,
diff --git a/packages/CarSystemUI/samples/sample3/rro/Android.bp b/core/tests/uwbtests/Android.bp
index 0eae7c271f66..c41c346b131a 100644
--- a/packages/CarSystemUI/samples/sample3/rro/Android.bp
+++ b/core/tests/uwbtests/Android.bp
@@ -1,5 +1,4 @@
-//
-// Copyright (C) 2020 The Android Open Source Project
+// 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.
@@ -12,16 +11,18 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
-android_app {
- name: "CarSystemUISampleThreeRRO",
- resource_dirs: ["res"],
- certificate: "platform",
+android_test {
+ name: "UwbManagerTests",
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ ],
+ libs: [
+ "android.test.runner",
+ ],
+ srcs: ["src/**/*.java"],
platform_apis: true,
- manifest: "AndroidManifest.xml",
- aaptflags: [
- "--no-resource-deduping",
- "--no-resource-removal",
- ]
-} \ No newline at end of file
+ certificate: "platform",
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/uwbtests/AndroidManifest.xml b/core/tests/uwbtests/AndroidManifest.xml
new file mode 100644
index 000000000000..dc991ff636d2
--- /dev/null
+++ b/core/tests/uwbtests/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.uwb">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!-- This is a self-instrumenting test package. -->
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.uwb"
+ android:label="UWB Manager Tests">
+ </instrumentation>
+
+</manifest>
+
diff --git a/core/tests/uwbtests/AndroidTest.xml b/core/tests/uwbtests/AndroidTest.xml
new file mode 100644
index 000000000000..ff4b668cc625
--- /dev/null
+++ b/core/tests/uwbtests/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+<configuration description="Config for UWB Manager test cases">
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-suite-tag" value="apct-instrumentation"/>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="UwbManagerTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="UwbManagerTests"/>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.uwb" />
+ <option name="hidden-api-checks" value="false"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+ </test>
+</configuration>
diff --git a/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java
new file mode 100644
index 000000000000..7769c28202f2
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/AngleMeasurementTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link AngleMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AngleMeasurementTest {
+ private static final double EPSILON = 0.00000000001;
+
+ @Test
+ public void testBuilder() {
+ double radians = 0.1234;
+ double errorRadians = 0.5678;
+ double confidence = 0.5;
+
+ AngleMeasurement.Builder builder = new AngleMeasurement.Builder();
+ tryBuild(builder, false);
+
+ builder.setRadians(radians);
+ tryBuild(builder, false);
+
+ builder.setErrorRadians(errorRadians);
+ tryBuild(builder, false);
+
+ builder.setConfidenceLevel(confidence);
+ AngleMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(measurement.getRadians(), radians, 0);
+ assertEquals(measurement.getErrorRadians(), errorRadians, 0);
+ assertEquals(measurement.getConfidenceLevel(), confidence, 0);
+ }
+
+ private AngleMeasurement tryBuild(AngleMeasurement.Builder builder, boolean expectSuccess) {
+ AngleMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected AngleMeasurement.Builder.build() to fail, but it succeeded");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected AngleMeasurement.Builder.build() to succeed, but it failed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ AngleMeasurement measurement = UwbTestUtils.getAngleMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ AngleMeasurement fromParcel = AngleMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
new file mode 100644
index 000000000000..077b08f41b59
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link AngleOfArrivalMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AngleOfArrivalMeasurementTest {
+
+ @Test
+ public void testBuilder() {
+ AngleMeasurement azimuth = UwbTestUtils.getAngleMeasurement();
+ AngleMeasurement altitude = UwbTestUtils.getAngleMeasurement();
+
+ AngleOfArrivalMeasurement.Builder builder = new AngleOfArrivalMeasurement.Builder();
+ tryBuild(builder, false);
+
+ builder.setAltitudeAngleMeasurement(altitude);
+ tryBuild(builder, false);
+
+ builder.setAzimuthAngleMeasurement(azimuth);
+ AngleOfArrivalMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(azimuth, measurement.getAzimuth());
+ assertEquals(altitude, measurement.getAltitude());
+ }
+
+ private AngleMeasurement getAngleMeasurement(double radian, double error, double confidence) {
+ return new AngleMeasurement.Builder()
+ .setRadians(radian)
+ .setErrorRadians(error)
+ .setConfidenceLevel(confidence)
+ .build();
+ }
+
+ private AngleOfArrivalMeasurement tryBuild(AngleOfArrivalMeasurement.Builder builder,
+ boolean expectSuccess) {
+ AngleOfArrivalMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected AngleOfArrivalMeasurement.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected AngleOfArrivalMeasurement.Builder.build() to succeed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ AngleOfArrivalMeasurement measurement = UwbTestUtils.getAngleOfArrivalMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ AngleOfArrivalMeasurement fromParcel =
+ AngleOfArrivalMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java
new file mode 100644
index 000000000000..439c884723be
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/DistanceMeasurementTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link DistanceMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DistanceMeasurementTest {
+ private static final double EPSILON = 0.00000000001;
+
+ @Test
+ public void testBuilder() {
+ double meters = 0.12;
+ double error = 0.54;
+ double confidence = 0.99;
+
+ DistanceMeasurement.Builder builder = new DistanceMeasurement.Builder();
+ tryBuild(builder, false);
+
+ builder.setMeters(meters);
+ tryBuild(builder, false);
+
+ builder.setErrorMeters(error);
+ tryBuild(builder, false);
+
+ builder.setConfidenceLevel(confidence);
+ DistanceMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(meters, measurement.getMeters(), 0);
+ assertEquals(error, measurement.getErrorMeters(), 0);
+ assertEquals(confidence, measurement.getConfidenceLevel(), 0);
+ }
+
+ private DistanceMeasurement tryBuild(DistanceMeasurement.Builder builder,
+ boolean expectSuccess) {
+ DistanceMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected DistanceMeasurement.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected DistanceMeasurement.Builder.build() to succeed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ DistanceMeasurement measurement = UwbTestUtils.getDistanceMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ DistanceMeasurement fromParcel =
+ DistanceMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java
new file mode 100644
index 000000000000..a7559d86221e
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/RangingMeasurementTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+import android.os.SystemClock;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link RangingMeasurement}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RangingMeasurementTest {
+
+ @Test
+ public void testBuilder() {
+ int status = RangingMeasurement.RANGING_STATUS_SUCCESS;
+ UwbAddress address = UwbTestUtils.getUwbAddress(false);
+ long time = SystemClock.elapsedRealtimeNanos();
+ AngleOfArrivalMeasurement angleMeasurement = UwbTestUtils.getAngleOfArrivalMeasurement();
+ DistanceMeasurement distanceMeasurement = UwbTestUtils.getDistanceMeasurement();
+
+ RangingMeasurement.Builder builder = new RangingMeasurement.Builder();
+
+ builder.setStatus(status);
+ tryBuild(builder, false);
+
+ builder.setElapsedRealtimeNanos(time);
+ tryBuild(builder, false);
+
+ builder.setAngleOfArrivalMeasurement(angleMeasurement);
+ tryBuild(builder, false);
+
+ builder.setDistanceMeasurement(distanceMeasurement);
+ tryBuild(builder, false);
+
+ builder.setRemoteDeviceAddress(address);
+ RangingMeasurement measurement = tryBuild(builder, true);
+
+ assertEquals(status, measurement.getStatus());
+ assertEquals(address, measurement.getRemoteDeviceAddress());
+ assertEquals(time, measurement.getElapsedRealtimeNanos());
+ assertEquals(angleMeasurement, measurement.getAngleOfArrival());
+ assertEquals(distanceMeasurement, measurement.getDistance());
+ }
+
+ private RangingMeasurement tryBuild(RangingMeasurement.Builder builder,
+ boolean expectSuccess) {
+ RangingMeasurement measurement = null;
+ try {
+ measurement = builder.build();
+ if (!expectSuccess) {
+ fail("Expected RangingMeasurement.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected DistanceMeasurement.Builder.build() to succeed");
+ }
+ }
+ return measurement;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ RangingMeasurement measurement = UwbTestUtils.getRangingMeasurement();
+ measurement.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ RangingMeasurement fromParcel = RangingMeasurement.CREATOR.createFromParcel(parcel);
+ assertEquals(measurement, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/RangingReportTest.java b/core/tests/uwbtests/src/android/uwb/RangingReportTest.java
new file mode 100644
index 000000000000..64c48ba4b6f4
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/RangingReportTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+/**
+ * Test of {@link RangingReport}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RangingReportTest {
+
+ @Test
+ public void testBuilder() {
+ List<RangingMeasurement> measurements = UwbTestUtils.getRangingMeasurements(5);
+
+ RangingReport.Builder builder = new RangingReport.Builder();
+ builder.addMeasurements(measurements);
+ RangingReport report = tryBuild(builder, true);
+ verifyMeasurementsEqual(measurements, report.getMeasurements());
+
+
+ builder = new RangingReport.Builder();
+ for (RangingMeasurement measurement : measurements) {
+ builder.addMeasurement(measurement);
+ }
+ report = tryBuild(builder, true);
+ verifyMeasurementsEqual(measurements, report.getMeasurements());
+ }
+
+ private void verifyMeasurementsEqual(List<RangingMeasurement> expected,
+ List<RangingMeasurement> actual) {
+ assertEquals(expected.size(), actual.size());
+ for (int i = 0; i < expected.size(); i++) {
+ assertEquals(expected.get(i), actual.get(i));
+ }
+ }
+
+ private RangingReport tryBuild(RangingReport.Builder builder,
+ boolean expectSuccess) {
+ RangingReport report = null;
+ try {
+ report = builder.build();
+ if (!expectSuccess) {
+ fail("Expected RangingReport.Builder.build() to fail");
+ }
+ } catch (IllegalStateException e) {
+ if (expectSuccess) {
+ fail("Expected RangingReport.Builder.build() to succeed");
+ }
+ }
+ return report;
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ RangingReport report = UwbTestUtils.getRangingReports(5);
+ report.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ RangingReport fromParcel = RangingReport.CREATOR.createFromParcel(parcel);
+ assertEquals(report, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java b/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java
new file mode 100644
index 000000000000..ccc88a9a5399
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/UwbAddressTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.uwb;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test of {@link UwbAddress}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class UwbAddressTest {
+
+ @Test
+ public void testFromBytes_Short() {
+ runFromBytes(UwbAddress.SHORT_ADDRESS_BYTE_LENGTH);
+ }
+
+ @Test
+ public void testFromBytes_Extended() {
+ runFromBytes(UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH);
+ }
+
+ private void runFromBytes(int len) {
+ byte[] addressBytes = getByteArray(len);
+ UwbAddress address = UwbAddress.fromBytes(addressBytes);
+ assertEquals(address.size(), len);
+ assertEquals(addressBytes, address.toBytes());
+ }
+
+ private byte[] getByteArray(int len) {
+ byte[] res = new byte[len];
+ for (int i = 0; i < len; i++) {
+ res[i] = (byte) i;
+ }
+ return res;
+ }
+
+ @Test
+ public void testParcel_Short() {
+ runParcel(true);
+ }
+
+ @Test
+ public void testParcel_Extended() {
+ runParcel(false);
+ }
+
+ private void runParcel(boolean useShortAddress) {
+ Parcel parcel = Parcel.obtain();
+ UwbAddress address = UwbTestUtils.getUwbAddress(useShortAddress);
+ address.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ UwbAddress fromParcel = UwbAddress.CREATOR.createFromParcel(parcel);
+ assertEquals(address, fromParcel);
+ }
+}
diff --git a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
new file mode 100644
index 000000000000..62e0b629539b
--- /dev/null
+++ b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
@@ -0,0 +1,92 @@
+/*
+ * 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.uwb;
+
+import android.os.SystemClock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UwbTestUtils {
+ private UwbTestUtils() {}
+
+ public static AngleMeasurement getAngleMeasurement() {
+ return new AngleMeasurement.Builder()
+ .setRadians(getDoubleInRange(-Math.PI, Math.PI))
+ .setErrorRadians(getDoubleInRange(0, Math.PI))
+ .setConfidenceLevel(getDoubleInRange(0, 1))
+ .build();
+ }
+
+ public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
+ return new AngleOfArrivalMeasurement.Builder()
+ .setAltitudeAngleMeasurement(getAngleMeasurement())
+ .setAzimuthAngleMeasurement(getAngleMeasurement())
+ .build();
+ }
+
+ public static DistanceMeasurement getDistanceMeasurement() {
+ return new DistanceMeasurement.Builder()
+ .setMeters(getDoubleInRange(0, 100))
+ .setErrorMeters(getDoubleInRange(0, 10))
+ .setConfidenceLevel(getDoubleInRange(0, 1))
+ .build();
+ }
+
+ public static RangingMeasurement getRangingMeasurement() {
+ return getRangingMeasurement(getUwbAddress(false));
+ }
+
+ public static RangingMeasurement getRangingMeasurement(UwbAddress address) {
+ return new RangingMeasurement.Builder()
+ .setDistanceMeasurement(getDistanceMeasurement())
+ .setAngleOfArrivalMeasurement(getAngleOfArrivalMeasurement())
+ .setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos())
+ .setRemoteDeviceAddress(address != null ? address : getUwbAddress(false))
+ .setStatus(RangingMeasurement.RANGING_STATUS_SUCCESS)
+ .build();
+ }
+
+ public static List<RangingMeasurement> getRangingMeasurements(int num) {
+ List<RangingMeasurement> result = new ArrayList<>();
+ for (int i = 0; i < num; i++) {
+ result.add(getRangingMeasurement());
+ }
+ return result;
+ }
+
+ public static RangingReport getRangingReports(int numMeasurements) {
+ RangingReport.Builder builder = new RangingReport.Builder();
+ for (int i = 0; i < numMeasurements; i++) {
+ builder.addMeasurement(getRangingMeasurement());
+ }
+ return builder.build();
+ }
+
+ private static double getDoubleInRange(double min, double max) {
+ return min + (max - min) * Math.random();
+ }
+
+ public static UwbAddress getUwbAddress(boolean isShortAddress) {
+ byte[] addressBytes = new byte[isShortAddress ? UwbAddress.SHORT_ADDRESS_BYTE_LENGTH :
+ UwbAddress.EXTENDED_ADDRESS_BYTE_LENGTH];
+ for (int i = 0; i < addressBytes.length; i++) {
+ addressBytes[i] = (byte) getDoubleInRange(1, 255);
+ }
+ return UwbAddress.fromBytes(addressBytes);
+ }
+}
diff --git a/data/etc/car/com.android.car.provision.xml b/data/etc/car/com.android.car.provision.xml
index 37f64b5b8228..474cd543d593 100644
--- a/data/etc/car/com.android.car.provision.xml
+++ b/data/etc/car/com.android.car.provision.xml
@@ -18,6 +18,7 @@
<privapp-permissions package="com.android.car.provision">
<permission name="android.car.permission.CAR_POWERTRAIN"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MASTER_CLEAR"/>
<permission name="android.permission.QUERY_ALL_PACKAGES"/>
<permission name="android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"/>
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 4c3b36f78eec..8406fdf99360 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -164,7 +164,6 @@ applications that come with the platform
<permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
<permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
<permission name="android.permission.DUMP"/>
- <permission name="android.permission.HANDLE_CAR_MODE_CHANGES"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.LOCAL_MAC_ADDRESS"/>
<permission name="android.permission.MANAGE_USERS"/>
@@ -175,6 +174,7 @@ applications that come with the platform
<permission name="android.permission.READ_CARRIER_APP_INFO"/>
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <permission name="android.permission.READ_PROJECTION_STATE"/>
<permission name="android.permission.READ_SEARCH_INDEXABLES"/>
<permission name="android.permission.REBOOT"/>
<permission name="android.permission.REGISTER_CALL_PROVIDER"/>
@@ -356,6 +356,8 @@ applications that come with the platform
<!-- Needed for test only -->
<permission name="android.permission.READ_PRECISE_PHONE_STATE" />
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <!-- Permission required for UiModeManager CTS test -->
+ <permission name="android.permission.READ_PROJECTION_STATE"/>
<permission name="android.permission.READ_WIFI_CREDENTIAL"/>
<permission name="android.permission.REAL_GET_TASKS"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
@@ -376,6 +378,8 @@ applications that come with the platform
<permission name="android.permission.STOP_APP_SWITCHES"/>
<permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
<permission name="android.permission.SUSPEND_APPS" />
+ <!-- Permission required for UiModeManager and Telecom car mode CTS tests -->
+ <permission name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION" />
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.USE_RESERVED_DISK"/>
<permission name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"/>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index bda84dd76cf5..ba2e52a5cf88 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -284,28 +284,28 @@
</family>
<family lang="und-Ethi">
<font weight="400" style="normal">NotoSansEthiopic-VF.ttf
- <axis tag="wght" stylevalue="400" />
+ <axis tag="wght" stylevalue="400"/>
</font>
<font weight="500" style="normal">NotoSansEthiopic-VF.ttf
- <axis tag="wght" stylevalue="500" />
+ <axis tag="wght" stylevalue="500"/>
</font>
<font weight="600" style="normal">NotoSansEthiopic-VF.ttf
- <axis tag="wght" stylevalue="600" />
+ <axis tag="wght" stylevalue="600"/>
</font>
<font weight="700" style="normal">NotoSansEthiopic-VF.ttf
- <axis tag="wght" stylevalue="700" />
+ <axis tag="wght" stylevalue="700"/>
</font>
<font weight="400" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
- <axis tag="wght" stylevalue="400" />
+ <axis tag="wght" stylevalue="400"/>
</font>
<font weight="500" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
- <axis tag="wght" stylevalue="500" />
+ <axis tag="wght" stylevalue="500"/>
</font>
<font weight="600" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
- <axis tag="wght" stylevalue="600" />
+ <axis tag="wght" stylevalue="600"/>
</font>
<font weight="700" style="normal" fallbackFor="serif">NotoSerifEthiopic-VF.ttf
- <axis tag="wght" stylevalue="700" />
+ <axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Hebr">
@@ -326,54 +326,54 @@
</family>
<family lang="und-Armn">
<font weight="400" style="normal">NotoSansArmenian-VF.ttf
- <axis tag="wght" stylevalue="400" />
+ <axis tag="wght" stylevalue="400"/>
</font>
<font weight="500" style="normal">NotoSansArmenian-VF.ttf
- <axis tag="wght" stylevalue="500" />
+ <axis tag="wght" stylevalue="500"/>
</font>
<font weight="600" style="normal">NotoSansArmenian-VF.ttf
- <axis tag="wght" stylevalue="600" />
+ <axis tag="wght" stylevalue="600"/>
</font>
<font weight="700" style="normal">NotoSansArmenian-VF.ttf
- <axis tag="wght" stylevalue="700" />
+ <axis tag="wght" stylevalue="700"/>
</font>
<font weight="400" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
- <axis tag="wght" stylevalue="400" />
+ <axis tag="wght" stylevalue="400"/>
</font>
<font weight="500" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
- <axis tag="wght" stylevalue="500" />
+ <axis tag="wght" stylevalue="500"/>
</font>
<font weight="600" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
- <axis tag="wght" stylevalue="600" />
+ <axis tag="wght" stylevalue="600"/>
</font>
<font weight="700" style="normal" fallbackFor="serif">NotoSerifArmenian-VF.ttf
- <axis tag="wght" stylevalue="700" />
+ <axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Geor,und-Geok">
<font weight="400" style="normal">NotoSansGeorgian-VF.ttf
- <axis tag="wght" stylevalue="400" />
+ <axis tag="wght" stylevalue="400"/>
</font>
<font weight="500" style="normal">NotoSansGeorgian-VF.ttf
- <axis tag="wght" stylevalue="500" />
+ <axis tag="wght" stylevalue="500"/>
</font>
<font weight="600" style="normal">NotoSansGeorgian-VF.ttf
- <axis tag="wght" stylevalue="600" />
+ <axis tag="wght" stylevalue="600"/>
</font>
<font weight="700" style="normal">NotoSansGeorgian-VF.ttf
- <axis tag="wght" stylevalue="700" />
+ <axis tag="wght" stylevalue="700"/>
</font>
<font weight="400" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
- <axis tag="wght" stylevalue="400" />
+ <axis tag="wght" stylevalue="400"/>
</font>
<font weight="500" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
- <axis tag="wght" stylevalue="500" />
+ <axis tag="wght" stylevalue="500"/>
</font>
<font weight="600" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
- <axis tag="wght" stylevalue="600" />
+ <axis tag="wght" stylevalue="600"/>
</font>
<font weight="700" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf
- <axis tag="wght" stylevalue="700" />
+ <axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Deva" variant="elegant">
@@ -491,44 +491,44 @@
</family>
<family lang="und-Khmr" variant="elegant">
<font weight="100" style="normal">NotoSansKhmer-VF.ttf
- <axis tag="wdth" stylevalue="100.0" />
- <axis tag="wght" stylevalue="26.0" />
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="26.0"/>
</font>
<font weight="200" style="normal">NotoSansKhmer-VF.ttf
- <axis tag="wdth" stylevalue="100.0" />
- <axis tag="wght" stylevalue="39.0" />
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="39.0"/>
</font>
<font weight="300" style="normal">NotoSansKhmer-VF.ttf
- <axis tag="wdth" stylevalue="100.0" />
- <axis tag="wght" stylevalue="58.0" />
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="58.0"/>
</font>
<font weight="400" style="normal">NotoSansKhmer-VF.ttf
- <axis tag="wdth" stylevalue="100.0" />
- <axis tag="wght" stylevalue="90.0" />
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="90.0"/>
</font>
<font weight="500" style="normal">NotoSansKhmer-VF.ttf
- <axis tag="wdth" stylevalue="100.0" />
- <axis tag="wght" stylevalue="108.0" />
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="108.0"/>
</font>
<font weight="600" style="normal">NotoSansKhmer-VF.ttf
- <axis tag="wdth" stylevalue="100.0" />
- <axis tag="wght" stylevalue="128.0" />
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="128.0"/>
</font>
<font weight="700" style="normal">NotoSansKhmer-VF.ttf
- <axis tag="wdth" stylevalue="100.0" />
- <axis tag="wght" stylevalue="151.0" />
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="151.0"/>
</font>
<font weight="800" style="normal">NotoSansKhmer-VF.ttf
- <axis tag="wdth" stylevalue="100.0" />
- <axis tag="wght" stylevalue="169.0" />
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="169.0"/>
</font>
<font weight="900" style="normal">NotoSansKhmer-VF.ttf
- <axis tag="wdth" stylevalue="100.0" />
- <axis tag="wght" stylevalue="190.0" />
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="190.0"/>
</font>
<font weight="400" style="normal" fallbackFor="serif">NotoSerifKhmer-Regular.otf</font>
<font weight="700" style="normal" fallbackFor="serif">NotoSerifKhmer-Bold.otf</font>
- </family>
+ </family>
<family lang="und-Khmr" variant="compact">
<font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
<font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
@@ -568,16 +568,16 @@
</family>
<family lang="und-Adlm">
<font weight="400" style="normal">NotoSansAdlam-VF.ttf
- <axis tag="wght" stylevalue="400" />
+ <axis tag="wght" stylevalue="400"/>
</font>
<font weight="500" style="normal">NotoSansAdlam-VF.ttf
- <axis tag="wght" stylevalue="500" />
+ <axis tag="wght" stylevalue="500"/>
</font>
<font weight="600" style="normal">NotoSansAdlam-VF.ttf
- <axis tag="wght" stylevalue="600" />
+ <axis tag="wght" stylevalue="600"/>
</font>
<font weight="700" style="normal">NotoSansAdlam-VF.ttf
- <axis tag="wght" stylevalue="700" />
+ <axis tag="wght" stylevalue="700"/>
</font>
</family>
<family lang="und-Avst">
@@ -762,8 +762,18 @@
<font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
</family>
<family lang="und-Tibt">
- <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
- <font weight="700" style="normal">NotoSansTibetan-Bold.ttf</font>
+ <font weight="400" style="normal">NotoSerifTibetan-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal">NotoSerifTibetan-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal">NotoSerifTibetan-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal">NotoSerifTibetan-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
</family>
<family lang="und-Tfng">
<font weight="400" style="normal">NotoSansTifinagh-Regular.otf</font>
@@ -893,4 +903,83 @@
<family lang="und-Wara">
<font weight="400" style="normal">NotoSansWarangCiti-Regular.otf</font>
</family>
+ <family lang="und-Gran">
+ <font weight="400" style="normal">NotoSansGrantha-Regular.ttf</font>
+ </family>
+ <family lang="und-Modi">
+ <font weight="400" style="normal">NotoSansModi-Regular.ttf</font>
+ </family>
+ <family lang="und-Dogr">
+ <font weight="400" style="normal">NotoSerifDogra-Regular.ttf</font>
+ </family>
+ <family lang="und-Medf">
+ <font weight="400" style="normal">NotoSansMedefaidrin-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal">NotoSansMedefaidrin-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal">NotoSansMedefaidrin-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal">NotoSansMedefaidrin-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Soyo">
+ <font weight="400" style="normal">NotoSansSoyombo-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal">NotoSansSoyombo-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal">NotoSansSoyombo-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal">NotoSansSoyombo-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Takr">
+ <font weight="400" style="normal">NotoSansTakri-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal">NotoSansTakri-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal">NotoSansTakri-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal">NotoSansTakri-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Hmnp">
+ <font weight="400" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal">NotoSerifNyiakengPuachueHmong-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Yezi">
+ <font weight="400" style="normal">NotoSerifYezidi-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal">NotoSerifYezidi-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal">NotoSerifYezidi-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal">NotoSerifYezidi-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
</familyset>
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 94bfdc9dbad6..4309ab24cc22 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -16,6 +16,7 @@
package android.graphics;
+import android.annotation.Nullable;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -60,8 +61,13 @@ public final class BLASTBufferQueue {
return nativeGetSurface(mNativeObject, true /* includeSurfaceControlHandle */);
}
- public void setNextTransaction(SurfaceControl.Transaction t) {
- nativeSetNextTransaction(mNativeObject, t.mNativeObject);
+ /**
+ * Send the transaction to BBQ so the next frame can be added and not applied immediately.
+ * This gives the caller a chance to apply the transaction when it's ready.
+ * @param t The transaction to add the frame to. This can be null to clear the transaction.
+ */
+ public void setNextTransaction(@Nullable SurfaceControl.Transaction t) {
+ nativeSetNextTransaction(mNativeObject, t == null ? 0 : t.mNativeObject);
}
public void update(SurfaceControl sc, int width, int height) {
diff --git a/graphics/java/android/graphics/Compatibility.java b/graphics/java/android/graphics/Compatibility.java
index ed849127aedc..747fbf111b4b 100644
--- a/graphics/java/android/graphics/Compatibility.java
+++ b/graphics/java/android/graphics/Compatibility.java
@@ -16,14 +16,11 @@
package android.graphics;
-import android.annotation.SystemApi;
-
/**
* Helper class for graphics classes to retrieve the targetSdkVersion, as
* specified by the app.
* @hide
*/
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class Compatibility {
private Compatibility() {}
@@ -34,7 +31,6 @@ public final class Compatibility {
* application. No other code should call this.
* @hide
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static void setTargetSdkVersion(int targetSdkVersion) {
sTargetSdkVersion = targetSdkVersion;
Canvas.setCompatibilityVersion(targetSdkVersion);
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 4cac7fbb023b..373228586161 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -27,7 +27,6 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Px;
-import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
import android.content.ContentResolver;
@@ -916,12 +915,8 @@ public final class ImageDecoder implements AutoCloseable {
/**
* Provide Resources for density scaling.
*
- * This is a SystemApi to enable legacy behavior, so there is no need to
- * make it public like the version above, which does not have a Resources
- * parameter.
* @hide
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@AnyThread
@NonNull
public static Source createSource(@NonNull ContentResolver cr,
diff --git a/graphics/java/android/graphics/RenderEffect.java b/graphics/java/android/graphics/RenderEffect.java
index 9fc0c8eb9d90..8b9e36a3b6b1 100644
--- a/graphics/java/android/graphics/RenderEffect.java
+++ b/graphics/java/android/graphics/RenderEffect.java
@@ -17,6 +17,7 @@
package android.graphics;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Shader.TileMode;
import libcore.util.NativeAllocationRegistry;
@@ -24,8 +25,6 @@ import libcore.util.NativeAllocationRegistry;
/**
* Intermediate rendering step used to render drawing commands with a corresponding
* visual effect
- *
- * @hide
*/
public final class RenderEffect {
@@ -99,7 +98,7 @@ public final class RenderEffect {
/**
* Create a {@link RenderEffect} that blurs the contents of the
* {@link android.graphics.RenderNode} that this RenderEffect is installed on with the
- * specified radius along hte x and y axis.
+ * specified radius along the x and y axis.
* @param radiusX Radius of blur along the X axis
* @param radiusY Radius of blur along the Y axis
* @param edgeTreatment Policy for how to blur content near edges of the blur kernel
@@ -117,9 +116,159 @@ public final class RenderEffect {
0,
edgeTreatment.nativeInt
)
+ );
+ }
+
+ /**
+ * Create a {@link RenderEffect} that renders the contents of the input {@link Bitmap}.
+ * This is useful to create an input for other {@link RenderEffect} types such as
+ * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, TileMode)} or
+ * {@link RenderEffect#createColorFilterEffect(ColorFilter, RenderEffect)}
+ *
+ * @param bitmap The source bitmap to be rendered by the created {@link RenderEffect}
+ */
+ @NonNull
+ public static RenderEffect createBitmapEffect(@NonNull Bitmap bitmap) {
+ float right = bitmap.getWidth();
+ float bottom = bitmap.getHeight();
+ return new RenderEffect(
+ nativeCreateBitmapEffect(
+ bitmap.getNativeInstance(),
+ 0f,
+ 0f,
+ right,
+ bottom,
+ 0f,
+ 0f,
+ right,
+ bottom
+ )
);
}
+ /**
+ * Create a {@link RenderEffect} that renders the contents of the input {@link Bitmap}.
+ * This is useful to create an input for other {@link RenderEffect} types such as
+ * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, TileMode)} or
+ * {@link RenderEffect#createColorFilterEffect(ColorFilter, RenderEffect)}
+ *
+ * @param bitmap The source bitmap to be rendered by the created {@link RenderEffect}
+ * @param src Optional subset of the bitmap to be part of the rendered output. If null
+ * is provided, the entire bitmap bounds are used.
+ * @param dst Bounds of the destination which the bitmap is translated and scaled to be
+ * drawn into
+ */
+ @NonNull
+ public static RenderEffect createBitmapEffect(
+ @NonNull Bitmap bitmap,
+ @Nullable Rect src,
+ @NonNull Rect dst
+ ) {
+ long bitmapHandle = bitmap.getNativeInstance();
+ int left = src == null ? 0 : src.left;
+ int top = src == null ? 0 : src.top;
+ int right = src == null ? bitmap.getWidth() : src.right;
+ int bottom = src == null ? bitmap.getHeight() : src.bottom;
+ return new RenderEffect(
+ nativeCreateBitmapEffect(
+ bitmapHandle,
+ left,
+ top,
+ right,
+ bottom,
+ dst.left,
+ dst.top,
+ dst.right,
+ dst.bottom
+ )
+ );
+ }
+
+ /**
+ * Create a filter that applies the color filter to the provided RenderEffect
+ *
+ * @param colorFilter ColorFilter applied to the content in the input RenderEffect
+ * @param renderEffect Source to be transformed by the specified {@link ColorFilter}
+ */
+ @NonNull
+ public static RenderEffect createColorFilterEffect(
+ @NonNull ColorFilter colorFilter,
+ @NonNull RenderEffect renderEffect
+ ) {
+ return new RenderEffect(
+ nativeCreateColorFilterEffect(
+ colorFilter.getNativeInstance(),
+ renderEffect.getNativeInstance()
+ )
+ );
+ }
+
+ /**
+ * Create a filter that applies the color filter to the contents of the
+ * {@link android.graphics.RenderNode} that this RenderEffect is installed on
+ * @param colorFilter ColorFilter applied to the content in the input RenderEffect
+ */
+ @NonNull
+ public static RenderEffect createColorFilterEffect(@NonNull ColorFilter colorFilter) {
+ return new RenderEffect(
+ nativeCreateColorFilterEffect(
+ colorFilter.getNativeInstance(),
+ 0
+ )
+ );
+ }
+
+ /**
+ * {@link RenderEffect} that is a composition of 2 other {@link RenderEffect} instances
+ * combined by the specified {@link BlendMode}
+ *
+ * @param dst The Dst pixels used in blending, if null the source bitmap is used.
+ * @param src The Src pixels used in blending, if null the source bitmap is use
+ * @param blendMode The {@link BlendMode} to be used to combine colors from the two
+ * {@link RenderEffect}s
+ */
+ @NonNull
+ public static RenderEffect createBlendModeEffect(
+ @NonNull RenderEffect dst,
+ @NonNull RenderEffect src,
+ @NonNull BlendMode blendMode
+ ) {
+ return new RenderEffect(
+ nativeCreateBlendModeEffect(
+ dst.getNativeInstance(),
+ src.getNativeInstance(),
+ blendMode.getXfermode().porterDuffMode
+ )
+ );
+ }
+
+ /**
+ * Create a filter that composes 'inner' with 'outer', such that the results of 'inner' are
+ * treated as the source bitmap passed to 'outer', i.e.
+ *
+ * result = outer(inner(source)).
+ *
+ * Consumers should favor explicit chaining of {@link RenderEffect} instances at creation time
+ * rather than using chain effect. Chain effects are useful for situations where the input or
+ * output are provided from elsewhere and the input or output {@link RenderEffect} need to be
+ * changed.
+ *
+ * @param outer {@link RenderEffect} that consumes the output of {@param inner} as its input
+ * @param inner {@link RenderEffect} that is consumed as input by {@param outer}
+ */
+ @NonNull
+ public static RenderEffect createChainEffect(
+ @NonNull RenderEffect outer,
+ @NonNull RenderEffect inner
+ ) {
+ return new RenderEffect(
+ nativeCreateChainEffect(
+ outer.getNativeInstance(),
+ inner.getNativeInstance()
+ )
+ );
+ }
+
private final long mNativeRenderEffect;
/* only constructed from static factory methods */
@@ -141,5 +290,11 @@ public final class RenderEffect {
float offsetX, float offsetY, long nativeInput);
private static native long nativeCreateBlurEffect(
float radiusX, float radiusY, long nativeInput, int edgeTreatment);
+ private static native long nativeCreateBitmapEffect(
+ long bitmapHandle, float srcLeft, float srcTop, float srcRight, float srcBottom,
+ float dstLeft, float dstTop, float dstRight, float dstBottom);
+ private static native long nativeCreateColorFilterEffect(long colorFilter, long nativeInput);
+ private static native long nativeCreateBlendModeEffect(long dst, long src, int blendmode);
+ private static native long nativeCreateChainEffect(long outer, long inner);
private static native long nativeGetFinalizer();
}
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index d812c1a5595d..001ebacfd2cd 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -858,8 +858,6 @@ public final class RenderNode {
* be blurred when this RenderNode is drawn into the destination.
* @param renderEffect to be applied to the RenderNode. Passing null clears all previously
* configured RenderEffects
- *
- * @hide
*/
public void setRenderEffect(@Nullable RenderEffect renderEffect) {
nSetRenderEffect(mNativeRenderNode,
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index b143be7b4d6a..c58e5f36cde3 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -56,6 +56,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -327,7 +328,7 @@ public class Typeface {
* 1) Create Typeface from ttf file.
* <pre>
* <code>
- * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf");
+ * Typeface.Builder builder = new Typeface.Builder("your_font_file.ttf");
* Typeface typeface = builder.build();
* </code>
* </pre>
@@ -335,7 +336,7 @@ public class Typeface {
* 2) Create Typeface from ttc file in assets directory.
* <pre>
* <code>
- * Typeface.Builder buidler = new Typeface.Builder(getAssets(), "your_font_file.ttc");
+ * Typeface.Builder builder = new Typeface.Builder(getAssets(), "your_font_file.ttc");
* builder.setTtcIndex(2); // Set index of font collection.
* Typeface typeface = builder.build();
* </code>
@@ -344,7 +345,7 @@ public class Typeface {
* 3) Create Typeface with variation settings.
* <pre>
* <code>
- * Typeface.Builder buidler = new Typeface.Builder("your_font_file.ttf");
+ * Typeface.Builder builder = new Typeface.Builder("your_font_file.ttf");
* builder.setFontVariationSettings("'wght' 700, 'slnt' 20, 'ital' 1");
* builder.setWeight(700); // Tell the system that this is a bold font.
* builder.setItalic(true); // Tell the system that this is an italic style font.
@@ -1209,6 +1210,36 @@ public class Typeface {
return Arrays.binarySearch(mSupportedAxes, axis) >= 0;
}
+ /**
+ * Writes Typeface instances to the ByteBuffer and returns the number of bytes written.
+ *
+ * <p>If {@code buffer} is null, this method returns the number of bytes required to serialize
+ * the typefaces, without writing anything.
+ * @hide
+ */
+ public static int writeTypefaces(
+ @Nullable ByteBuffer buffer, @NonNull List<Typeface> typefaces) {
+ long[] nativePtrs = new long[typefaces.size()];
+ for (int i = 0; i < nativePtrs.length; i++) {
+ nativePtrs[i] = typefaces.get(i).native_instance;
+ }
+ return nativeWriteTypefaces(buffer, nativePtrs);
+ }
+
+ /**
+ * Reads serialized Typeface instances from the ByteBuffer. Returns null on errors.
+ * @hide
+ */
+ public static @Nullable List<Typeface> readTypefaces(@NonNull ByteBuffer buffer) {
+ long[] nativePtrs = nativeReadTypefaces(buffer);
+ if (nativePtrs == null) return null;
+ List<Typeface> typefaces = new ArrayList<>(nativePtrs.length);
+ for (long nativePtr : nativePtrs) {
+ typefaces.add(new Typeface(nativePtr));
+ }
+ return typefaces;
+ }
+
private static native long nativeCreateFromTypeface(long native_instance, int style);
private static native long nativeCreateFromTypefaceWithExactStyle(
long native_instance, int weight, boolean italic);
@@ -1234,4 +1265,9 @@ public class Typeface {
private static native long nativeGetReleaseFunc();
private static native void nativeRegisterGenericFamily(String str, long nativePtr);
+
+ private static native int nativeWriteTypefaces(
+ @Nullable ByteBuffer buffer, @NonNull long[] nativePtrs);
+
+ private static native @Nullable long[] nativeReadTypefaces(@NonNull ByteBuffer buffer);
}
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index 586c512b3f97..e7c15821e5b3 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -28,6 +28,7 @@ import android.os.LocaleList;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.util.LongSparseArray;
+import android.util.LongSparseLongArray;
import android.util.TypedValue;
import com.android.internal.annotations.GuardedBy;
@@ -69,6 +70,11 @@ public final class Font {
private static final LongSparseArray<WeakReference<Font>> FONT_PTR_MAP =
new LongSparseArray<>();
+ private static final Object SOURCE_ID_LOCK = new Object();
+ @GuardedBy("SOURCE_ID_LOCK")
+ private static final LongSparseLongArray FONT_SOURCE_ID_MAP =
+ new LongSparseLongArray(300); // System font has 200 fonts, so 300 should be enough.
+
/**
* A builder class for creating new Font.
*/
@@ -465,13 +471,24 @@ public final class Font {
final String filePath = mFile == null ? "" : mFile.getAbsolutePath();
long ptr;
+ int fontIdentifier;
if (mFont == null) {
ptr = nBuild(builderPtr, readonlyBuffer, filePath, mWeight, italic, mTtcIndex);
+ long fontBufferPtr = nGetFontBufferAddress(ptr);
+ synchronized (SOURCE_ID_LOCK) {
+ long id = FONT_SOURCE_ID_MAP.get(fontBufferPtr, -1);
+ if (id == -1) {
+ id = FONT_SOURCE_ID_MAP.size();
+ FONT_SOURCE_ID_MAP.put(fontBufferPtr, id);
+ }
+ fontIdentifier = (int) id;
+ }
} else {
ptr = nClone(mFont.getNativePtr(), builderPtr, mWeight, italic, mTtcIndex);
+ fontIdentifier = mFont.mSourceIdentifier;
}
final Font font = new Font(ptr, readonlyBuffer, mFile,
- new FontStyle(mWeight, slant), mTtcIndex, mAxes, mLocaleList);
+ new FontStyle(mWeight, slant), mTtcIndex, mAxes, mLocaleList, fontIdentifier);
sFontRegistry.registerNativeAllocation(font, ptr);
return font;
}
@@ -500,13 +517,15 @@ public final class Font {
private final @IntRange(from = 0) int mTtcIndex;
private final @Nullable FontVariationAxis[] mAxes;
private final @NonNull String mLocaleList;
+ private final int mSourceIdentifier; // An identifier of font source data.
/**
* Use Builder instead
*/
private Font(long nativePtr, @NonNull ByteBuffer buffer, @Nullable File file,
@NonNull FontStyle fontStyle, @IntRange(from = 0) int ttcIndex,
- @Nullable FontVariationAxis[] axes, @NonNull String localeList) {
+ @Nullable FontVariationAxis[] axes, @NonNull String localeList,
+ int sourceIdentifier) {
mBuffer = buffer;
mFile = file;
mFontStyle = fontStyle;
@@ -514,6 +533,7 @@ public final class Font {
mTtcIndex = ttcIndex;
mAxes = axes;
mLocaleList = localeList;
+ mSourceIdentifier = sourceIdentifier;
synchronized (MAP_LOCK) {
FONT_PTR_MAP.append(nGetNativeFontPtr(mNativePtr), new WeakReference<>(this));
@@ -626,25 +646,89 @@ public final class Font {
return mNativePtr;
}
- @Override
- public boolean equals(@Nullable Object o) {
- if (o == this) {
- return true;
- }
- if (!(o instanceof Font)) {
- return false;
- }
- Font f = (Font) o;
- boolean paramEqual = mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex
- && Arrays.equals(f.mAxes, mAxes) && Objects.equals(f.mLocaleList, mLocaleList)
- && Objects.equals(mFile, f.mFile);
+ /**
+ * Returns the unique ID of the source font data.
+ *
+ * You can use this identifier as a key of the cache or checking if two fonts can be
+ * interpolated with font variation settings.
+ * <pre>
+ * <code>
+ * // Following three Fonts, fontA, fontB, fontC have the same identifier.
+ * Font fontA = new Font.Builder("/path/to/font").build();
+ * Font fontB = new Font.Builder(fontA).setTtcIndex(1).build();
+ * Font fontC = new Font.Builder(fontB).setFontVariationSettings("'wght' 700).build();
+ *
+ * // Following fontD has the different identifier from above three.
+ * Font fontD = new Font.Builder("/path/to/another/font").build();
+ *
+ * // Following fontE has different identifier from above four even the font path is the same.
+ * // To get the same identifier, please create new Font instance from existing fonts.
+ * Font fontE = new Font.Builder("/path/to/font").build();
+ * </code>
+ * </pre>
+ *
+ * Here is an example of caching font object that has
+ * <pre>
+ * <code>
+ * private LongSparseArray<SparseArray<Font>> mCache = new LongSparseArray<>();
+ *
+ * private Font getFontWeightVariation(Font font, int weight) {
+ * // Different collection index is treated as different font.
+ * long key = ((long) font.getSourceIdentifier()) << 32 | (long) font.getTtcIndex();
+ *
+ * SparseArray<Font> weightCache = mCache.get(key);
+ * if (weightCache == null) {
+ * weightCache = new SparseArray<>();
+ * mCache.put(key, weightCache);
+ * }
+ *
+ * Font cachedFont = weightCache.get(weight);
+ * if (cachedFont != null) {
+ * return cachedFont;
+ * }
+ *
+ * Font newFont = new Font.Builder(cachedFont)
+ * .setFontVariationSettings("'wght' " + weight);
+ * .build();
+ *
+ * weightCache.put(weight, newFont);
+ * return newFont;
+ * }
+ * </code>
+ * </pre>
+ * @return an unique identifier for the font source data.
+ */
+ public int getSourceIdentifier() {
+ return mSourceIdentifier;
+ }
- if (!paramEqual) {
- return false;
+ /**
+ * Returns true if the given font is created from the same source data from this font.
+ *
+ * This method essentially compares {@link ByteBuffer} inside Font, but has some optimization
+ * for faster comparing. This method compares the internal object before going to one-by-one
+ * byte compare with {@link ByteBuffer}. This typically works efficiently if you compares the
+ * font that is created from {@link Builder#Builder(Font)}.
+ *
+ * This API is typically useful for checking if two fonts can be interpolated by font variation
+ * axes. For example, when you call {@link android.text.TextShaper} for the same
+ * string but different style, you may get two font objects which is created from the same
+ * source but have different parameters. You may want to animate between them by interpolating
+ * font variation settings if these fonts are created from the same source.
+ *
+ * @param other a font object to be compared.
+ * @return true if given font is created from the same source from this font. Otherwise false.
+ */
+ private boolean isSameSource(@NonNull Font other) {
+ Objects.requireNonNull(other);
+
+ // Shortcut for the same instance.
+ if (mBuffer == other.mBuffer) {
+ return true;
}
// Shortcut for different font buffer check by comparing size.
- if (mBuffer.capacity() != f.mBuffer.capacity()) {
+ if (mBuffer.capacity() != other.mBuffer.capacity()) {
return false;
}
@@ -652,15 +736,35 @@ public final class Font {
// underlying native font object holds buffer address, check if this buffer points exactly
// the same address as a shortcut of equality. For being compatible with of API30 or before,
// check buffer position even if the buffer points the same address.
- if (nIsSameBufferAddress(mNativePtr, f.mNativePtr)
- && mBuffer.position() == f.mBuffer.position()) {
+ if (mSourceIdentifier == other.mSourceIdentifier
+ && mBuffer.position() == other.mBuffer.position()) {
return true;
}
// Unfortunately, need to compare bytes one-by-one since the buffer may be different font
// file but has the same file size, or two font has same content but they are allocated
// differently. For being compatible with API30 ore before, compare with ByteBuffer#equals.
- return mBuffer.equals(f.mBuffer);
+ return mBuffer.equals(other.mBuffer);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof Font)) {
+ return false;
+ }
+ Font f = (Font) o;
+ boolean paramEqual = mFontStyle.equals(f.mFontStyle) && f.mTtcIndex == mTtcIndex
+ && Arrays.equals(f.mAxes, mAxes) && Objects.equals(f.mLocaleList, mLocaleList)
+ && Objects.equals(mFile, f.mFile);
+
+ if (!paramEqual) {
+ return false;
+ }
+
+ return isSameSource(f);
}
@Override
@@ -760,5 +864,5 @@ public final class Font {
private static native long nGetNativeFontPtr(long ptr);
@CriticalNative
- private static native boolean nIsSameBufferAddress(long lFontPtr, long rFontPtr);
+ private static native long nGetFontBufferAddress(long font);
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 71e6559c53c6..d1b4464c1aed 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -23,6 +23,7 @@ import android.security.KeyStore;
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterDefs;
+import android.sysprop.Keystore2Properties;
import java.io.IOException;
import java.security.KeyFactory;
@@ -111,6 +112,26 @@ public class AndroidKeyStoreProvider extends Provider {
putSecretKeyFactoryImpl("HmacSHA512");
}
+ private static boolean sKeystore2Enabled;
+
+ /**
+ * This function indicates whether or not Keystore 2.0 is enabled. Some parts of the
+ * Keystore SPI must behave subtly differently when Keystore 2.0 is enabled. However,
+ * the platform property that indicates that Keystore 2.0 is enabled is not readable
+ * by applications. So we set this value when {@code install()} is called because it
+ * is called by zygote, which can access Keystore2Properties.
+ *
+ * This function can be removed once the transition to Keystore 2.0 is complete.
+ * b/171305684
+ *
+ * @return true if Keystore 2.0 is enabled.
+ * @hide
+ */
+ public static boolean isKeystore2Enabled() {
+ return sKeystore2Enabled;
+ }
+
+
/**
* Installs a new instance of this provider (and the
* {@link AndroidKeyStoreBCWorkaroundProvider}).
@@ -138,6 +159,11 @@ public class AndroidKeyStoreProvider extends Provider {
// priority.
Security.addProvider(workaroundProvider);
}
+
+ // {@code install()} is run by zygote when this property is still accessible. We store its
+ // value so that the Keystore SPI can act accordingly without having to access an internal
+ // property.
+ sKeystore2Enabled = Keystore2Properties.keystore2_enabled().orElse(false);
}
private void putSecretKeyFactoryImpl(String algorithm) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 970726051e11..3694d635422f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -211,7 +211,11 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
userAuthenticationValidWhileOnBody,
trustedUserPresenceRequired,
invalidatedByBiometricEnrollment,
- userConfirmationRequired);
+ userConfirmationRequired,
+ // Keystore 1.0 does not tell us the exact security level of the key
+ // so we report an unknown but secure security level.
+ insideSecureHardware ? KeyProperties.SECURITY_LEVEL_UNKNOWN_SECURE
+ : KeyProperties.SECURITY_LEVEL_SOFTWARE);
}
private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
diff --git a/keystore/java/android/security/keystore/ArrayUtils.java b/keystore/java/android/security/keystore/ArrayUtils.java
index f519c7cdd3d2..c8c1de4a5e83 100644
--- a/keystore/java/android/security/keystore/ArrayUtils.java
+++ b/keystore/java/android/security/keystore/ArrayUtils.java
@@ -18,6 +18,8 @@ package android.security.keystore;
import libcore.util.EmptyArray;
+import java.util.function.Consumer;
+
/**
* @hide
*/
@@ -107,4 +109,16 @@ public abstract class ArrayUtils {
return result;
}
}
+
+ /**
+ * Runs {@code consumer.accept()} for each element of {@code array}.
+ * @param array
+ * @param consumer
+ * @hide
+ */
+ public static void forEach(int[] array, Consumer<Integer> consumer) {
+ for (int i : array) {
+ consumer.accept(i);
+ }
+ }
}
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 688c4a7b5969..e9aac7ddb56d 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -27,7 +27,6 @@ import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.os.Build;
import android.security.GateKeeper;
-import android.security.KeyStore;
import android.text.TextUtils;
import java.math.BigInteger;
@@ -246,7 +245,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
private final String mKeystoreAlias;
- private final int mUid;
+ private final int mNamespace;
private final int mKeySize;
private final AlgorithmParameterSpec mSpec;
private final X500Principal mCertificateSubject;
@@ -286,7 +285,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
*/
public KeyGenParameterSpec(
String keyStoreAlias,
- int uid,
+ int namespace,
int keySize,
AlgorithmParameterSpec spec,
X500Principal certificateSubject,
@@ -337,7 +336,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
}
mKeystoreAlias = keyStoreAlias;
- mUid = uid;
+ mNamespace = namespace;
mKeySize = keySize;
mSpec = spec;
mCertificateSubject = certificateSubject;
@@ -382,11 +381,43 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
* Returns the UID which will own the key. {@code -1} is an alias for the UID of the current
* process.
*
+ * @deprecated See deprecation message on {@link KeyGenParameterSpec.Builder#setUid(int)}.
+ * Known namespaces will be translated to their legacy UIDs. Unknown
+ * Namespaces will yield {@link IllegalStateException}.
+ *
* @hide
*/
@UnsupportedAppUsage
+ @Deprecated
public int getUid() {
- return mUid;
+ if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
+ // If Keystore2 has not been enabled we have to behave as if mNamespace is actually
+ // a UID, because we are still being used with the old Keystore SPI.
+ // TODO This if statement and body can be removed when the Keystore 2 migration is
+ // complete. b/171563717
+ return mNamespace;
+ }
+ try {
+ return KeyProperties.namespaceToLegacyUid(mNamespace);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalStateException("getUid called on KeyGenParameterSpec with non legacy"
+ + " keystore namespace.", e);
+ }
+ }
+
+ /**
+ * Returns the target namespace for the key.
+ * See {@link KeyGenParameterSpec.Builder#setNamespace(int)}.
+ *
+ * @return The numeric namespace as configured in the keystore2_key_contexts files of Android's
+ * SEPolicy.
+ * TODO b/171806779 link to public Keystore 2.0 documentation.
+ * See bug for more details for now.
+ * @hide
+ */
+ @SystemApi
+ public int getNamespace() {
+ return mNamespace;
}
/**
@@ -767,7 +798,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
private final String mKeystoreAlias;
private @KeyProperties.PurposeEnum int mPurposes;
- private int mUid = KeyStore.UID_SELF;
+ private int mNamespace = KeyProperties.NAMESPACE_APPLICATION;
private int mKeySize = -1;
private AlgorithmParameterSpec mSpec;
private X500Principal mCertificateSubject;
@@ -830,7 +861,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
*/
public Builder(@NonNull KeyGenParameterSpec sourceSpec) {
this(sourceSpec.getKeystoreAlias(), sourceSpec.getPurposes());
- mUid = sourceSpec.getUid();
+ mNamespace = sourceSpec.getNamespace();
mKeySize = sourceSpec.getKeySize();
mSpec = sourceSpec.getAlgorithmParameterSpec();
mCertificateSubject = sourceSpec.getCertificateSubject();
@@ -873,12 +904,51 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
*
* @param uid UID or {@code -1} for the UID of the current process.
*
+ * @deprecated Setting the UID of the target namespace is based on a hardcoded
+ * hack in the Keystore service. This is no longer supported with Keystore 2.0/Android S.
+ * Instead, dedicated non UID based namespaces can be configured in SEPolicy using
+ * the keystore2_key_contexts files. The functionality of this method will be supported
+ * by mapping knows special UIDs, such as WIFI, to the newly configured SELinux based
+ * namespaces. Unknown UIDs will yield {@link IllegalArgumentException}.
+ *
* @hide
*/
@SystemApi
@NonNull
+ @Deprecated
public Builder setUid(int uid) {
- mUid = uid;
+ if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
+ // If Keystore2 has not been enabled we have to behave as if mNamespace is actually
+ // a UID, because we are still being used with the old Keystore SPI.
+ // TODO This if statement and body can be removed when the Keystore 2 migration is
+ // complete. b/171563717
+ mNamespace = uid;
+ return this;
+ }
+ mNamespace = KeyProperties.legacyUidToNamespace(uid);
+ return this;
+ }
+
+ /**
+ * Set the designated SELinux namespace that the key shall live in. The caller must
+ * have sufficient permissions to install a key in the given namespace. Namespaces
+ * can be created using SEPolicy. The keystore2_key_contexts files map numeric
+ * namespaces to SELinux labels, and SEPolicy can be used to grant access to these
+ * namespaces to the desired target context. This is the preferred way to share
+ * keys between system and vendor components, e.g., WIFI settings and WPA supplicant.
+ *
+ * @param namespace Numeric SELinux namespace as configured in keystore2_key_contexts
+ * of Android's SEPolicy.
+ * TODO b/171806779 link to public Keystore 2.0 documentation.
+ * See bug for more details for now.
+ * @return this Builder object.
+ *
+ * @hide
+ */
+ @SystemApi
+ @NonNull
+ public Builder setNamespace(int namespace) {
+ mNamespace = namespace;
return this;
}
@@ -1489,7 +1559,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
public KeyGenParameterSpec build() {
return new KeyGenParameterSpec(
mKeystoreAlias,
- mUid,
+ mNamespace,
mKeySize,
mSpec,
mCertificateSubject,
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index d891a25dba68..7158d0cf248e 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -84,6 +84,7 @@ public class KeyInfo implements KeySpec {
private final boolean mTrustedUserPresenceRequired;
private final boolean mInvalidatedByBiometricEnrollment;
private final boolean mUserConfirmationRequired;
+ private final @KeyProperties.SecurityLevelEnum int mSecurityLevel;
/**
* @hide
@@ -107,7 +108,8 @@ public class KeyInfo implements KeySpec {
boolean userAuthenticationValidWhileOnBody,
boolean trustedUserPresenceRequired,
boolean invalidatedByBiometricEnrollment,
- boolean userConfirmationRequired) {
+ boolean userConfirmationRequired,
+ @KeyProperties.SecurityLevelEnum int securityLevel) {
mKeystoreAlias = keystoreKeyAlias;
mInsideSecureHardware = insideSecureHardware;
mOrigin = origin;
@@ -131,6 +133,7 @@ public class KeyInfo implements KeySpec {
mTrustedUserPresenceRequired = trustedUserPresenceRequired;
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
mUserConfirmationRequired = userConfirmationRequired;
+ mSecurityLevel = securityLevel;
}
/**
@@ -144,7 +147,10 @@ public class KeyInfo implements KeySpec {
* Returns {@code true} if the key resides inside secure hardware (e.g., Trusted Execution
* Environment (TEE) or Secure Element (SE)). Key material of such keys is available in
* plaintext only inside the secure hardware and is not exposed outside of it.
+ *
+ * @deprecated This method is superseded by @see getSecurityLevel.
*/
+ @Deprecated
public boolean isInsideSecureHardware() {
return mInsideSecureHardware;
}
@@ -355,4 +361,17 @@ public class KeyInfo implements KeySpec {
public boolean isTrustedUserPresenceRequired() {
return mTrustedUserPresenceRequired;
}
+
+ /**
+ * Returns the security level that the key is protected by.
+ * {@code KeyProperties.SecurityLevelEnum.TRUSTED_ENVIRONMENT} and
+ * {@code KeyProperties.SecurityLevelEnum.STRONGBOX} indicate that the key material resides
+ * in secure hardware. Key material of such keys is available in
+ * plaintext only inside the secure hardware and is not exposed outside of it.
+ *
+ * <p>See {@link KeyProperties}.{@code SecurityLevelEnum} constants.
+ */
+ public @KeyProperties.SecurityLevelEnum int getSecurityLevel() {
+ return mSecurityLevel;
+ }
}
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index c58a1236d475..5928540b19bf 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
+import android.security.KeyStore;
import android.security.keymaster.KeymasterDefs;
import libcore.util.EmptyArray;
@@ -496,10 +497,16 @@ public abstract class KeyProperties {
*/
public static final String SIGNATURE_PADDING_RSA_PSS = "PSS";
- static abstract class SignaturePadding {
+ /**
+ * @hide
+ */
+ public abstract static class SignaturePadding {
private SignaturePadding() {}
- static int toKeymaster(@NonNull @SignaturePaddingEnum String padding) {
+ /**
+ * @hide
+ */
+ public static int toKeymaster(@NonNull @SignaturePaddingEnum String padding) {
switch (padding.toUpperCase(Locale.US)) {
case SIGNATURE_PADDING_RSA_PKCS1:
return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
@@ -512,7 +519,7 @@ public abstract class KeyProperties {
}
@NonNull
- static @SignaturePaddingEnum String fromKeymaster(int padding) {
+ public static @SignaturePaddingEnum String fromKeymaster(int padding) {
switch (padding) {
case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
return SIGNATURE_PADDING_RSA_PKCS1;
@@ -524,7 +531,7 @@ public abstract class KeyProperties {
}
@NonNull
- static int[] allToKeymaster(@Nullable @SignaturePaddingEnum String[] paddings) {
+ public static int[] allToKeymaster(@Nullable @SignaturePaddingEnum String[] paddings) {
if ((paddings == null) || (paddings.length == 0)) {
return EmptyArray.INT;
}
@@ -771,4 +778,123 @@ public abstract class KeyProperties {
}
return result;
}
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "SECURITY_LEVEL_" }, value = {
+ SECURITY_LEVEL_UNKNOWN,
+ SECURITY_LEVEL_UNKNOWN_SECURE,
+ SECURITY_LEVEL_SOFTWARE,
+ SECURITY_LEVEL_TRUSTED_ENVIRONMENT,
+ SECURITY_LEVEL_STRONGBOX,
+ })
+ public @interface SecurityLevelEnum {}
+
+ /**
+ * This security level indicates that no assumptions can be made about the security level of the
+ * respective key.
+ */
+ public static final int SECURITY_LEVEL_UNKNOWN = -2;
+ /**
+ * This security level indicates that due to the target API level of the caller no exact
+ * statement can be made about the security level of the key, however, the security level
+ * can be considered is at least equivalent to {@link #SECURITY_LEVEL_TRUSTED_ENVIRONMENT}.
+ */
+ public static final int SECURITY_LEVEL_UNKNOWN_SECURE = -1;
+
+ /** Indicates enforcement by system software. */
+ public static final int SECURITY_LEVEL_SOFTWARE = 0;
+
+ /** Indicates enforcement by a trusted execution environment. */
+ public static final int SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1;
+
+ /**
+ * Indicates enforcement by environment meeting the Strongbox security profile,
+ * such as a secure element.
+ */
+ public static final int SECURITY_LEVEL_STRONGBOX = 2;
+
+ /**
+ * @hide
+ */
+ public abstract static class SecurityLevel {
+ private SecurityLevel() {}
+
+ /**
+ * @hide
+ */
+ public static int toKeymaster(int securityLevel) {
+ switch (securityLevel) {
+ case SECURITY_LEVEL_SOFTWARE:
+ return KeymasterDefs.KM_SECURITY_LEVEL_SOFTWARE;
+ case SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
+ return KeymasterDefs.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ case SECURITY_LEVEL_STRONGBOX:
+ return KeymasterDefs.KM_SECURITY_LEVEL_STRONGBOX;
+ default:
+ throw new IllegalArgumentException("Unsupported security level: "
+ + securityLevel);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @NonNull
+ public static int fromKeymaster(int securityLevel) {
+ switch (securityLevel) {
+ case KeymasterDefs.KM_SECURITY_LEVEL_SOFTWARE:
+ return SECURITY_LEVEL_SOFTWARE;
+ case KeymasterDefs.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
+ return SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ case KeymasterDefs.KM_SECURITY_LEVEL_STRONGBOX:
+ return SECURITY_LEVEL_STRONGBOX;
+ default:
+ throw new IllegalArgumentException("Unsupported security level: "
+ + securityLevel);
+ }
+ }
+ }
+
+ /**
+ * This value indicates the implicit keystore namespace of the calling application.
+ * It is used by default. Only select system components can choose a different namespace
+ * which it must be configured in SEPolicy.
+ * @hide
+ */
+ public static final int NAMESPACE_APPLICATION = -1;
+
+ /**
+ * For legacy support, translate namespaces into known UIDs.
+ * @hide
+ */
+ public static int namespaceToLegacyUid(int namespace) {
+ switch (namespace) {
+ case NAMESPACE_APPLICATION:
+ return KeyStore.UID_SELF;
+ // TODO Translate WIFI and VPN UIDs once the namespaces are defined.
+ // b/171305388 and b/171305607
+ default:
+ throw new IllegalArgumentException("No UID corresponding to namespace "
+ + namespace);
+ }
+ }
+
+ /**
+ * For legacy support, translate namespaces into known UIDs.
+ * @hide
+ */
+ public static int legacyUidToNamespace(int uid) {
+ switch (uid) {
+ case KeyStore.UID_SELF:
+ return NAMESPACE_APPLICATION;
+ // TODO Translate WIFI and VPN UIDs once the namespaces are defined.
+ // b/171305388 and b/171305607
+ default:
+ throw new IllegalArgumentException("No namespace corresponding to uid "
+ + uid);
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 0defbd6451fe..39e32c694d2e 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -116,12 +116,15 @@ android_library {
"res",
],
static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx.arch.core_core-runtime",
"androidx.dynamicanimation_dynamicanimation",
"kotlinx-coroutines-android",
"kotlinx-coroutines-core",
+ "iconloader_base",
"protolog-lib",
+ "SettingsLib",
"WindowManager-Shell-proto",
- "androidx.appcompat_appcompat",
],
kotlincflags: ["-Xjvm-default=enable"],
manifest: "AndroidManifest.xml",
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
index 4390004f5f93..36da7aac9106 100644
--- a/libs/WindowManager/Shell/OWNERS
+++ b/libs/WindowManager/Shell/OWNERS
@@ -1,4 +1,5 @@
# sysui owners
hwwang@google.com
mrenouf@google.com
-winsonc@google.com \ No newline at end of file
+winsonc@google.com
+madym@google.com
diff --git a/packages/CarSystemUI/res/drawable/headsup_scrim_bottom.xml b/libs/WindowManager/Shell/res/drawable/bubble_dismiss_circle.xml
index 1724ef008269..2104be48d1d9 100644
--- a/packages/CarSystemUI/res/drawable/headsup_scrim_bottom.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_dismiss_circle.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -14,11 +13,16 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+<!--
+ The transparent circle outline that encircles the bubbles when they're in the dismiss target.
+-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <gradient
- android:startColor="@android:color/black"
- android:endColor="@android:color/transparent"
- android:angle="90" />
-</shape>
+ 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/CarSystemUI/res/drawable/car_ic_home_selected.xml b/libs/WindowManager/Shell/res/drawable/bubble_dismiss_icon.xml
index 16192df86676..ff8feded11ab 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_home_selected.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_dismiss_icon.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -14,12 +13,14 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+<!-- The 'X' bubble dismiss icon. This is just ic_close with a stroke. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="24"
- android:viewportHeight="24">
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"
- android:fillColor="@color/car_nav_icon_fill_color_selected" />
-</vector> \ No newline at end of file
+ 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>
diff --git a/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml b/libs/WindowManager/Shell/res/drawable/bubble_ic_create_bubble.xml
index 270d932714f3..920671a24204 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_ic_create_bubble.xml
@@ -15,11 +15,11 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
+ android:width="20dp"
+ android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"
- android:fillColor="@color/system_bar_icon_color"/>
-</vector> \ No newline at end of file
+ android:fillColor="#FF000000"
+ android:pathData="M23,5v8h-2V5H3v14h10v2v0H3c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h18C22.1,3 23,3.9 23,5zM10,8v2.59L5.71,6.29L4.29,7.71L8.59,12H6v2h6V8H10zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_dark.xml b/libs/WindowManager/Shell/res/drawable/bubble_ic_empty_overflow_dark.xml
index 8f8f1b664692..8f8f1b664692 100644
--- a/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_dark.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_ic_empty_overflow_dark.xml
diff --git a/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_light.xml b/libs/WindowManager/Shell/res/drawable/bubble_ic_empty_overflow_light.xml
index 5e02f67700e7..5e02f67700e7 100644
--- a/packages/SystemUI/res/drawable/ic_empty_bubble_overflow_light.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_ic_empty_overflow_light.xml
diff --git a/packages/SystemUI/res/drawable/ic_bubble_overflow_button.xml b/libs/WindowManager/Shell/res/drawable/bubble_ic_overflow_button.xml
index 3acebc12a807..3acebc12a807 100644
--- a/packages/SystemUI/res/drawable/ic_bubble_overflow_button.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_ic_overflow_button.xml
diff --git a/packages/CarSystemUI/res/drawable/car_ic_home.xml b/libs/WindowManager/Shell/res/drawable/bubble_ic_stop_bubble.xml
index c78f0edd5594..8609576ce789 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_home.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_ic_stop_bubble.xml
@@ -15,11 +15,11 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M11.29,14.71L7,10.41V13H5V7h6v2H8.41l4.29,4.29L11.29,14.71zM21,3H3C1.9,3 1,3.9 1,5v14c0,1.1 0.9,2 2,2h10v0v-2H3V5h18v8h2V5C23,3.9 22.1,3 21,3zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/bubble_manage_menu_row.xml b/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_row.xml
index a793680a037d..c61ac1c5f2d5 100644
--- a/packages/SystemUI/res/drawable/bubble_manage_menu_row.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_row.xml
@@ -12,7 +12,7 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License
+ ~ limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
diff --git a/packages/SystemUI/res/drawable/bubble_stack_user_education_bg.xml b/libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg.xml
index 4b9219cd6194..4b9219cd6194 100644
--- a/packages/SystemUI/res/drawable/bubble_stack_user_education_bg.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg.xml
diff --git a/packages/SystemUI/res/drawable/bubble_stack_user_education_bg_rtl.xml b/libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg_rtl.xml
index c7baba14b5e5..c7baba14b5e5 100644
--- a/packages/SystemUI/res/drawable/bubble_stack_user_education_bg_rtl.xml
+++ b/libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg_rtl.xml
diff --git a/libs/WindowManager/Shell/res/drawable/ic_remove_no_shadow.xml b/libs/WindowManager/Shell/res/drawable/ic_remove_no_shadow.xml
new file mode 100644
index 000000000000..265c5019c79a
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/ic_remove_no_shadow.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
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/textColorPrimary" >
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.41,12l5.29-5.29c0.39-0.39,0.39-1.02,0-1.41c-0.39-0.39-1.02-0.39-1.41,0L12,10.59L6.71,
+ 5.29c-0.39-0.39-1.02-0.39-1.41,0c-0.39,0.39-0.39,1.02,0,1.41L10.59,12l-5.29,5.29c-0.39,0.39-0.39,1.02,
+ 0,1.41c0.39,0.39,1.02,0.39,1.41,0L12,13.41l5.29,5.29c0.39,0.39,1.02,0.39,1.41,0c0.39-0.39,0.39-1.02,0-1.41L13.41,12z"/>
+</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_rounded_bg_bottom.xml b/libs/WindowManager/Shell/res/drawable/rounded_bg_full.xml
index 07227fbeb0d8..e95744573960 100644
--- a/packages/CarSystemUI/res/drawable/car_rounded_bg_bottom.xml
+++ b/libs/WindowManager/Shell/res/drawable/rounded_bg_full.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2018 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -12,16 +12,15 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License
+ ~ limitations under the License.
-->
-
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?android:attr/colorBackgroundFloating" />
<corners
- android:bottomLeftRadius="@*android:dimen/car_radius_3"
- android:topLeftRadius="0dp"
- android:bottomRightRadius="@*android:dimen/car_radius_3"
- android:topRightRadius="0dp"
+ android:bottomLeftRadius="?android:attr/dialogCornerRadius"
+ android:topLeftRadius="?android:attr/dialogCornerRadius"
+ android:bottomRightRadius="?android:attr/dialogCornerRadius"
+ android:topRightRadius="?android:attr/dialogCornerRadius"
/>
</shape>
diff --git a/packages/SystemUI/res/layout/bubble_dismiss_target.xml b/libs/WindowManager/Shell/res/layout/bubble_dismiss_target.xml
index f5cd727a6d03..f5cd727a6d03 100644
--- a/packages/SystemUI/res/layout/bubble_dismiss_target.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_dismiss_target.xml
diff --git a/packages/SystemUI/res/layout/bubble_expanded_view.xml b/libs/WindowManager/Shell/res/layout/bubble_expanded_view.xml
index db40c4fde053..54b08c6f220e 100644
--- a/packages/SystemUI/res/layout/bubble_expanded_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_expanded_view.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2018 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -12,9 +12,9 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License
+ ~ limitations under the License.
-->
-<com.android.systemui.bubbles.BubbleExpandedView
+<com.android.wm.shell.bubbles.BubbleExpandedView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
@@ -27,7 +27,7 @@
android:layout_height="@dimen/bubble_pointer_height"
/>
- <com.android.systemui.statusbar.AlphaOptimizedButton
+ <com.android.wm.shell.common.AlphaOptimizedButton
style="@android:style/Widget.Material.Button.Borderless"
android:id="@+id/settings_button"
android:layout_gravity="start"
@@ -35,7 +35,7 @@
android:layout_height="wrap_content"
android:focusable="true"
android:text="@string/manage_bubbles_text"
- android:textColor="?attr/wallpaperTextColor"
+ android:textColor="?android:attr/textColorPrimaryInverse"
/>
-</com.android.systemui.bubbles.BubbleExpandedView>
+</com.android.wm.shell.bubbles.BubbleExpandedView>
diff --git a/packages/SystemUI/res/layout/bubble_flyout.xml b/libs/WindowManager/Shell/res/layout/bubble_flyout.xml
index 22a81357ee15..7fdf290efd09 100644
--- a/packages/SystemUI/res/layout/bubble_flyout.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_flyout.xml
@@ -34,7 +34,7 @@
android:layout_height="30dp"
android:layout_marginEnd="@dimen/bubble_flyout_avatar_message_space"
android:scaleType="centerInside"
- android:src="@drawable/ic_create_bubble"/>
+ android:src="@drawable/bubble_ic_create_bubble"/>
<LinearLayout
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/bubble_manage_menu.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
index 84948828bdbe..3a6aa805d071 100644
--- a/packages/SystemUI/res/layout/bubble_manage_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_menu.xml
@@ -35,7 +35,7 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_remove_no_shadow"
- android:tint="@color/global_actions_text"/>
+ android:tint="@color/bubbles_icon_tint"/>
<TextView
android:layout_width="wrap_content"
@@ -59,8 +59,8 @@
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
- android:src="@drawable/ic_stop_bubble"
- android:tint="@color/global_actions_text"/>
+ android:src="@drawable/bubble_ic_stop_bubble"
+ android:tint="@color/bubbles_icon_tint"/>
<TextView
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/bubble_menu_view.xml b/libs/WindowManager/Shell/res/layout/bubble_menu_view.xml
index 24608d3e9611..d19b65394cd8 100644
--- a/packages/SystemUI/res/layout/bubble_menu_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_menu_view.xml
@@ -14,30 +14,32 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.bubbles.BubbleMenuView
+<com.android.wm.shell.bubbles.BubbleMenuView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="#66000000"
android:visibility="gone"
- android:id="@+id/bubble_menu_container">
+ android:id="@+id/bubble_menu_container"
+ tools:ignore="MissingClass">
<FrameLayout
- android:layout_height="@dimen/individual_bubble_size"
+ android:layout_height="@dimen/bubble_menu_item_height"
android:layout_width="wrap_content"
android:background="#FFFFFF"
android:id="@+id/bubble_menu_view">
<ImageView
android:id="@*android:id/icon"
- android:layout_width="@dimen/global_actions_grid_item_icon_width"
- android:layout_height="@dimen/global_actions_grid_item_icon_height"
- android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin"
- android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin"
- android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
- android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
+ android:layout_width="@dimen/bubble_grid_item_icon_width"
+ android:layout_height="@dimen/bubble_grid_item_icon_height"
+ android:layout_marginTop="@dimen/bubble_grid_item_icon_top_margin"
+ android:layout_marginBottom="@dimen/bubble_grid_item_icon_bottom_margin"
+ android:layout_marginLeft="@dimen/bubble_grid_item_icon_side_margin"
+ android:layout_marginRight="@dimen/bubble_grid_item_icon_side_margin"
android:scaleType="centerInside"
- android:tint="@color/global_actions_text"
+ android:tint="@color/bubbles_icon_tint"
/>
</FrameLayout>
-</com.android.systemui.bubbles.BubbleMenuView>
+</com.android.wm.shell.bubbles.BubbleMenuView>
diff --git a/packages/SystemUI/res/layout/bubble_overflow_activity.xml b/libs/WindowManager/Shell/res/layout/bubble_overflow_activity.xml
index 306061911f8d..306061911f8d 100644
--- a/packages/SystemUI/res/layout/bubble_overflow_activity.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_overflow_activity.xml
diff --git a/packages/SystemUI/res/layout/bubble_overflow_button.xml b/libs/WindowManager/Shell/res/layout/bubble_overflow_button.xml
index 8f0fd4f37461..e392cdc26c60 100644
--- a/packages/SystemUI/res/layout/bubble_overflow_button.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_overflow_button.xml
@@ -14,9 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<com.android.systemui.bubbles.BadgedImageView
+<com.android.wm.shell.bubbles.BadgedImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/bubble_overflow_button"
- android:layout_width="@dimen/individual_bubble_size"
- android:layout_height="@dimen/individual_bubble_size"
- android:src="@drawable/ic_bubble_overflow_button"/>
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/bubble_ic_overflow_button"/>
diff --git a/packages/SystemUI/res/layout/bubble_overflow_view.xml b/libs/WindowManager/Shell/res/layout/bubble_overflow_view.xml
index 1218fba23502..c1f67bd27d93 100644
--- a/packages/SystemUI/res/layout/bubble_overflow_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_overflow_view.xml
@@ -21,7 +21,7 @@
android:layout_height="wrap_content"
android:orientation="vertical">
- <com.android.systemui.bubbles.BadgedImageView
+ <com.android.wm.shell.bubbles.BadgedImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/bubble_view"
android:layout_gravity="center"
diff --git a/packages/SystemUI/res/layout/bubble_stack_user_education.xml b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
index fe1ed4b6f726..fe1ed4b6f726 100644
--- a/packages/SystemUI/res/layout/bubble_stack_user_education.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_stack_user_education.xml
diff --git a/packages/SystemUI/res/layout/bubble_view.xml b/libs/WindowManager/Shell/res/layout/bubble_view.xml
index 78f7cffab650..2b4b9e9042c9 100644
--- a/packages/SystemUI/res/layout/bubble_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_view.xml
@@ -14,8 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<com.android.systemui.bubbles.BadgedImageView
+<com.android.wm.shell.bubbles.BadgedImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/bubble_view"
- android:layout_width="@dimen/individual_bubble_size"
- android:layout_height="@dimen/individual_bubble_size"/>
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
diff --git a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
index b51dc93dc373..8de06c7732d4 100644
--- a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
+++ b/libs/WindowManager/Shell/res/layout/bubbles_manage_button_education.xml
@@ -64,7 +64,7 @@
android:id="@+id/button_layout"
android:orientation="horizontal" >
- <com.android.systemui.statusbar.AlphaOptimizedButton
+ <com.android.wm.shell.common.AlphaOptimizedButton
style="@android:style/Widget.Material.Button.Borderless"
android:id="@+id/manage"
android:layout_gravity="start"
@@ -73,10 +73,10 @@
android:focusable="true"
android:clickable="false"
android:text="@string/manage_bubbles_text"
- android:textColor="?attr/wallpaperTextColor"
+ android:textColor="?android:attr/textColorPrimaryInverse"
/>
- <com.android.systemui.statusbar.AlphaOptimizedButton
+ <com.android.wm.shell.common.AlphaOptimizedButton
style="@android:style/Widget.Material.Button.Borderless"
android:id="@+id/got_it"
android:layout_gravity="start"
@@ -84,7 +84,7 @@
android:layout_height="wrap_content"
android:focusable="true"
android:text="@string/bubbles_user_education_got_it"
- android:textColor="?attr/wallpaperTextColor"
+ android:textColor="?android:attr/textColorPrimaryInverse"
/>
</LinearLayout>
</LinearLayout>
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
index d8474b865a36..0d684e8b0ab5 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
@@ -15,6 +15,7 @@
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tv_pip_menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
index bee9f4163b04..8213f2fec04d 100644
--- a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
+++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
@@ -79,11 +79,11 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/splitscreen\/SplitScreenTaskListener.java"
},
- "-712674749": {
- "message": "Clip description: %s",
+ "-742394458": {
+ "message": "pair task1=%d task2=%d in AppPair=%s",
"level": "VERBOSE",
- "group": "WM_SHELL_DRAG_AND_DROP",
- "at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java"
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/apppairs\/AppPair.java"
},
"-710770147": {
"message": "Add target: %s",
@@ -97,6 +97,12 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/splitscreen\/SplitScreenTaskListener.java"
},
+ "-234284913": {
+ "message": "unpair taskId=%d pair=%s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/apppairs\/AppPairsController.java"
+ },
"-191422040": {
"message": "Transition animations finished, notifying core %s",
"level": "VERBOSE",
@@ -121,6 +127,12 @@
"group": "WM_SHELL_DRAG_AND_DROP",
"at": "com\/android\/wm\/shell\/draganddrop\/DropOutlineDrawable.java"
},
+ "375908576": {
+ "message": "Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_DRAG_AND_DROP",
+ "at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java"
+ },
"481673835": {
"message": "addListenerForTaskId taskId=%s",
"level": "VERBOSE",
@@ -139,12 +151,30 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
+ "900599280": {
+ "message": "Can't pair unresizeable tasks task1.isResizeable=%b task1.isResizeable=%b",
+ "level": "ERROR",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/apppairs\/AppPair.java"
+ },
+ "950299522": {
+ "message": "taskId %d isn't isn't in an app-pair.",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/apppairs\/AppPairsController.java"
+ },
"980952660": {
"message": "Task root back pressed taskId=%d",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
+ "1079041527": {
+ "message": "incrementPool size=%d",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/apppairs\/AppPairsPool.java"
+ },
"1104702476": {
"message": "Letterbox Task Changed: #%d",
"level": "VERBOSE",
@@ -169,24 +199,30 @@
"group": "WM_SHELL_DRAG_AND_DROP",
"at": "com\/android\/wm\/shell\/draganddrop\/DragLayout.java"
},
- "1842752748": {
- "message": "Clip description: handlingDrag=%b mimeTypes=%s",
- "level": "VERBOSE",
- "group": "WM_SHELL_DRAG_AND_DROP",
- "at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java"
- },
"1862198614": {
"message": "Drag event: action=%s x=%f y=%f xOffset=%f yOffset=%f",
"level": "VERBOSE",
"group": "WM_SHELL_DRAG_AND_DROP",
"at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java"
},
+ "1891981945": {
+ "message": "release entry.taskId=%s listener=%s size=%d",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/apppairs\/AppPairsPool.java"
+ },
"1990759023": {
"message": "addListenerForType types=%s listener=%s",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
+ "2006473416": {
+ "message": "acquire entry.taskId=%s listener=%s size=%d",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/apppairs\/AppPairsPool.java"
+ },
"2057038970": {
"message": "Display changed: %d",
"level": "VERBOSE",
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
new file mode 100644
index 000000000000..7698e511a209
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Maak toe"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Vou uit"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Instellings"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Kieslys"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in beeld-in-beeld"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"As jy nie wil hê dat <xliff:g id="NAME">%s</xliff:g> hierdie kenmerk moet gebruik nie, tik om instellings oop te maak en skakel dit af."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Speel"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Laat wag"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Slaan oor na volgende"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Slaan oor na vorige"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Verander grootte"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Program steun nie verdeelde skerm nie."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Program sal dalk nie op \'n sekondêre skerm werk nie."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Program steun nie begin op sekondêre skerms nie."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Skermverdeler"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Volskerm links"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Links 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Links 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Links 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Volskerm regs"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Volskerm bo"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Bo 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bo 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Bo 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Volskerm onder"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Instellings vir <xliff:g id="APP_NAME">%1$s</xliff:g>-borrels"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Oorloop"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Voeg terug op stapel"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> vanaf <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g> en <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> meer af"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Beweeg na links bo"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Beweeg na regs bo"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Beweeg na links onder"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Beweeg na regs onder"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-instellings"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Maak borrel toe"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Moenie dat gesprek \'n borrel word nie"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Klets met borrels"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nuwe gesprekke verskyn as swerwende ikone, of borrels Tik op borrel om dit oop te maak. Sleep om dit te skuif."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Beheer borrels enige tyd"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tik op Bestuur om borrels vanaf hierdie program af te skakel"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Geen onlangse borrels nie"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Onlangse borrels en borrels wat toegemaak is, sal hier verskyn"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Borrel"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Bestuur"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Borrel is toegemaak."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-af/strings_tv.xml b/libs/WindowManager/Shell/res/values-af/strings_tv.xml
new file mode 100644
index 000000000000..d5e9b9253833
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-af/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Titellose program)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Maak PIP toe"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Volskerm"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
new file mode 100644
index 000000000000..49436badb6c1
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"ዝጋ"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"ዘርጋ"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"ቅንብሮች"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"ምናሌ"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> በስዕል-ላይ-ስዕል ውስጥ ነው"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ይህን ባህሪ እንዲጠቀም ካልፈለጉ ቅንብሮችን ለመክፈት መታ ያድርጉና ያጥፉት።"</string>
+ <string name="pip_play" msgid="3496151081459417097">"አጫውት"</string>
+ <string name="pip_pause" msgid="690688849510295232">"ባለበት አቁም"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"ወደ ቀጣይ ዝለል"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"ወደ ቀዳሚ ዝለል"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"መጠን ይቀይሩ"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"መተግበሪያው የተከፈለ ማያ ገጽን አይደግፍም።"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"መተግበሪያ በሁለተኛ ማሳያ ላይ ላይሠራ ይችላል።"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"መተግበሪያ በሁለተኛ ማሳያዎች ላይ ማስጀመርን አይደግፍም።"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"የተከፈለ የማያ ገጽ ከፋይ"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"የግራ ሙሉ ማያ ገጽ"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ግራ 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ግራ 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ግራ 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"የቀኝ ሙሉ ማያ ገጽ"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"የላይ ሙሉ ማያ ገጽ"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ከላይ 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ከላይ 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ከላይ 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"የታች ሙሉ ማያ ገጽ"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"ቅንብሮች ለ <xliff:g id="APP_NAME">%1$s</xliff:g> አረፋዎች"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ትርፍ ፍሰት"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"ወደ ቁልል መልሰው ያክሉ"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ከ<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ከ <xliff:g id="APP_NAME">%2$s</xliff:g> እና <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ተጨማሪ"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ወደ ላይኛው ግራ አንቀሳቅስ"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ወደ ላይኛው ቀኝ አንቀሳቅስ"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"የግርጌውን ግራ አንቀሳቅስ"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ታችኛውን ቀኝ ያንቀሳቅሱ"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"የ<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ቅንብሮች"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"አረፋን አሰናብት"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ውይይቶችን በአረፋ አታሳይ"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"አረፋዎችን በመጠቀም ይወያዩ"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"አዲስ ውይይቶች እንደ ተንሳፋፊ አዶዎች ወይም አረፋዎች ሆነው ይታያሉ። አረፋን ለመክፈት መታ ያድርጉ። ለመውሰድ ይጎትቱት።"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"በማንኛውም ጊዜ አረፋዎችን ይቆጣጠሩ"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"የዚህ መተግበሪያ አረፋዎችን ለማጥፋት አቀናብርን መታ ያድርጉ"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ምንም የቅርብ ጊዜ አረፋዎች የሉም"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"የቅርብ ጊዜ አረፋዎች እና የተሰናበቱ አረፋዎች እዚህ ብቅ ይላሉ"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"አረፋ"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"ያቀናብሩ"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"አረፋ ተሰናብቷል።"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-am/strings_tv.xml b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
new file mode 100644
index 000000000000..1661882e60fc
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-am/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ርዕስ የሌለው ፕሮግራም)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIPን ዝጋ"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"ሙሉ ማያ ገጽ"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
new file mode 100644
index 000000000000..3e812551265c
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"إغلاق"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"توسيع"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"الإعدادات"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"القائمة"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> يظهر في صورة داخل صورة"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"إذا كنت لا تريد أن يستخدم <xliff:g id="NAME">%s</xliff:g> هذه الميزة، فانقر لفتح الإعدادات، ثم أوقِف تفعيل هذه الميزة."</string>
+ <string name="pip_play" msgid="3496151081459417097">"تشغيل"</string>
+ <string name="pip_pause" msgid="690688849510295232">"إيقاف مؤقت"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"التخطي إلى التالي"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"التخطي إلى السابق"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"تغيير الحجم"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"التطبيق لا يتيح تقسيم الشاشة."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"قد لا يعمل التطبيق على شاشة عرض ثانوية."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"لا يمكن تشغيل التطبيق على شاشات عرض ثانوية."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"أداة تقسيم الشاشة"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"عرض النافذة اليسرى بملء الشاشة"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ضبط حجم النافذة اليسرى ليكون ٧٠%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ضبط حجم النافذة اليسرى ليكون ٥٠%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ضبط حجم النافذة اليسرى ليكون ٣٠%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"عرض النافذة اليمنى بملء الشاشة"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"عرض النافذة العلوية بملء الشاشة"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ضبط حجم النافذة العلوية ليكون ٧٠%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ضبط حجم النافذة العلوية ليكون ٥٠%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ضبط حجم النافذة العلوية ليكون ٣٠%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"عرض النافذة السفلية بملء الشاشة"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"إعدادات فقاعات المحادثات على <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"القائمة الكاملة"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"إضافة دعم إلى الحزم"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> من <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> من <xliff:g id="APP_NAME">%2$s</xliff:g> و<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> أيضًا"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"نقل إلى أعلى يمين الشاشة"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"الانتقال إلى أعلى اليسار"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"نقل إلى أسفل يمين الشاشة"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"نقل إلى أسفل اليسار"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"إعدادات <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"إغلاق فقاعة المحادثة"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"عدم عرض المحادثة كفقاعة محادثة"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"الدردشة باستخدام فقاعات المحادثات"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"تظهر المحادثات الجديدة كرموز عائمة أو كفقاعات. انقر لفتح فقاعة المحادثة، واسحبها لتحريكها."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"التحكّم في فقاعات المحادثات في أي وقت"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"انقر على \"إدارة\" لإيقاف فقاعات المحادثات من هذا التطبيق."</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ليس هناك فقاعات محادثات"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ستظهر هنا أحدث فقاعات المحادثات وفقاعات المحادثات التي تم إغلاقها."</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"فقاعة"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"إدارة"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"تم إغلاق الفقاعة."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings_tv.xml b/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
new file mode 100644
index 000000000000..61588a0101aa
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ar/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ليس هناك عنوان للبرنامج)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"‏إغلاق PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"ملء الشاشة"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
new file mode 100644
index 000000000000..81cdc7fb699d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"বন্ধ কৰক"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"বিস্তাৰ কৰক"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"ছেটিংসমূহ"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"মেনু"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> চিত্ৰৰ ভিতৰৰ চিত্ৰত আছে"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"আপুনি যদি <xliff:g id="NAME">%s</xliff:g> সুবিধাটো ব্যৱহাৰ কৰিব নোখোজে, তেন্তে ছেটিংসমূহ খুলিবলৈ টিপক আৰু তালৈ গৈ ইয়াক অফ কৰক।"</string>
+ <string name="pip_play" msgid="3496151081459417097">"প্লে কৰক"</string>
+ <string name="pip_pause" msgid="690688849510295232">"পজ কৰক"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"পৰৱৰ্তী মিডিয়ালৈ যাওক"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"আগৰটো মিডিয়ালৈ যাওক"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"আকাৰ সলনি কৰক"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"এপটোৱে বিভাজিত স্ক্ৰীণ সমৰ্থন নকৰে।"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"গৌণ ডিছপ্লেত এপে সঠিকভাৱে কাম নকৰিব পাৰে।"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"গৌণ ডিছপ্লেত এপ্ লঞ্চ কৰিব নোৱাৰি।"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"স্প্লিট স্ক্ৰীণৰ বিভাজক"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"বাওঁফালৰ স্ক্ৰীণখন সম্পূৰ্ণ স্ক্ৰীণ কৰক"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"বাওঁফালৰ স্ক্ৰীণখন ৭০% কৰক"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"বাওঁফালৰ স্ক্ৰীণখন ৫০% কৰক"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"বাওঁফালৰ স্ক্ৰীণখন ৩০% কৰক"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"সোঁফালৰ স্ক্ৰীণখন সম্পূৰ্ণ স্ক্ৰীণ কৰক"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"শীৰ্ষ স্ক্ৰীণখন সম্পূৰ্ণ স্ক্ৰীণ কৰক"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"শীর্ষ স্ক্ৰীণখন ৭০% কৰক"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ স্ক্ৰীণখন ৫০% কৰক"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"শীর্ষ স্ক্ৰীণখন ৩০% কৰক"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"তলৰ স্ক্ৰীণখন সম্পূৰ্ণ স্ক্ৰীণ কৰক"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ bubblesৰ ছেটিংসমূহ"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"অভাৰফ্ল’"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"ষ্টেকত পুনৰ যোগ দিয়ক"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g>ৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> আৰু<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>টাৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"শীৰ্ষৰ বাওঁফালে নিয়ক"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"শীৰ্ষৰ সোঁফালে নিয়ক"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"বুটামটো বাওঁফালে নিয়ক"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"তলৰ সোঁফালে নিয়ক"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ছেটিংসমূহ"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"বাবল অগ্ৰাহ্য কৰক"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"বাৰ্তালাপ বাবল নকৰিব"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Bubbles ব্যৱহাৰ কৰি চাট কৰক"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"নতুন বাৰ্তালাপ উপঙি থকা চিহ্নসমূহ অথবা bubbles হিচাপে প্ৰদর্শিত হয়। Bubbles খুলিবলৈ টিপক। এইটো স্থানান্তৰ কৰিবলৈ টানি নিয়ক।"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"যিকোনো সময়তে bubbles নিয়ন্ত্ৰণ কৰক"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"এই এপ্‌টোৰ পৰা bubbles অফ কৰিবলৈ পৰিচালনা কৰকত টিপক"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"কোনো শেহতীয়া bubbles নাই"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"শেহতীয়া bubbles আৰু অগ্ৰাহ্য কৰা bubbles ইয়াত প্ৰদর্শিত হ\'ব"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"বাবল"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"পৰিচালনা কৰক"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল অগ্ৰাহ্য কৰা হৈছে"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-as/strings_tv.xml b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
new file mode 100644
index 000000000000..c4e3f3833052
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-as/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(শিৰোনামবিহীন কাৰ্যক্ৰম)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"পিপ বন্ধ কৰক"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"সম্পূৰ্ণ স্ক্ৰীণ"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
new file mode 100644
index 000000000000..7e8590f16412
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Bağlayın"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Genişləndirin"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Ayarlar"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menyu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> şəkil içində şəkildədir"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> tətbiqinin bu funksiyadan istifadə etməyini istəmirsinizsə, ayarları açmaq və deaktiv etmək üçün klikləyin."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Oxudun"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Fasilə verin"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Növbətiyə keçin"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Əvvəlkinə keçin"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ölçüsünü dəyişin"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Tətbiq ekran bölünməsini dəstəkləmir."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Tətbiq ikinci ekranda işləməyə bilər."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Tətbiq ikinci ekranda başlamağı dəstəkləmir."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Bölünmüş ekran ayırıcısı"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Sol tam ekran"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Sol 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sol 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Sol 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Sağ tam ekran"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Yuxarı tam ekran"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Yuxarı 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yuxarı 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Yuxarı 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Aşağı tam ekran"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> yumrucuqları üçün ayarlar"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Kənara çıxma"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Yenidən dəstəyə əlavə edin"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> tətbiqindən <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> tətbiqindən <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> və daha <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> qabarcıq"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Yuxarıya sola köçürün"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Yuxarıya sağa köçürün"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Aşağıya sola köçürün"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Aşağıya sağa köçürün"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ayarları"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Yumrucuğu ləğv edin"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Söhbəti yumrucuqda göstərmə"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Yumrucuqlardan istifadə edərək söhbət edin"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Yeni söhbətlər üzən nişanlar və ya yumrucuqlar kimi görünür. Yumrucuğu açmaq üçün toxunun. Hərəkət etdirmək üçün sürüşdürün."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Yumrucuqları istənilən vaxt idarə edin"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Bu tətbiqdə yumrucuqları deaktiv etmək üçün \"İdarə edin\" seçiminə toxunun"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Yumrucuqlar yoxdur"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Son yumrucuqlar və buraxılmış yumrucuqlar burada görünəcək"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Qabarcıq"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"İdarə edin"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Qabarcıqdan imtina edilib."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-az/strings_tv.xml b/libs/WindowManager/Shell/res/values-az/strings_tv.xml
new file mode 100644
index 000000000000..58e9d106cd6c
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-az/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Başlıqsız proqram)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP bağlayın"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Tam ekran"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 000000000000..9b2c49acc762
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Zatvori"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Proširi"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Podešavanja"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Meni"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> je slika u slici"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ako ne želite da <xliff:g id="NAME">%s</xliff:g> koristi ovu funkciju, dodirnite da biste otvorili podešavanja i isključili je."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Pusti"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pauziraj"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Pređi na sledeće"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Pređi na prethodno"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promenite veličinu"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podeljeni ekran."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionisati na sekundarnom ekranu."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim ekranima."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Razdelnik podeljenog ekrana"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Režim celog ekrana za levi ekran"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Levi ekran 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Levi ekran 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Levi ekran 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Režim celog ekrana za donji ekran"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Režim celog ekrana za gornji ekran"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gornji ekran 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gornji ekran 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gornji ekran 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Režim celog ekrana za donji ekran"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Podešavanja za <xliff:g id="APP_NAME">%1$s</xliff:g> oblačiće"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Preklapanje"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Dodaj ponovo u grupu"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Premesti gore levo"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Premesti gore desno"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Premesti dole levo"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Premesti dole desno"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Podešavanja za <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Odbaci oblačić"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne koristi oblačiće za konverzaciju"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Ćaskajte u oblačićima"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nove konverzacije se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da biste otvorili oblačić. Prevucite da biste ga premestili."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Kontrolišite oblačiće u bilo kom trenutku"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Dodirnite Upravljajte da biste isključili oblačiće iz ove aplikacije"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nema nedavnih oblačića"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Ovde se prikazuju nedavni i odbačeni oblačići"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljajte"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić je odbačen."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
new file mode 100644
index 000000000000..d341fd23348c
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez naslova)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Zatvori PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Ceo ekran"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
new file mode 100644
index 000000000000..b42e2ce3dfe3
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Закрыць"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Разгарнуць"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Налады"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> з’яўляецца відарысам у відарысе"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Калі вы не хочаце, каб праграма <xliff:g id="NAME">%s</xliff:g> выкарыстоўвала гэту функцыю, дакраніцеся, каб адкрыць налады і адключыць яе."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Прайграць"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Прыпыніць"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Перайсці да наступнага"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Перайсці да папярэдняга"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Змяніць памер"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Праграма не падтрымлівае функцыю дзялення экрана."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Праграма можа не працаваць на дадатковых экранах."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Праграма не падтрымлівае запуск на дадатковых экранах."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Раздзяляльнік падзеленага экрана"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Левы экран – поўнаэкранны рэжым"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Левы экран – 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левы экран – 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Левы экран – 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Правы экран – поўнаэкранны рэжым"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Верхні экран – поўнаэкранны рэжым"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Верхні экран – 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхні экран – 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Верхні экран – 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ніжні экран – поўнаэкранны рэжым"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Налады ўсплывальных апавяшчэнняў у праграме \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Дадатковае меню"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Зноў дадаць у стос"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ад праграмы \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ад праграмы \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" і яшчэ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Перамясціць лявей і вышэй"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Перамясціце правей і вышэй"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Перамясціць лявей і ніжэй"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Перамясціць правей і ніжэй"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Налады \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\""</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Адхіліць апавяшчэнне"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не паказваць размову ў выглядзе ўсплывальных апавяшчэнняў"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Усплывальныя апавяшчэнні"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Новыя размовы будуць паказвацца як рухомыя значкі ці ўсплывальныя апавяшчэнні. Націсніце, каб адкрыць усплывальнае апавяшчэнне. Перацягніце яго, каб перамясціць."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Кіруйце ўсплывальнымі апавяшчэннямі ў любы час"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Каб выключыць усплывальныя апавяшчэнні з гэтай праграмы, націсніце \"Кіраваць\""</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Няма нядаўніх усплывальных апавяшчэнняў"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Нядаўнія і адхіленыя ўсплывальныя апавяшчэнні будуць паказаны тут"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Усплывальнае апавяшчэнне"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Кіраваць"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Усплывальнае апавяшчэнне адхілена."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-be/strings_tv.xml b/libs/WindowManager/Shell/res/values-be/strings_tv.xml
new file mode 100644
index 000000000000..527b5af8195f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-be/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Праграма без назвы)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Закрыць PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Ва ўвесь экран"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
new file mode 100644
index 000000000000..df25b8fb16ee
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Затваряне"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Разгъване"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Настройки"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> е в режима „Картина в картината“"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ако не искате <xliff:g id="NAME">%s</xliff:g> да използва тази функция, докоснете, за да отворите настройките, и я изключете."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Пускане"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Поставяне на пауза"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Към следващия елемент"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Към предишния елемент"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Преоразмеряване"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложението не поддържа разделен екран."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Възможно е приложението да не работи на алтернативни дисплеи."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Приложението не поддържа използването на алтернативни дисплеи."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Разделител в режима за разделен екран"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ляв екран: Показване на цял екран"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ляв екран: 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ляв екран: 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ляв екран: 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Десен екран: Показване на цял екран"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Горен екран: Показване на цял екран"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горен екран: 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горен екран: 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Горен екран: 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Долен екран: Показване на цял екран"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Настройки за балончетата за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Препълване"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Добавяне обратно към стека"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> от <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ от<xliff:g id="APP_NAME">%2$s</xliff:g> и още <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Преместване горе вляво"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Преместване горе вдясно"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Преместване долу вляво"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Преместване долу вдясно"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Настройки за <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Отхвърляне на балончетата"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Без балончета за разговора"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Чат с балончета"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Новите разговори се показват като плаващи икони, или балончета. Докоснете балонче, за да го отворите, или го плъзнете, за да го преместите."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Управление на балончетата по всяко време"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Докоснете „Управление“, за да изключите балончетата от това приложение"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Няма скорошни балончета"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Скорошните и отхвърлените балончета ще се показват тук"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Балонче"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Управление"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отхвърлено."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings_tv.xml b/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
new file mode 100644
index 000000000000..388eb8477ede
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-bg/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програма без заглавие)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Затваряне на PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Цял екран"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
new file mode 100644
index 000000000000..e92f8c9464de
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"বন্ধ করুন"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"বড় করুন"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"সেটিংস"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"মেনু"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"ছবির-মধ্যে-ছবি তে <xliff:g id="NAME">%s</xliff:g> আছেন"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> কে এই বৈশিষ্ট্যটি ব্যবহার করতে দিতে না চাইলে ট্যাপ করে সেটিংসে গিয়ে সেটি বন্ধ করে দিন।"</string>
+ <string name="pip_play" msgid="3496151081459417097">"চালান"</string>
+ <string name="pip_pause" msgid="690688849510295232">"বিরাম দিন"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"এগিয়ে যাওয়ার জন্য এড়িয়ে যান"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"পিছনে যাওয়ার জন্য এড়িয়ে যান"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"রিসাইজ করুন"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"অ্যাপ্লিকেশান বিভক্ত-স্ক্রিন সমর্থন করে না৷"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"সেকেন্ডারি ডিসপ্লেতে অ্যাপটি কাজ নাও করতে পারে।"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"সেকেন্ডারি ডিসপ্লেতে অ্যাপ লঞ্চ করা যাবে না।"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"বিভক্ত-স্ক্রিন বিভাজক"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"বাঁ দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"৭০% বাকি আছে"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"৫০% বাকি আছে"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"৩০% বাকি আছে"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ডান দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"উপর দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"শীর্ষ ৭০%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ ৫০%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"শীর্ষ ৩০%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"নীচের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> বাবলের জন্য সেটিংস"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ওভারফ্লো"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"স্ট্যাকে আবার যোগ করুন"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> অ্যাপ থেকে <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> অ্যাপ এবং আরও <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>টি থেকে <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"উপরে বাঁদিকে সরান"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"উপরে ডানদিকে সরান"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"নিচে বাঁদিকে সরান"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"নিচে ডান দিকে সরান"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> সেটিংস"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"বাবল খারিজ করুন"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"কথোপকথন বাবল হিসেবে দেখাবে না"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"বাবল ব্যবহার করে চ্যাট করুন"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"নতুন কথোপকথন ভেসে থাকা আইকন বা বাবল হিসেবে দেখানো হয়। বাবল খুলতে ট্যাপ করুন। সেটি সরাতে ধরে টেনে আনুন।"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"যেকোনও সময় বাবল নিয়ন্ত্রণ করুন"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"এই অ্যাপ থেকে বাবল বন্ধ করতে \'ম্যানেজ করুন\' বিকল্প ট্যাপ করুন"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"কোনও সাম্প্রতিক বাবল নেই"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"সাম্প্রতিক ও বাতিল করা বাবল এখানে দেখা যাবে"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"বাবল"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"ম্যানেজ করুন"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"বাবল বাতিল করা হয়েছে।"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings_tv.xml b/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
new file mode 100644
index 000000000000..783cb9275d5b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-bn/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(শিরোনামহীন প্রোগ্রাম)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP বন্ধ করুন"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"পূর্ণ স্ক্রিন"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
new file mode 100644
index 000000000000..938e8b558fdd
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Zatvori"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Proširi"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Postavke"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Meni"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> je u načinu priakza Slika u slici"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ako ne želite da <xliff:g id="NAME">%s</xliff:g> koristi ovu funkciju, dodirnite da otvorite postavke i isključite je."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Reproduciraj"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pauziraj"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Preskoči na sljedeći"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskoči na prethodni"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promjena veličine"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava dijeljenje ekrana."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće raditi na sekundarnom ekranu."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim ekranima."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Razdjelnik ekrana"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lijevo cijeli ekran"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Lijevo 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevo 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Lijevo 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Desno cijeli ekran"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Gore cijeli ekran"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gore 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gore 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gore 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Donji ekran kao cijeli ekran"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Postavke za oblačiće aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Preklapanje"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Dodaj nazad u grupu"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> od aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"Obavještenje <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Pomjeri gore lijevo"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Pomjerite gore desno"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Pomjeri dolje lijevo"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Pomjerite dolje desno"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Postavke aplikacije <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Odbaci oblačić"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nemoj prikazivati razgovor u oblačićima"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatajte koristeći oblačiće"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Novi razgovori se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da otvorite oblačić. Prevucite da ga premjestite."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Upravljajte oblačićima u svakom trenutku"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Dodirnite Upravljaj da isključite oblačiće iz ove aplikacije"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nema nedavnih oblačića"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nedavni i odbačeni oblačići će se pojaviti ovdje"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljaj"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić je odbačen."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings_tv.xml b/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
new file mode 100644
index 000000000000..6845ef46e00c
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-bs/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez naslova)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Zatvori PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Cijeli ekran"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
new file mode 100644
index 000000000000..9cfdc559b4a1
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Tanca"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Desplega"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Configuració"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menú"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> està en pantalla en pantalla"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Si no vols que <xliff:g id="NAME">%s</xliff:g> utilitzi aquesta funció, toca per obrir la configuració i desactiva-la."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Reprodueix"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Posa en pausa"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Ves al següent"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Torna a l\'anterior"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Canvia la mida"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'aplicació no admet la pantalla dividida."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"És possible que l\'aplicació no funcioni en una pantalla secundària."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'aplicació no es pot obrir en pantalles secundàries."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalles"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla esquerra completa"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Pantalla esquerra al 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pantalla esquerra al 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Pantalla esquerra al 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla dreta completa"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Pantalla superior al 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Pantalla superior al 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Pantalla superior al 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Configuració de les bombolles: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menú addicional"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Torna a afegir a la pila"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>) i <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> més"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Mou a dalt a l\'esquerra"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mou a dalt a la dreta"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mou a baix a l\'esquerra"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mou a baix a la dreta"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Configuració de l\'aplicació <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignora la bombolla"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostris la conversa com a bombolla"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Xateja amb bombolles"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Les converses noves es mostren com a icones flotants o bombolles. Toca per obrir una bombolla. Arrossega-la per moure-la."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controla les bombolles en qualsevol moment"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Toca Gestiona per desactivar les bombolles d\'aquesta aplicació"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No hi ha bombolles recents"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Les bombolles recents i les ignorades es mostraran aquí"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bombolla"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestiona"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"La bombolla s\'ha ignorat."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings_tv.xml b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
new file mode 100644
index 000000000000..ba89b0c367d3
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ca/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa sense títol)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Tanca PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
new file mode 100644
index 000000000000..973a5f9b8952
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Zavřít"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Rozbalit"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Nastavení"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Nabídka"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"Aplikace <xliff:g id="NAME">%s</xliff:g> je v režimu obraz v obraze"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Pokud nechcete, aby aplikace <xliff:g id="NAME">%s</xliff:g> tuto funkci používala, klepnutím otevřete nastavení a funkci vypněte."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Přehrát"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pozastavit"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Přeskočit na další"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Přeskočit na předchozí"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Změnit velikost"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikace nepodporuje režim rozdělené obrazovky."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikace na sekundárním displeji nemusí fungovat."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikace nepodporuje spuštění na sekundárních displejích."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Čára rozdělující obrazovku"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Levá část na celou obrazovku"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % vlevo"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % vlevo"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % vlevo"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pravá část na celou obrazovku"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Horní část na celou obrazovku"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % nahoře"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % nahoře"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % nahoře"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Dolní část na celou obrazovku"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Nastavení bublin aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Rozbalovací nabídka"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Přidat zpět do sady"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"Oznámení <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikace <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikace <xliff:g id="APP_NAME">%2$s</xliff:g> a dalších (<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>)"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Přesunout vlevo nahoru"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Přesunout vpravo nahoru"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Přesunout vlevo dolů"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Přesunout vpravo dolů"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Nastavení <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Zavřít bublinu"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nezobrazovat konverzaci v bublinách"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatujte pomocí bublin"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nové konverzace se zobrazují jako plovoucí ikony, neboli bubliny. Klepnutím bublinu otevřete. Přetažením ji posunete."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Nastavení bublin můžete kdykoli upravit"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Bubliny pro tuto aplikaci můžete vypnout klepnutím na Spravovat"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Žádné nedávné bubliny"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Zde se budou zobrazovat nedávné bubliny a zavřené bubliny"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovat"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina byla zavřena."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings_tv.xml b/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
new file mode 100644
index 000000000000..c75ee13692b0
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-cs/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Bez názvu)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Ukončit obraz v obraze (PIP)"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Celá obrazovka"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
new file mode 100644
index 000000000000..cdde84c51658
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Luk"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Udvid"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Indstillinger"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> vises som integreret billede"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Hvis du ikke ønsker, at <xliff:g id="NAME">%s</xliff:g> skal benytte denne funktion, kan du åbne indstillingerne og deaktivere den."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Afspil"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Sæt på pause"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Gå videre til næste"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Gå til forrige"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Rediger størrelse"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen understøtter ikke opdelt skærm."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer muligvis ikke på sekundære skærme."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan ikke åbnes på sekundære skærme."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Adskiller til opdelt skærm"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vis venstre del i fuld skærm"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Venstre 70 %"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Venstre 50 %"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Venstre 30 %"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Vis højre del i fuld skærm"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Vis øverste del i fuld skærm"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Øverste 70 %"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Øverste 50 %"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Øverste 30 %"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Vis nederste del i fuld skærm"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Indstillinger for <xliff:g id="APP_NAME">%1$s</xliff:g>-bobler"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Overløb"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Føj til stak igen"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> andre"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Flyt op til venstre"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Flyt op til højre"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Flyt ned til venstre"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Flyt ned til højre"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Indstillinger for <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Afvis boble"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Vis ikke samtaler i bobler"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat ved hjælp af bobler"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nye samtaler vises som svævende ikoner eller bobler. Tryk for at åbne boblen. Træk for at flytte den."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Styr bobler når som helst"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tryk på Administrer for at deaktivere bobler fra denne app"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ingen seneste bobler"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nye bobler og afviste bobler vises her"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Boble"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen blev lukket."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-da/strings_tv.xml b/libs/WindowManager/Shell/res/values-da/strings_tv.xml
new file mode 100644
index 000000000000..edf10d7c588f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-da/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program uden titel)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Luk integreret billede"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Fuld skærm"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
new file mode 100644
index 000000000000..4979a4015525
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Schließen"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Maximieren"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Einstellungen"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menü"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ist in Bild im Bild"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Wenn du nicht möchtest, dass <xliff:g id="NAME">%s</xliff:g> diese Funktion verwendet, tippe, um die Einstellungen zu öffnen und die Funktion zu deaktivieren."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Wiedergeben"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pausieren"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Vorwärts springen"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Rückwärts springen"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Größe anpassen"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Das Teilen des Bildschirms wird in dieser App nicht unterstützt."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Die App funktioniert auf einem sekundären Display möglicherweise nicht."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Die App unterstützt den Start auf sekundären Displays nicht."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Bildschirmteiler"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vollbild links"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % links"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % links"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % links"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Vollbild rechts"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Vollbild oben"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % oben"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % oben"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % oben"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Vollbild unten"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Einstellungen für <xliff:g id="APP_NAME">%1$s</xliff:g>-Bubbles"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Mehr anzeigen"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Wieder dem Stapel hinzufügen"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> von <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> aus <xliff:g id="APP_NAME">%2$s</xliff:g> und <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> weiteren"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Nach oben links verschieben"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Nach rechts oben verschieben"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Nach unten links verschieben"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Nach unten rechts verschieben"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Einstellungen für <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Bubble schließen"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Unterhaltung nicht als Bubble anzeigen"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Bubbles zum Chatten verwenden"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Neue Unterhaltungen erscheinen als unverankerte Symbole, \"Bubbles\" genannt. Wenn du die Bubble öffnen möchtest, tippe sie an. Wenn du sie verschieben möchtest, zieh an ihr."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Bubble-Einstellungen festlegen"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tippe auf \"Verwalten\", um Bubbles für diese App zu deaktivieren"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Keine kürzlich geschlossenen Bubbles"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Hier werden aktuelle und geschlossene Bubbles angezeigt"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Verwalten"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble verworfen."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-de/strings_tv.xml b/libs/WindowManager/Shell/res/values-de/strings_tv.xml
new file mode 100644
index 000000000000..0432f1c353e4
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-de/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Kein Sendungsname gefunden)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP schließen"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Vollbild"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
new file mode 100644
index 000000000000..2fa31f02e16d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Κλείσιμο"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Ανάπτυξη"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Ρυθμίσεις"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Μενού"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"Η λειτουργία picture-in-picture είναι ενεργή σε <xliff:g id="NAME">%s</xliff:g>."</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Εάν δεν θέλετε να χρησιμοποιείται αυτή η λειτουργία από την εφαρμογή <xliff:g id="NAME">%s</xliff:g>, πατήστε για να ανοίξετε τις ρυθμίσεις και απενεργοποιήστε την."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Αναπαραγωγή"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Παύση"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Μετάβαση στο επόμενο"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Μετάβαση στο προηγούμενο"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Αλλαγή μεγέθους"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Η εφαρμογή δεν υποστηρίζει διαχωρισμό οθόνης."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Η εφαρμογή ίσως να μην λειτουργήσει σε δευτερεύουσα οθόνη."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Η εφαρμογή δεν υποστηρίζει την εκκίνηση σε δευτερεύουσες οθόνες."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Διαχωριστικό οθόνης"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Αριστερή πλήρης οθόνη"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Αριστερή 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Αριστερή 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Αριστερή 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Δεξιά πλήρης οθόνη"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Πάνω πλήρης οθόνη"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Πάνω 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Πάνω 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Πάνω 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Κάτω πλήρης οθόνη"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Ρυθμίσεις για συννεφάκια <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Υπερχείλιση"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Προσθήκη ξανά στη στοίβα"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> από <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> από την εφαρμογή <xliff:g id="APP_NAME">%2$s</xliff:g> και <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ακόμη"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Μετακίνηση επάνω αριστερά"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Μετακίνηση επάνω δεξιά"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Μετακίνηση κάτω αριστερά"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Μετακίνηση κάτω δεξιά"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Ρυθμίσεις <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Παράβλ. για συννεφ."</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Να μην γίνει προβολή της συζήτησης σε συννεφάκια."</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Συζητήστε χρησιμοποιώντας συννεφάκια."</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Οι νέες συζητήσεις εμφανίζονται ως κινούμενα εικονίδια ή συννεφάκια. Πατήστε για να ανοίξετε το συννεφάκι. Σύρετε για να το μετακινήσετε."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Ελέγξτε τα συννεφάκια ανά πάσα στιγμή."</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Πατήστε Διαχείριση για να απενεργοποιήσετε τα συννεφάκια από αυτήν την εφαρμογή."</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Δεν υπάρχουν πρόσφατα συννεφάκια"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Τα πρόσφατα συννεφάκια και τα συννεφάκια που παραβλέψατε θα εμφανίζονται εδώ."</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Συννεφάκι"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Διαχείριση"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Το συννεφάκι παραβλέφθηκε."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings_tv.xml b/libs/WindowManager/Shell/res/values-el/strings_tv.xml
new file mode 100644
index 000000000000..7e4466adb7af
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-el/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Δεν υπάρχει τίτλος προγράμματος)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Κλείσιμο PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Πλήρης οθόνη"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
new file mode 100644
index 000000000000..3a790ec4390e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Close"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Expand"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Settings"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Play"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pause"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Top 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Bottom full screen"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Overflow"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Add back to stack"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Move top left"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Move top right"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Move bottom left"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Move bottom right"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Dismiss bubble"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat using bubbles"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Control bubbles at any time"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tap Manage to turn off bubbles from this app"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No recent bubbles"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recent bubbles and dismissed bubbles will appear here"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
new file mode 100644
index 000000000000..d1d81410d0f6
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
new file mode 100644
index 000000000000..3a790ec4390e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Close"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Expand"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Settings"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Play"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pause"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Top 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Bottom full screen"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Overflow"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Add back to stack"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Move top left"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Move top right"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Move bottom left"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Move bottom right"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Dismiss bubble"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat using bubbles"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Control bubbles at any time"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tap Manage to turn off bubbles from this app"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No recent bubbles"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recent bubbles and dismissed bubbles will appear here"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
new file mode 100644
index 000000000000..d1d81410d0f6
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
new file mode 100644
index 000000000000..3a790ec4390e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Close"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Expand"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Settings"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Play"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pause"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Top 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Bottom full screen"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Overflow"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Add back to stack"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Move top left"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Move top right"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Move bottom left"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Move bottom right"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Dismiss bubble"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat using bubbles"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Control bubbles at any time"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tap Manage to turn off bubbles from this app"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No recent bubbles"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recent bubbles and dismissed bubbles will appear here"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
new file mode 100644
index 000000000000..d1d81410d0f6
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
new file mode 100644
index 000000000000..3a790ec4390e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Close"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Expand"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Settings"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Play"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pause"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Left full screen"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Left 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Top 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Bottom full screen"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Overflow"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Add back to stack"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Move top left"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Move top right"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Move bottom left"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Move bottom right"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Dismiss bubble"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat using bubbles"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Control bubbles at any time"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tap Manage to turn off bubbles from this app"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No recent bubbles"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recent bubbles and dismissed bubbles will appear here"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Manage"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubble dismissed."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
new file mode 100644
index 000000000000..d1d81410d0f6
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(No title program)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Close PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
new file mode 100644
index 000000000000..d8b5b40035f7
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -0,0 +1,72 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎Close‎‏‎‎‏‎"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‏‎‎‎‏‎‏‏‏‎‏‎‎‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‎‎‎Expand‎‏‎‎‏‎"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‎Settings‎‏‎‎‏‎"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎‎‎‎Menu‎‏‎‎‏‎"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ is in picture-in-picture‎‏‎‎‏‎"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎If you don\'t want ‎‏‎‎‏‏‎<xliff:g id="NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ to use this feature, tap to open settings and turn it off.‎‏‎‎‏‎"</string>
+ <string name="pip_play" msgid="3496151081459417097">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‎‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‏‎‎‏‎Play‎‏‎‎‏‎"</string>
+ <string name="pip_pause" msgid="690688849510295232">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‏‎‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‏‏‎‎‎‎‎‎‎Pause‎‏‎‎‏‎"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎Skip to next‎‏‎‎‏‎"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎Skip to previous‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎Resize‎‏‎‎‏‎"</string>
+ <string name="dock_forced_resizable" msgid="1749750436092293116">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎App may not work with split-screen.‎‏‎‎‏‎"</string>
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎‏‎App does not support split-screen.‎‏‎‎‏‎"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎App may not work on a secondary display.‎‏‎‎‏‎"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‎App does not support launch on secondary displays.‎‏‎‎‏‎"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎‏‏‏‎Split-screen divider‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‏‏‎‎‏‏‎‎‎‎Left full screen‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎Left 70%‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎Left 50%‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‏‏‎Left 30%‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‎‎‏‎‎‎‏‏‏‎Right full screen‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎‏‎‏‎‎Top full screen‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‎‎‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‎Top 70%‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‎Top 50%‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎Top 30%‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎Bottom full screen‎‏‎‎‏‎"</string>
+ <string name="one_handed_tutorial_title" msgid="4583241688067426350">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‎‎‎‎‎‏‎‏‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‎‎Using one-handed mode‎‏‎‎‏‎"</string>
+ <string name="one_handed_tutorial_description" msgid="3486582858591353067">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‎‎‎‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‏‎‏‏‎To exit, swipe up from the bottom of the screen or tap anywhere above the app‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‎‎Start one-handed mode‎‏‎‎‏‎"</string>
+ <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‏‏‎‏‎‎‎‏‏‏‎‏‎‏‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‎‎Exit one-handed mode‎‏‎‎‏‎"</string>
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‎‎‎Settings for ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ bubbles‎‏‎‎‏‎"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‎‎‎‎‏‎‏‏‎‏‎‏‎‎‏‏‎‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎Overflow‎‏‎‎‏‎"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎‏‎‏‏‎‎‏‎Add back to stack‎‏‎‎‏‎"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ from ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ from ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>‎‏‎‎‏‏‏‎ more‎‏‎‎‏‎"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‎Move top left‎‏‎‎‏‎"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‏‎Move top right‎‏‎‎‏‎"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‎‎Move bottom left‎‏‎‎‏‎"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎Move bottom right‎‏‎‎‏‎"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ settings‎‏‎‎‏‎"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‏‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‎‏‎‏‎‏‎‎‎‏‏‏‎‎Dismiss bubble‎‏‎‎‏‎"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎Don’t bubble conversation‎‏‎‎‏‎"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎Chat using bubbles‎‏‎‎‏‎"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‏‎New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it.‎‏‎‎‏‎"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎Control bubbles anytime‎‏‎‎‏‎"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‎‎Tap Manage to turn off bubbles from this app‎‏‎‎‏‎"</string>
+ <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‎Got it‎‏‎‎‏‎"</string>
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‎No recent bubbles‎‏‎‎‏‎"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎Recent bubbles and dismissed bubbles will appear here‎‏‎‎‏‎"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‎‎‎‎‏‎‎Bubble‎‏‎‎‏‎"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎Manage‎‏‎‎‏‎"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‏‎Bubble dismissed.‎‏‎‎‏‎"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
new file mode 100644
index 000000000000..3f9ef0ea2816
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings_tv.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="2576686079160402435">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‏‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‏‏‎Picture-in-Picture‎‏‎‎‏‎"</string>
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎(No title program)‎‏‎‎‏‎"</string>
+ <string name="pip_close" msgid="9135220303720555525">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎Close PIP‎‏‎‎‏‎"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎Full screen‎‏‎‎‏‎"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
new file mode 100644
index 000000000000..2cac751144a9
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Cerrar"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Expandir"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Configuración"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menú"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> está en modo de Pantalla en pantalla"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Si no quieres que <xliff:g id="NAME">%s</xliff:g> use esta función, presiona para abrir la configuración y desactivarla."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Reproducir"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pausar"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Siguiente"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Anterior"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar el tamaño"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La app no es compatible con la función de pantalla dividida."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la app no funcione en una pantalla secundaria."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"La app no puede iniciarse en pantallas secundarias."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalla dividida"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla izquierda completa"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Izquierda: 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda: 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Izquierda: 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla derecha completa"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Superior: 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior: 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Superior: 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Configuración para burbujas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menú ampliado"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Volver a agregar a la pila"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> y <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> más"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Ubicar arriba a la izquierda"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Ubicar arriba a la derecha"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Ubicar abajo a la izquierda"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Ubicar abajo a la derecha"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Configuración de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Descartar burbuja"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostrar la conversación en burbujas"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat con burbujas"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Las conversaciones nuevas aparecen como elementos flotantes o burbujas. Presiona para abrir la burbuja. Arrástrala para moverla."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controla las burbujas"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Presiona Administrar para desactivar las burbujas de esta app"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No hay burbujas recientes"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Las burbujas recientes y las que se descartaron aparecerán aquí"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Cuadro"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Administrar"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Se descartó el cuadro."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
new file mode 100644
index 000000000000..b275b6ceb742
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Sin título de programa)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Cerrar PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
new file mode 100644
index 000000000000..7b5045a0e979
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Cerrar"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Mostrar"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Ajustes"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menú"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> está en imagen en imagen"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Si no quieres que <xliff:g id="NAME">%s</xliff:g> utilice esta función, toca la notificación para abrir los ajustes y desactivarla."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Reproducir"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pausar"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Saltar al siguiente"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Volver al anterior"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar tamaño"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La aplicación no admite la pantalla dividida."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la aplicación no funcione en una pantalla secundaria."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"La aplicación no se puede abrir en pantallas secundarias."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Dividir la pantalla"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla izquierda completa"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Izquierda 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Izquierda 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla derecha completa"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Superior 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Superior 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla inferior completa"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Ajustes de las burbujas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menú adicional"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Volver a añadir a la pila"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> y <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> más"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Mover arriba a la izquierda"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mover arriba a la derecha"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mover abajo a la izquierda."</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mover abajo a la derecha"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Ajustes de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Cerrar burbuja"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostrar conversación en burbuja"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatea con burbujas"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Las conversaciones nuevas aparecen como iconos flotantes llamadas \"burbujas\". Toca para abrir la burbuja. Arrastra para moverla."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controla las burbujas"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Toca Gestionar para desactivar las burbujas de esta aplicación"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No hay burbujas recientes"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Las burbujas recientes y las cerradas aparecerán aquí"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Burbuja"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionar"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbuja cerrada."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-es/strings_tv.xml b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
new file mode 100644
index 000000000000..6a6ad13f2f3d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-es/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa sin título)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Cerrar PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
new file mode 100644
index 000000000000..2a261dbd2ef6
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Sule"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Laiendamine"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Seaded"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menüü"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> on režiimis Pilt pildis"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Kui te ei soovi, et rakendus <xliff:g id="NAME">%s</xliff:g> seda funktsiooni kasutaks, puudutage seadete avamiseks ja lülitage see välja."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Esita"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Peata"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Järgmise juurde"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Eelmise juurde"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Suuruse muutmine"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Rakendus ei toeta jagatud ekraani."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Rakendus ei pruugi teisesel ekraanil töötada."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Rakendus ei toeta teisestel ekraanidel käivitamist."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Ekraanijagaja"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vasak täisekraan"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vasak: 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasak: 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vasak: 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Parem täisekraan"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ülemine täisekraan"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Ülemine: 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ülemine: 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Ülemine: 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Alumine täisekraan"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> mullide seaded"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Ületäide"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Lisa tagasi virna"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> rakendusest <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> rakenduselt <xliff:g id="APP_NAME">%2$s</xliff:g> ja veel <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Teisalda üles vasakule"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Teisalda üles paremale"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Teisalda alla vasakule"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Teisalda alla paremale"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Rakenduse <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> seaded"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Sule mull"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ära kuva vestlust mullina"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Vestelge mullide abil"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Uued vestlused kuvatakse hõljuvate ikoonidena ehk mullidena. Puudutage mulli avamiseks. Lohistage mulli, et seda liigutada."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Juhtige mulle igal ajal"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Selle rakenduse puhul mullide väljalülitamiseks puudutage valikut Halda"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Hiljutisi mulle pole"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Siin kuvatakse hiljutised ja suletud mullid."</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Mull"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Halda"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Mullist loobuti."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-et/strings_tv.xml b/libs/WindowManager/Shell/res/values-et/strings_tv.xml
new file mode 100644
index 000000000000..26cfae2c194f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-et/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programmi pealkiri puudub)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Sule PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Täisekraan"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
new file mode 100644
index 000000000000..9167e8e9e3f4
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Itxi"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Zabaldu"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Ezarpenak"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menua"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"Pantaila txiki gainjarrian dago <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ez baduzu nahi <xliff:g id="NAME">%s</xliff:g> zerbitzuak eginbide hori erabiltzea, sakatu hau ezarpenak ireki eta aukera desaktibatzeko."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Erreproduzitu"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pausatu"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Saltatu hurrengora"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Saltatu aurrekora"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Aldatu tamaina"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikazioak ez du onartzen pantaila zatitua"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Baliteke aplikazioak ez funtzionatzea bigarren mailako pantailetan."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikazioa ezin da abiarazi bigarren mailako pantailatan."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Pantaila-zatitzailea"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ezarri ezkerraldea pantaila osoan"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ezarri ezkerraldea % 70en"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ezarri ezkerraldea % 50en"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ezarri ezkerraldea % 30en"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ezarri eskuinaldea pantaila osoan"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ezarri goialdea pantaila osoan"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Ezarri goialdea % 70en"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ezarri goialdea % 50en"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Ezarri goialdea % 30en"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ezarri behealdea pantaila osoan"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren ezarpenen burbuilak"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Gainezkatzea"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Gehitu berriro errenkadan"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioaren \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" jakinarazpena, eta beste <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Eraman goialdera, ezkerretara"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Eraman goialdera, eskuinetara"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Eraman behealdera, ezkerretara"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Eraman behealdera, eskuinetara"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> aplikazioaren ezarpenak"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Baztertu burbuila"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ez erakutsi elkarrizketak burbuila gisa"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Txateatu burbuilen bidez"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Elkarrizketa berriak ikono gainerakor edo burbuila gisa agertzen dira. Sakatu burbuila irekitzeko. Arrasta ezazu mugitzeko."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Kontrolatu burbuilak edonoiz"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Aplikazioaren burbuilak desaktibatzeko, sakatu Kudeatu"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ez dago azkenaldiko burbuilarik"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Azken burbuilak eta baztertutakoak agertuko dira hemen"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Burbuila"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Kudeatu"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Baztertu da globoa."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings_tv.xml b/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
new file mode 100644
index 000000000000..985677fd3604
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-eu/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa izengabea)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Itxi PIPa"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Pantaila osoa"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
new file mode 100644
index 000000000000..3f566bf8ea0d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"بستن"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"بزرگ کردن"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"تنظیمات"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"منو"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> درحالت تصویر در تصویر است"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"اگر نمی‌خواهید <xliff:g id="NAME">%s</xliff:g> از این قابلیت استفاده کند، با ضربه زدن، تنظیمات را باز کنید و آن را خاموش کنید."</string>
+ <string name="pip_play" msgid="3496151081459417097">"پخش"</string>
+ <string name="pip_pause" msgid="690688849510295232">"توقف موقت"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"رد شدن به بعدی"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"رد شدن به قبلی"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"تغییر اندازه"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"برنامه از تقسیم صفحه پشتیبانی نمی‌کند."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن است برنامه در نمایشگر ثانویه کار نکند."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"برنامه از راه‌اندازی در نمایشگرهای ثانویه پشتیبانی نمی‌کند."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"تقسیم‌کننده صفحه"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"تمام‌صفحه چپ"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"٪۷۰ چپ"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"٪۵۰ چپ"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"٪۳۰ چپ"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"تمام‌صفحه راست"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"تمام‌صفحه بالا"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"٪۷۰ بالا"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"٪۵۰ بالا"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"٪۳۰ بالا"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"تمام‌صفحه پایین"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"تنظیمات برای حبابک‌های <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"لبریزشده"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"افزودن برگشت به پشته"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g> و <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> مورد بیشتر"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"انتقال به بالا سمت راست"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"انتقال به بالا سمت چپ"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"انتقال به پایین سمت راست"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"انتقال به پایین سمت چپ"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"تنظیمات <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"رد کردن حبابک"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"مکالمه در حباب نشان داده نشود"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"گپ بااستفاده از حبابک‌ها"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"مکالمه‌های جدید به‌صورت نمادهای شناور یا حبابک‌ها نشان داده می‌شوند. برای باز کردن حبابک‌ها ضربه بزنید. برای جابه‌جایی، آن را بکشید."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"کنترل حبابک‌ها در هرزمانی"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"برای خاموش کردن «حبابک‌ها» از این برنامه، روی «مدیریت» ضربه بزنید"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"هیچ حبابک جدیدی وجود ندارد"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"حبابک‌ها اخیر و حبابک‌ها ردشده اینجا ظاهر خواهند شد"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"حباب"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"مدیریت"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"حبابک رد شد."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings_tv.xml b/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
new file mode 100644
index 000000000000..c17dc33ea69b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-fa/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(برنامه بدون عنوان)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"‏بستن PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"تمام صفحه"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
new file mode 100644
index 000000000000..0aa4b4024149
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Sulje"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Laajenna"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Asetukset"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Valikko"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> on kuva kuvassa ‑tilassa"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Jos et halua, että <xliff:g id="NAME">%s</xliff:g> voi käyttää tätä ominaisuutta, avaa asetukset napauttamalla ja poista se käytöstä."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Toista"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Keskeytä"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Siirry seuraavaan"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Siirry edelliseen"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Muuta kokoa"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Sovellus ei tue jaetun näytön tilaa."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Sovellus ei ehkä toimi toissijaisella näytöllä."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Sovellus ei tue käynnistämistä toissijaisilla näytöillä."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Näytön jakaja"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vasen koko näytölle"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vasen 70 %"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasen 50 %"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vasen 30 %"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Oikea koko näytölle"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Yläosa koko näytölle"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Yläosa 70 %"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yläosa 50 %"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Yläosa 30 %"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Alaosa koko näytölle"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Kuplien asetukset: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Ylivuoto"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Lisää takaisin pinoon"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g>: <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>) ja <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> muuta"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Siirrä vasempaan yläreunaan"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Siirrä oikeaan yläreunaan"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Siirrä vasempaan alareunaan"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Siirrä oikeaan alareunaan"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: asetukset"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ohita kupla"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Älä näytä kuplia keskusteluista"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chattaile kuplien avulla"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Uudet keskustelut näkyvät kelluvina kuvakkeina tai kuplina. Avaa kupla napauttamalla. Siirrä sitä vetämällä."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Muuta kuplien asetuksia milloin tahansa"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Valitse Ylläpidä, jos haluat poistaa kuplat käytöstä tästä sovelluksesta"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ei viimeaikaisia kuplia"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Viimeaikaiset ja äskettäin ohitetut kuplat näkyvät täällä"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Kupla"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Ylläpidä"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Kupla ohitettu."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings_tv.xml b/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
new file mode 100644
index 000000000000..55c168055af5
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-fi/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Nimetön)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Sulje PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Koko näyttö"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
new file mode 100644
index 000000000000..6a505933a208
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Fermer"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Développer"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Paramètres"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> est en mode d\'incrustation d\'image"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Si vous ne voulez pas que <xliff:g id="NAME">%s</xliff:g> utilise cette fonctionnalité, touchez l\'écran pour ouvrir les paramètres, puis désactivez-la."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Lire"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Interrompre"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Passer au suivant"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Revenir au précédent"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionner"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'application n\'est pas compatible avec l\'écran partagé."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'application ne peut pas être lancée sur des écrans secondaires."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Séparateur d\'écran partagé"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Plein écran à la gauche"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % à la gauche"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % à la gauche"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % à la gauche"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Plein écran à la droite"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Plein écran dans le haut"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % dans le haut"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % dans le haut"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % dans le haut"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Plein écran dans le bas"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Paramètres pour les bulles de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menu déroulant"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Replacer sur la pile"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> et <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> autres"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Déplacer dans coin sup. gauche"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Déplacer dans coin sup. droit"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Déplacer dans coin inf. gauche"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Déplacer dans coin inf. droit"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Paramètres <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignorer la bulle"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne pas afficher les conversations dans des bulles"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Clavarder en utilisant des bulles"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes (de bulles). Touchez une bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Paramètres des bulles"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Toucher Gérer pour désactiver les bulles de cette application"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Aucune bulle récente"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Les bulles récentes et les bulles ignorées s\'afficheront ici"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle ignorée."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
new file mode 100644
index 000000000000..5f813e6c3101
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Aucun programme de titre)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Fermer mode IDI"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Plein écran"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
new file mode 100644
index 000000000000..fd6e743b007f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Fermer"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Développer"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Paramètres"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> est en mode Picture-in-picture"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Si vous ne voulez pas que l\'application <xliff:g id="NAME">%s</xliff:g> utilise cette fonctionnalité, appuyez ici pour ouvrir les paramètres et la désactiver."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Lecture"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Suspendre"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Passer au contenu suivant"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Passer au contenu précédent"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionner"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Application incompatible avec l\'écran partagé."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'application ne peut pas être lancée sur des écrans secondaires."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Séparateur d\'écran partagé"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Écran de gauche en plein écran"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Écran de gauche à 70 %"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Écran de gauche à 50 %"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Écran de gauche à 30 %"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Écran de droite en plein écran"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Écran du haut en plein écran"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Écran du haut à 70 %"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Écran du haut à 50 %"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Écran du haut à 30 %"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Écran du bas en plein écran"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Paramètres des bulles de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Dépassement"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Ajouter à nouveau l\'élément à la pile"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de l\'application <xliff:g id="APP_NAME">%2$s</xliff:g> et <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> autres"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Déplacer en haut à gauche"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Déplacer en haut à droite"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Déplacer en bas à gauche"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Déplacer en bas à droite"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Paramètres <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Fermer la bulle"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne pas afficher la conversation dans une bulle"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatter en utilisant des bulles"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes ou bulles. Appuyez sur la bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Contrôler les paramètres des bulles"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Appuyez sur \"Gérer\" pour désactiver les bulles de cette application"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Aucune bulle récente"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Les bulles récentes et ignorées s\'afficheront ici"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle fermée."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings_tv.xml b/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
new file mode 100644
index 000000000000..52d942dcf412
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-fr/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programme sans titre)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Fermer mode PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Plein écran"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
new file mode 100644
index 000000000000..057881be0be3
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Pechar"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Despregar"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Configuración"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menú"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> está na pantalla superposta"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Se non queres que <xliff:g id="NAME">%s</xliff:g> utilice esta función, toca a configuración para abrir as opcións e desactivar a función."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Reproducir"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pausar"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Ir ao seguinte"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Ir ao anterior"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar tamaño"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A aplicación non é compatible coa función de pantalla dividida."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É posible que a aplicación non funcione nunha pantalla secundaria."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"A aplicación non se pode iniciar en pantallas secundarias."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalla dividida"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Pantalla completa á esquerda"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70 % á esquerda"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % á esquerda"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % á esquerda"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla completa á dereita"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla completa arriba"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % arriba"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % arriba"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30 % arriba"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pantalla completa abaixo"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Configuración das burbullas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Mostrar menú adicional"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Engadir de novo á pilla"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> e <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> máis"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Mover á parte super. esquerda"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mover á parte superior dereita"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mover á parte infer. esquerda"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mover á parte inferior dereita"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Configuración de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignorar burbulla"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Non mostrar a conversa como burbulla"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatear usando burbullas"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"As conversas novas aparecen como iconas flotantes ou burbullas. Toca para abrir a burbulla e arrastra para movela."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controla as burbullas"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Para desactivar as burbullas nesta aplicación, toca Xestionar"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Non hai burbullas recentes"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"As burbullas recentes e ignoradas aparecerán aquí."</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Burbulla"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Xestionar"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ignorouse a burbulla."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings_tv.xml b/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
new file mode 100644
index 000000000000..a896d88ee8e5
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-gl/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa sen título)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Pechar PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Pantalla completa"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
new file mode 100644
index 000000000000..d9950aa651b2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"બંધ કરો"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"વિસ્તૃત કરો"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"સેટિંગ"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"મેનૂ"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ચિત્રમાં-ચિત્રની અંદર છે"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"જો તમે નથી ઇચ્છતા કે <xliff:g id="NAME">%s</xliff:g> આ સુવિધાનો ઉપયોગ કરે, તો સેટિંગ ખોલવા માટે ટૅપ કરો અને તેને બંધ કરો."</string>
+ <string name="pip_play" msgid="3496151081459417097">"ચલાવો"</string>
+ <string name="pip_pause" msgid="690688849510295232">"થોભાવો"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"આગલા પર જાઓ"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"પહેલાંના પર જાઓ"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"કદ બદલો"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ઍપ્લિકેશન સ્ક્રીન-વિભાજનનું સમર્થન કરતી નથી."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર કદાચ કામ ન કરે."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર લૉન્ચનું સમર્થન કરતી નથી."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"સ્પ્લિટ-સ્ક્રીન વિભાજક"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ડાબી પૂર્ણ સ્ક્રીન"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ડાબે 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ડાબે 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ડાબે 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"જમણી સ્ક્રીન સ્ક્રીન"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"શીર્ષ પૂર્ણ સ્ક્રીન"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"શીર્ષ 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"શીર્ષ 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"શીર્ષ 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"તળિયાની પૂર્ણ સ્ક્રીન"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> બબલ માટેનાં સેટિંગ"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ઓવરફ્લો"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"સ્ટૅકમાં ફરી ઉમેરો"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> તરફથી <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> અને વધુ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> તરફથી <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ઉપર ડાબે ખસેડો"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ઉપર જમણે ખસેડો"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"નીચે ડાબે ખસેડો"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"નીચે જમણે ખસેડો"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> સેટિંગ"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"બબલને છોડી દો"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"વાતચીતને બબલ કરશો નહીં"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"બબલનો ઉપયોગ કરીને ચેટ કરો"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"નવી વાતચીત ફ્લોટિંગ આઇકન અથવા બબલ જેવી દેખાશે. બબલને ખોલવા માટે ટૅપ કરો. તેને ખસેડવા માટે ખેંચો."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"બબલને કોઈપણ સમયે નિયંત્રિત કરો"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"આ ઍપમાંથી બબલને બંધ કરવા માટે મેનેજ કરો પર ટૅપ કરો"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"તાજેતરના કોઈ બબલ નથી"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"એકદમ નવા બબલ અને છોડી દીધેલા બબલ અહીં દેખાશે"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"બબલ"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"મેનેજ કરો"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"બબલ છોડી દેવાયો."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings_tv.xml b/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
new file mode 100644
index 000000000000..a5c0c311a16b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-gu/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(કોઈ ટાઇટલ પ્રોગ્રામ નથી)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP બંધ કરો"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"પૂર્ણ સ્ક્રીન"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
new file mode 100644
index 000000000000..b1117bde08f5
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"बंद करें"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"विस्तार करें"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"सेटिंग"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"मेन्यू"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> \"पिक्चर में पिक्चर\" के अंदर है"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"अगर आप नहीं चाहते कि <xliff:g id="NAME">%s</xliff:g> इस सुविधा का उपयोग करे, तो सेटिंग खोलने के लिए टैप करें और उसे बंद करें ."</string>
+ <string name="pip_play" msgid="3496151081459417097">"चलाएं"</string>
+ <string name="pip_pause" msgid="690688849510295232">"रोकें"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"अगले पर जाएं"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"पिछले पर जाएं"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदलें"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ऐप विभाजित स्‍क्रीन का समर्थन नहीं करता है."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"हो सकता है कि ऐप प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर काम न करे."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर ऐप लॉन्च नहीं किया जा सकता."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"विभाजित स्क्रीन विभाजक"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"बाईं स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"बाईं स्क्रीन को 70% बनाएं"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बाईं स्क्रीन को 50% बनाएं"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"बाईं स्क्रीन को 30% बनाएं"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"दाईं स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ऊपर की स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ऊपर की स्क्रीन को 70% बनाएं"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ऊपर की स्क्रीन को 50% बनाएं"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ऊपर की स्क्रीन को 30% बनाएं"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"नीचे की स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> बबल्स की सेटिंग"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ओवरफ़्लो"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"स्टैक में वापस जोड़ें"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> से <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> और <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> अन्य ऐप्लिकेशन से <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"सबसे ऊपर बाईं ओर ले जाएं"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"सबसे ऊपर दाईं ओर ले जाएं"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"बाईं ओर सबसे नीचे ले जाएं"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"सबसे नीचे दाईं ओर ले जाएं"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> की सेटिंग"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"बबल खारिज करें"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"बातचीत को बबल न करें"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"बबल्स का इस्तेमाल करके चैट करें"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"नई बातचीत फ़्लोटिंग आइकॉन या बबल्स की तरह दिखेंगी. बबल को खोलने के लिए टैप करें. इसे एक जगह से दूसरी जगह ले जाने के लिए खींचें और छोड़ें."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"जब चाहें, बबल्स को कंट्रोल करें"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"इस ऐप्लिकेशन पर बबल्स को बंद करने के लिए \'प्रबंधित करें\' पर टैप करें"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"हाल ही के बबल्स मौजूद नहीं हैं"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"हाल ही के बबल्स और हटाए गए बबल्स यहां दिखेंगे"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"प्रबंधित करें"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल खारिज किया गया."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings_tv.xml b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
new file mode 100644
index 000000000000..c2131ebd1874
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-hi/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(कोई शीर्षक कार्यक्रम नहीं)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP बंद करें"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"फ़ुल स्‍क्रीन"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
new file mode 100644
index 000000000000..0f617f3601f2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Zatvori"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Proširivanje"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Postavke"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Izbornik"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> jest na slici u slici"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ako ne želite da aplikacija <xliff:g id="NAME">%s</xliff:g> upotrebljava tu značajku, dodirnite da biste otvorili postavke i isključili je."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Reproduciraj"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pauziraj"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Preskoči na sljedeće"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskoči na prethodno"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promjena veličine"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podijeljeni zaslon."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionirati na sekundarnom zaslonu."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim zaslonima."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Razdjelnik podijeljenog zaslona"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lijevi zaslon u cijeli zaslon"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Lijevi zaslon na 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevi zaslon na 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Lijevi zaslon na 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Desni zaslon u cijeli zaslon"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Gornji zaslon u cijeli zaslon"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gornji zaslon na 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gornji zaslon na 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gornji zaslon na 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Donji zaslon u cijeli zaslon"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Postavke za oblačiće za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Dodatno"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Dodajte natrag u nizove"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Premjesti u gornji lijevi kut"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Premjesti u gornji desni kut"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Premjesti u donji lijevi kut"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Premjestite u donji desni kut"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Postavke za <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Odbaci oblačić"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Zaustavi razgovor u oblačićima"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Oblačići u chatu"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Novi razgovori pojavljuju se kao pomične ikone ili oblačići. Dodirnite za otvaranje oblačića. Povucite da biste ga premjestili."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Upravljanje oblačićima u svakom trenutku"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Dodirnite Upravljanje da biste isključili oblačiće iz ove aplikacije"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nema nedavnih oblačića"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Ovdje će se prikazivati nedavni i odbačeni oblačići"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljanje"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblačić odbačen."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings_tv.xml b/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
new file mode 100644
index 000000000000..76994a50c405
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-hr/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez naslova)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Zatvori PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Cijeli zaslon"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
new file mode 100644
index 000000000000..1fd87e6ce8b2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Bezárás"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Kibontás"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Beállítások"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menü"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"A(z) <xliff:g id="NAME">%s</xliff:g> kép a képben funkciót használ"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ha nem szeretné, hogy a(z) <xliff:g id="NAME">%s</xliff:g> használja ezt a funkciót, koppintson a beállítások megnyitásához, és kapcsolja ki."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Lejátszás"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Szüneteltetés"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Ugrás a következőre"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Ugrás az előzőre"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Átméretezés"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Az alkalmazás nem támogatja az osztott képernyős nézetet."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Előfordulhat, hogy az alkalmazás nem működik másodlagos kijelzőn."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Az alkalmazást nem lehet másodlagos kijelzőn elindítani."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Elválasztó az osztott nézetben"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Bal oldali teljes képernyőre"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Bal oldali 70%-ra"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Bal oldali 50%-ra"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Bal oldali 30%-ra"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Jobb oldali teljes képernyőre"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Felső teljes képernyőre"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Felső 70%-ra"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Felső 50%-ra"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Felső 30%-ra"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Alsó teljes képernyőre"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g>-buborékok beállításai"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"További elemeket tartalmazó menü"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Visszaküldés a verembe"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> a(z) <xliff:g id="APP_NAME">%2$s</xliff:g> alkalmazásból és <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> további"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Áthelyezés fel és balra"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Áthelyezés fel és jobbra"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Áthelyezés le és balra"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Áthelyezés le és jobbra"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> beállításai"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Buborék elvetése"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne jelenjen meg a beszélgetés buborékban"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Buborékokat használó csevegés"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Az új beszélgetések lebegő ikonként, vagyis buborékként jelennek meg. A buborék megnyitásához koppintson rá. Áthelyezéshez húzza a kívánt helyre."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Buborékok vezérlése bármikor"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"A Kezelés gombra koppintva kapcsolhatja ki az alkalmazásból származó buborékokat"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nincsenek buborékok a közelmúltból"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"A legutóbbi és az elvetett buborékok itt jelennek majd meg"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Buborék"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Kezelés"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Buborék elvetve."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings_tv.xml b/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
new file mode 100644
index 000000000000..5254ccc08bc4
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-hu/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Cím nélküli program)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP bezárása"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Teljes képernyő"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
new file mode 100644
index 000000000000..c3749278e54d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Փակել"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Ընդարձակել"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Կարգավորումներ"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Ընտրացանկ"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g>-ը «Նկար նկարի մեջ» ռեժիմում է"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Եթե չեք ցանկանում, որ <xliff:g id="NAME">%s</xliff:g>-ն օգտագործի այս գործառույթը, հպեք՝ կարգավորումները բացելու և այն անջատելու համար։"</string>
+ <string name="pip_play" msgid="3496151081459417097">"Նվագարկել"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Դադարեցնել"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Անցնել հաջորդին"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Վերադառնալ նախորդին"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Փոխել չափը"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Հավելվածը չի աջակցում էկրանի տրոհումը:"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Հավելվածը կարող է չաշխատել լրացուցիչ էկրանի վրա"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Հավելվածը չի աջակցում գործարկումը լրացուցիչ էկրանների վրա"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Տրոհված էկրանի բաժանիչ"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ձախ էկրանը՝ լիաէկրան"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ձախ էկրանը՝ 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ձախ էկրանը՝ 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ձախ էկրանը՝ 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Աջ էկրանը՝ լիաէկրան"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Վերևի էկրանը՝ լիաէկրան"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Վերևի էկրանը՝ 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Վերևի էկրանը՝ 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Վերևի էկրանը՝ 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ներքևի էկրանը՝ լիաէկրան"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ի ամպիկների կարգավորումներ"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Լրացուցիչ ընտրացանկ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Նորից ավելացնել զտիչներում"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>՝ <xliff:g id="APP_NAME">%2$s</xliff:g>-ից"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>` <xliff:g id="APP_NAME">%2$s</xliff:g>-ից ու ևս <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ամպիկ"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Տեղափոխել վերև՝ ձախ"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Տեղափոխել վերև՝ աջ"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Տեղափոխել ներքև՝ ձախ"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Տեղափոխել ներքև՝ աջ"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – կարգավորումներ"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Փակել ամպիկը"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Զրույցը չցուցադրել ամպիկի տեսքով"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Զրույցի ամպիկներ"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Նոր զրույցները կհայտնվեն լողացող պատկերակների կամ ամպիկների տեսքով։ Հպեք՝ ամպիկը բացելու համար։ Քաշեք՝ այն տեղափոխելու համար։"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Ամպիկների կարգավորումներ"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Հպեք «Կառավարել» կոճակին՝ այս հավելվածի ամպիկներն անջատելու համար։"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ամպիկներ չկան"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Այստեղ կցուցադրվեն վերջերս օգտագործված և փակված ամպիկները, որոնք կկարողանաք հեշտությամբ վերաբացել"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Պղպջակ"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Կառավարել"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ամպիկը փակվեց։"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings_tv.xml b/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
new file mode 100644
index 000000000000..36680e94def0
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-hy/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Առանց վերնագրի ծրագիր)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Փակել PIP-ն"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Լիէկրան"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
new file mode 100644
index 000000000000..2cb26b467d98
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Tutup"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Luaskan"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Setelan"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> adalah picture-in-picture"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Jika Anda tidak ingin <xliff:g id="NAME">%s</xliff:g> menggunakan fitur ini, ketuk untuk membuka setelan dan menonaktifkannya."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Putar"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Jeda"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Lewati ke berikutnya"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Lewati ke sebelumnya"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ubah ukuran"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App tidak mendukung layar terpisah."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikasi mungkin tidak berfungsi pada layar sekunder."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikasi tidak mendukung peluncuran pada layar sekunder."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Pembagi layar terpisah"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Layar penuh di kiri"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kiri 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kiri 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kiri 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Layar penuh di kanan"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Layar penuh di atas"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Atas 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Atas 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Atas 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Layar penuh di bawah"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Setelan untuk balon <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Tambahan"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Tambahkan kembali ke stack"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> dari <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> dari <xliff:g id="APP_NAME">%2$s</xliff:g> dan <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> lainnya"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Pindahkan ke kiri atas"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Pindahkan ke kanan atas"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Pindahkan ke kiri bawah"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Pindahkan ke kanan bawah"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Setelan <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Tutup balon"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Jangan gunakan percakapan balon"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat dalam tampilan balon"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Percakapan baru muncul sebagai ikon mengambang, atau balon. Ketuk untuk membuka balon. Tarik untuk memindahkannya."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Kontrol balon kapan saja"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Ketuk Kelola untuk menonaktifkan balon dari aplikasi ini"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Tidak ada balon baru-baru ini"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Balon yang baru dipakai dan balon yang telah ditutup akan muncul di sini"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Kelola"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balon ditutup."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-in/strings_tv.xml b/libs/WindowManager/Shell/res/values-in/strings_tv.xml
new file mode 100644
index 000000000000..30544b573d5d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-in/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program tanpa judul)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Tutup PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Layar penuh"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
new file mode 100644
index 000000000000..3b749bd2aca0
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Loka"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Stækka"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Stillingar"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Valmynd"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> er með mynd í mynd"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ef þú vilt ekki að <xliff:g id="NAME">%s</xliff:g> noti þennan eiginleika skaltu ýta til að opna stillingarnar og slökkva á því."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Spila"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Gera hlé"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Fara á næsta"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Fara á fyrra"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Breyta stærð"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Forritið styður ekki að skjánum sé skipt."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Hugsanlegt er að forritið virki ekki á öðrum skjá."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Forrit styður ekki opnun á öðrum skjá."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Skjáskipting"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Vinstri á öllum skjánum"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vinstri 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vinstri 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vinstri 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Hægri á öllum skjánum"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Efri á öllum skjánum"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Efri 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Efri 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Efri 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Neðri á öllum skjánum"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Stillingar fyrir blöðrur frá <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Yfirflæði"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Bæta aftur í stafla"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> frá <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ frá <xliff:g id="APP_NAME">%2$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> í viðbót"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Færa efst til vinstri"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Færa efst til hægri"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Færa neðst til vinstri"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Færðu neðst til hægri"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Stillingar <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Loka blöðru"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ekki setja samtal í blöðru"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Spjalla með blöðrum"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Ný samtöl birtast sem fljótandi tákn eða blöðrur. Ýttu til að opna blöðru. Dragðu hana til að færa."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Hægt er að stjórna blöðrum hvenær sem er"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Ýttu á „Stjórna“ til að slökkva á blöðrum frá þessu forriti"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Engar nýlegar blöðrur"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nýlegar blöðrur og blöðrur sem þú hefur lokað birtast hér"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Blaðra"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Stjórna"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Blöðru lokað."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-is/strings_tv.xml b/libs/WindowManager/Shell/res/values-is/strings_tv.xml
new file mode 100644
index 000000000000..ab3f3a64d858
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-is/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Efni án titils)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Loka mynd í mynd"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Allur skjárinn"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
new file mode 100644
index 000000000000..bb4f9d745796
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Chiudi"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Espandi"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Impostazioni"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> è in Picture in picture"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Se non desideri che l\'app <xliff:g id="NAME">%s</xliff:g> utilizzi questa funzione, tocca per aprire le impostazioni e disattivarla."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Riproduci"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Metti in pausa"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Passa ai contenuti successivi"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Passa ai contenuti precedenti"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ridimensiona"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'app non supporta la modalità Schermo diviso."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"L\'app potrebbe non funzionare su un display secondario."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'app non supporta l\'avvio su display secondari."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Strumento per schermo diviso"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Schermata sinistra a schermo intero"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Schermata sinistra al 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Schermata sinistra al 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Schermata sinistra al 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Schermata destra a schermo intero"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Schermata superiore a schermo intero"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Schermata superiore al 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Schermata superiore al 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Schermata superiore al 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Schermata inferiore a schermo intero"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Impostazioni per bolle <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Altre"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Aggiungi di nuovo all\'elenco"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g> e altre <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Sposta in alto a sinistra"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Sposta in alto a destra"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Sposta in basso a sinistra"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Sposta in basso a destra"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Impostazioni <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignora bolla"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Non mettere la conversazione nella bolla"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatta utilizzando le bolle"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Le nuove conversazioni vengono visualizzate come icone mobili o bolle. Tocca per aprire la bolla. Trascinala per spostarla."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controlla le bolle quando vuoi"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tocca Gestisci per disattivare le bolle dall\'app"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nessuna bolla recente"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Le bolle recenti e ignorate appariranno qui"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Fumetto"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestisci"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Fumetto ignorato."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-it/strings_tv.xml b/libs/WindowManager/Shell/res/values-it/strings_tv.xml
new file mode 100644
index 000000000000..0d50580cbce2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-it/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programma senza titolo)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Chiudi PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Schermo intero"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
new file mode 100644
index 000000000000..f163dcfc67a2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"סגירה"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"הרחב"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"הגדרות"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"תפריט"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> במצב תמונה בתוך תמונה"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"אם אינך רוצה שהתכונה הזו תשמש את <xliff:g id="NAME">%s</xliff:g>, יש להקיש כדי לפתוח את ההגדרות ולכבות את התכונה."</string>
+ <string name="pip_play" msgid="3496151081459417097">"הפעל"</string>
+ <string name="pip_pause" msgid="690688849510295232">"השהה"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"אפשר לדלג אל הבא"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"אפשר לדלג אל הקודם"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"שינוי גודל"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"האפליקציה אינה תומכת במסך מפוצל."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ייתכן שהאפליקציה לא תפעל במסך משני."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"האפליקציה אינה תומכת בהפעלה במסכים משניים."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"מחלק מסך מפוצל"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"מסך שמאלי מלא"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"שמאלה 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"שמאלה 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"שמאלה 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"מסך ימני מלא"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"מסך עליון מלא"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"עליון 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"עליון 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"עליון 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"מסך תחתון מלא"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"הגדרות בשביל בועות של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"גלישה"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"הוספה בחזרה לערימה"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מהאפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מ-<xliff:g id="APP_NAME">%2$s</xliff:g> ועוד <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"העברה לפינה השמאלית העליונה"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"העברה לפינה הימנית העליונה"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"העברה לפינה השמאלית התחתונה"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"העברה לפינה הימנית התחתונה"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"הגדרות <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"סגירת בועה"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"אין להציג בועות לשיחה"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"לדבר בבועות"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"שיחות חדשות מופיעות כסמלים צפים, או בועות. יש להקיש כדי לפתוח בועה. יש לגרור כדי להזיז אותה."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"שליטה בבועות, בכל זמן"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"יש להקיש על \'ניהול\' כדי להשבית את הבועות מהאפליקציה הזו"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"אין בועות מהזמן האחרון"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"בועות אחרונות ובועות שנסגרו יופיעו כאן"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"בועה"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"ניהול"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"הבועה נסגרה."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings_tv.xml b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
new file mode 100644
index 000000000000..528d55751783
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-iw/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(תוכנית ללא כותרת)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"‏סגור PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"מסך מלא"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
new file mode 100644
index 000000000000..c31d01ceb0a9
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"閉じる"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"展開"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"設定"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"メニュー"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g>はピクチャー イン ピクチャーで表示中です"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g>でこの機能を使用しない場合は、タップして設定を開いて OFF にしてください。"</string>
+ <string name="pip_play" msgid="3496151081459417097">"再生"</string>
+ <string name="pip_pause" msgid="690688849510295232">"一時停止"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"次へスキップ"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"前へスキップ"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"サイズ変更"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"アプリで分割画面がサポートされていません。"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"アプリはセカンダリ ディスプレイでは動作しないことがあります。"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"アプリはセカンダリ ディスプレイでの起動に対応していません。"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"分割画面の分割線"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"左全画面"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"左 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右全画面"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"上部全画面"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"上 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"上 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"上 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"下部全画面"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> のバブルの設定"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"オーバーフロー"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"スタックに戻す"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)、他 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 件"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"左上に移動"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"右上に移動"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"左下に移動"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"右下に移動"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> の設定"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"バブルを閉じる"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"会話をバブルで表示しない"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"チャットでバブルを使う"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"新しい会話はフローティング アイコン(バブル)として表示されます。タップするとバブルが開きます。ドラッグしてバブルを移動できます。"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"いつでもバブルを管理"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"このアプリからのバブルを OFF にするには、[管理] をタップしてください"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近閉じたバブルはありません"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"最近表示されたバブルや閉じたバブルが、ここに表示されます"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"バブル"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ふきだしが非表示になっています。"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings_tv.xml b/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
new file mode 100644
index 000000000000..4a9cc403f5a3
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ja/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(無題の番組)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP を閉じる"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"全画面表示"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
new file mode 100644
index 000000000000..9e86c8a4cf99
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"დახურვა"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"გაშლა"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"პარამეტრები"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"მენიუ"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> იყენებს რეჟიმს „ეკრანი ეკრანში“"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"თუ არ გსურთ, რომ <xliff:g id="NAME">%s</xliff:g> ამ ფუნქციას იყენებდეს, აქ შეხებით შეგიძლიათ გახსნათ პარამეტრები და გამორთოთ ის."</string>
+ <string name="pip_play" msgid="3496151081459417097">"დაკვრა"</string>
+ <string name="pip_pause" msgid="690688849510295232">"დაპაუზება"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"შემდეგზე გადასვლა"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"წინაზე გადასვლა"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ზომის შეცვლა"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"აპმა შეიძლება არ იმუშაოს მეორეულ ეკრანზე."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"აპს არ გააჩნია მეორეული ეკრანის მხარდაჭერა."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"გაყოფილი ეკრანის რეჟიმის გამყოფი"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"მარცხენა ნაწილის სრულ ეკრანზე გაშლა"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"მარცხენა ეკრანი — 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"მარცხენა ეკრანი — 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"მარცხენა ეკრანი — 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"მარჯვენა ნაწილის სრულ ეკრანზე გაშლა"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ზედა ნაწილის სრულ ეკრანზე გაშლა"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ზედა ეკრანი — 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ზედა ეკრანი — 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ზედა ეკრანი — 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ქვედა ნაწილის სრულ ეკრანზე გაშლა"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"პარამეტრები <xliff:g id="APP_NAME">%1$s</xliff:g> ბუშტებისთვის"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"გადავსება"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"ისევ დამატება დასტაზე"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g>-ისგან"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g>-დან და კიდევ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ზევით და მარცხნივ გადატანა"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"გადაანაცვლეთ ზევით და მარჯვნივ"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ქვევით და მარცხნივ გადატანა"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"გადაანაცვ. ქვემოთ და მარჯვნივ"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-ის პარამეტრები"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"ბუშტის დახურვა"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"აიკრძალოს საუბრის ბუშტები"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"ჩეთი ბუშტების გამოყენებით"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"ახალი საუბრები გამოჩნდება როგორც მოტივტივე ხატულები ან ბუშტები. შეეხეთ ბუშტის გასახსნელად. გადაიტანეთ ჩავლებით."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"ბუშტების ნებისმიერ დროს გაკონტროლება"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"ამ აპის ბუშტების გამოსართავად შეეხეთ „მართვას“"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ბოლო დროს გამოყენებული ბუშტები არ არის"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"აქ გამოჩნდება ბოლოდროინდელი ბუშტები და უარყოფილი ბუშტები"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"ბუშტი"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"მართვა"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ბუშტი დაიხურა."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings_tv.xml b/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
new file mode 100644
index 000000000000..be420a3cdcc4
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ka/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(პროგრამის სათაურის გარეშე)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP-ის დახურვა"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"სრულ ეკრანზე"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
new file mode 100644
index 000000000000..0cda01ecade4
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Жабу"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Жаю"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Параметрлер"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Mәзір"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> \"суреттегі сурет\" режимінде"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> деген пайдаланушының бұл мүмкіндікті пайдалануын қаламасаңыз, параметрлерді түртіп ашыңыз да, оларды өшіріңіз."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Ойнату"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Кідірту"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Келесіге өту"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Алдыңғысына оралу"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Өлшемін өзгерту"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Қодланба бөлінген экранды қолдамайды."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Қолданба қосымша дисплейде жұмыс істемеуі мүмкін."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Қолданба қосымша дисплейлерде іске қосуды қолдамайды."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Бөлінген экран бөлгіші"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Сол жағын толық экранға шығару"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% сол жақта"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% сол жақта"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% сол жақта"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Оң жағын толық экранға шығару"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Жоғарғы жағын толық экранға шығару"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% жоғарғы жақта"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% жоғарғы жақта"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% жоғарғы жақта"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Төменгісін толық экранға шығару"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> қалқыма хабарларының параметрлері"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Қосымша мәзір"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Стекке қайта енгізу"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> жіберген хабарландыру: <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасы жіберген <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> және тағы <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Жоғарғы сол жаққа жылжыту"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Жоғары оң жаққа жылжыту"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Төменгі сол жаққа жылжыту"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Төменгі оң жаққа жылжыту"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> параметрлері"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Қалқымалы хабарды жабу"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Әңгіменің қалқыма хабары көрсетілмесін"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Қалқыма хабарлар арқылы сөйлесу"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Жаңа әңгімелер қалқыма белгішелер немесе хабарлар түрінде көрсетіледі. Қалқыма хабарды ашу үшін түртіңіз. Жылжыту үшін сүйреңіз."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Қалқыма хабарларды реттеу"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Бұл қолданбадан қалқыма хабарларды өшіру үшін \"Басқару\" түймесін түртіңіз."</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Жақындағы қалқыма хабарлар жоқ"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Соңғы және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Көпіршік"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Басқару"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Қалқымалы анықтама өшірілді."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings_tv.xml b/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
new file mode 100644
index 000000000000..9b12cff76bfd
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-kk/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Атаусыз бағдарлама)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP жабу"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Толық экран"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
new file mode 100644
index 000000000000..d0b18769ce9d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"បិទ"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"ពង្រីក"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"ការកំណត់"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"ម៉ឺនុយ"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ស្ថិតក្នុងមុខងាររូបក្នុងរូប"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"ប្រសិនបើ​អ្នក​មិន​ចង់​ឲ្យ <xliff:g id="NAME">%s</xliff:g> ប្រើ​មុខងារ​នេះ​ សូមចុច​​បើក​ការកំណត់ រួច​បិទ​វា។"</string>
+ <string name="pip_play" msgid="3496151081459417097">"លេង"</string>
+ <string name="pip_pause" msgid="690688849510295232">"ផ្អាក"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"រំលងទៅបន្ទាប់"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"រំលងទៅក្រោយ"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ប្ដូរ​ទំហំ"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"កម្មវិធីមិនគាំទ្រអេក្រង់បំបែកជាពីរទេ"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"កម្មវិធីនេះ​ប្រហែល​ជាមិនដំណើរការ​នៅលើ​អេក្រង់បន្ទាប់បន្សំទេ។"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"កម្មវិធី​នេះមិន​អាច​ចាប់ផ្តើម​នៅលើ​អេក្រង់បន្ទាប់បន្សំបានទេ។"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"កម្មវិធីចែកអេក្រង់បំបែក"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"អេក្រង់ពេញខាងឆ្វេង"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ឆ្វេង 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ឆ្វេង 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ឆ្វេង 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"អេក្រង់ពេញខាងស្តាំ"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"អេក្រង់ពេញខាងលើ"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ខាងលើ 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ខាងលើ 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ខាងលើ 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"អេក្រង់ពេញខាងក្រោម"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"ការកំណត់​សម្រាប់​ពពុះ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ម៉ឺនុយបន្ថែម"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"បញ្ចូល​ទៅក្នុង​គំនរវិញ"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g> និង <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ទៀត"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ផ្លាស់ទីទៅផ្នែកខាងលើខាងឆ្វេង"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ផ្លាស់ទីទៅផ្នែកខាងលើខាងស្ដាំ"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ផ្លាស់ទីទៅផ្នែកខាងក្រោមខាងឆ្វេង​"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ផ្លាស់ទីទៅផ្នែកខាងក្រោម​ខាងស្ដាំ"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"ការកំណត់ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"ច្រានចោល​ពពុះ"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"កុំបង្ហាញ​ការសន្ទនា​ជាពពុះ"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"ជជែក​ដោយប្រើ​ពពុះ"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"ការសន្ទនាថ្មីៗ​បង្ហាញជា​​ពពុះ ឬរូបអណ្ដែត។ ចុច ដើម្បីបើក​ពពុះ។ អូស ដើម្បី​ផ្លាស់ទី​ពពុះនេះ។"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"គ្រប់គ្រង​​ពពុះ​បានគ្រប់ពេល"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"ចុច \"គ្រប់គ្រង\" ដើម្បីបិទ​ពពុះពីកម្មវិធីនេះ"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"មិនមាន​ពពុះ​ថ្មីៗ​ទេ"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ពពុះថ្មីៗ​ និង​ពពុះដែលបានបិទ​​នឹង​បង្ហាញ​នៅទីនេះ"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"ពពុះ"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"គ្រប់គ្រង"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"បានច្រានចោល​សារលេចឡើង។"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-km/strings_tv.xml b/libs/WindowManager/Shell/res/values-km/strings_tv.xml
new file mode 100644
index 000000000000..e1a673e863cf
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-km/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(កម្មវិធី​គ្មានចំណងជើង)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"បិទ PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"ពេញអេក្រង់"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
new file mode 100644
index 000000000000..456dc06b02cd
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"ಮುಚ್ಚಿ"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"ವಿಸ್ತೃತಗೊಳಿಸು"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"ಮೆನು"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವಾಗಿದೆ"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ಈ ವೈಶಿಷ್ಟ್ಯ ಬಳಸುವುದನ್ನು ನೀವು ಬಯಸದಿದ್ದರೆ, ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಲು ಮತ್ತು ಅದನ್ನು ಆಫ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+ <string name="pip_play" msgid="3496151081459417097">"ಪ್ಲೇ"</string>
+ <string name="pip_pause" msgid="690688849510295232">"ವಿರಾಮಗೊಳಿಸಿ"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"ಮುಂದಕ್ಕೆ ಸ್ಕಿಪ್‌ ಮಾಡಿ"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"ಹಿಂದಕ್ಕೆ ಸ್ಕಿಪ್‌ ಮಾಡಿ"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ಅಪ್ಲಿಕೇಶನ್ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ಸೆಕೆಂಡರಿ ಡಿಸ್‌ಪ್ಲೇಗಳಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್‌ ಕಾರ್ಯ ನಿರ್ವಹಿಸದೇ ಇರಬಹುದು."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ಸೆಕೆಂಡರಿ ಡಿಸ್‌ಪ್ಲೇಗಳಲ್ಲಿ ಪ್ರಾರಂಭಿಸುವಿಕೆಯನ್ನು ಅಪ್ಲಿಕೇಶನ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"ಸ್ಪ್ಲಿಟ್-ಪರದೆ ಡಿವೈಡರ್"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ಎಡ ಪೂರ್ಣ ಪರದೆ"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% ಎಡಕ್ಕೆ"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% ಎಡಕ್ಕೆ"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% ಎಡಕ್ಕೆ"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ಬಲ ಪೂರ್ಣ ಪರದೆ"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ಮೇಲಿನ ಪೂರ್ಣ ಪರದೆ"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% ಮೇಲಕ್ಕೆ"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% ಮೇಲಕ್ಕೆ"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% ಮೇಲಕ್ಕೆ"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ಕೆಳಗಿನ ಪೂರ್ಣ ಪರದೆ"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಬಬಲ್ಸ್‌ಗಾಗಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ಓವರ್‌ಫ್ಲೋ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"ಸ್ಟ್ಯಾಕ್‌ಗೆ ಪುನಃ ಸೇರಿಸಿ"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> ಆ್ಯಪ್‌ನ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> ಮತ್ತು <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ಹೆಚ್ಚಿನವುಗಳ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ಎಡ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ಬಲ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ಸ್ಕ್ರೀನ್‌ನ ಎಡ ಕೆಳಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ಕೆಳಗಿನ ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"ಬಬಲ್ ವಜಾಗೊಳಿಸಿ"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ಸಂಭಾಷಣೆಯನ್ನು ಬಬಲ್ ಮಾಡಬೇಡಿ"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"ಬಬಲ್ಸ್ ಬಳಸಿ ಚಾಟ್ ಮಾಡಿ"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"ಹೊಸ ಸಂಭಾಷಣೆಗಳು ತೇಲುವ ಐಕಾನ್‌ಗಳು ಅಥವಾ ಬಬಲ್ಸ್ ಆಗಿ ಗೋಚರಿಸುತ್ತವೆ. ಬಬಲ್ ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಅದನ್ನು ಡ್ರ್ಯಾಗ್ ಮಾಡಲು ಎಳೆಯಿರಿ."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಬಬಲ್ಸ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"ಈ ಆ್ಯಪ್‌ನಿಂದ ಬಬಲ್ಸ್ ಅನ್ನು ಆಫ್ ಮಾಡಲು ನಿರ್ವಹಿಸಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಇಲ್ಲ"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಮತ್ತು ವಜಾಗೊಳಿಸಿದ ಬಬಲ್ಸ್ ಇಲ್ಲಿ ಗೋಚರಿಸುತ್ತವೆ"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"ಬಬಲ್"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"ನಿರ್ವಹಿಸಿ"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ಬಬಲ್ ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings_tv.xml b/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
new file mode 100644
index 000000000000..699824aa724f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-kn/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ಶೀರ್ಷಿಕೆ ರಹಿತ ಕಾರ್ಯಕ್ರಮ)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP ಮುಚ್ಚಿ"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"ಪೂರ್ಣ ಪರದೆ"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
new file mode 100644
index 000000000000..57a2cb1b970d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"닫기"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"펼치기"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"설정"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"메뉴"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g>에서 PIP 사용 중"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g>에서 이 기능이 사용되는 것을 원하지 않는 경우 탭하여 설정을 열고 기능을 사용 중지하세요."</string>
+ <string name="pip_play" msgid="3496151081459417097">"재생"</string>
+ <string name="pip_pause" msgid="690688849510295232">"일시중지"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"다음으로 건너뛰기"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"이전으로 건너뛰기"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"크기 조절"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"앱이 화면 분할을 지원하지 않습니다."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"앱이 보조 디스플레이에서 작동하지 않을 수도 있습니다."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"앱이 보조 디스플레이에서의 실행을 지원하지 않습니다."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"화면 분할기"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"왼쪽 화면 전체화면"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"왼쪽 화면 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"왼쪽 화면 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"왼쪽 화면 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"오른쪽 화면 전체화면"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"위쪽 화면 전체화면"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"위쪽 화면 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"위쪽 화면 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"위쪽 화면 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"아래쪽 화면 전체화면"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> 대화창 설정"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"더보기"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"스택에 다시 추가"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g>의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> 외 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>개의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"왼쪽 상단으로 이동"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"오른쪽 상단으로 이동"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"왼쪽 하단으로 이동"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"오른쪽 하단으로 이동"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> 설정"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"대화창 닫기"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"대화를 대화창으로 표시하지 않기"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"대화창으로 채팅하기"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"새로운 대화가 플로팅 아이콘인 대화창으로 표시됩니다. 대화창을 열려면 탭하세요. 드래그하여 이동할 수 있습니다."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"언제든지 대화창을 제어하세요"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"이 앱에서 대화창을 사용 중지하려면 관리를 탭하세요."</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"최근 대화창 없음"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"최근 대화창과 내가 닫은 대화창이 여기에 표시됩니다."</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"버블"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"관리"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"대화창을 닫았습니다."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings_tv.xml b/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
new file mode 100644
index 000000000000..827561e8a2dd
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ko/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(제목 없는 프로그램)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP 닫기"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"전체화면"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
new file mode 100644
index 000000000000..6862aa1d4e61
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Жабуу"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Жайып көрсөтүү"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Жөндөөлөр"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> – сүрөт ичиндеги сүрөт"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Эгер <xliff:g id="NAME">%s</xliff:g> колдонмосу бул функцияны пайдаланбасын десеңиз, жөндөөлөрдү ачып туруп, аны өчүрүп коюңуз."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Ойнотуу"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Тындыруу"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Кийинкисине өткөрүп жиберүү"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Мурункусуна өткөрүп жиберүү"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Өлчөмүн өзгөртүү"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Колдонмодо экран бөлүнбөйт."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Колдонмо кошумча экранда иштебей коюшу мүмкүн."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Колдонмону кошумча экрандарда иштетүүгө болбойт."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Экранды бөлгүч"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Сол жактагы экранды толук экран режимине өткөрүү"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Сол жактагы экранды 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Сол жактагы экранды 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Сол жактагы экранды 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Оң жактагы экранды толук экран режимине өткөрүү"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Үстүнкү экранды толук экран режимине өткөрүү"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Үстүнкү экранды 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Үстүнкү экранды 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Үстүнкү экранды 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ылдыйкы экранды толук экран режимине өткөрүү"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> калкып чыкма билдирмелер жөндөөлөрү"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Кошумча меню"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Кайра топтомго кошуу"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> колдонмосунан <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> жана дагы <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> колдонмодон <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Жогорку сол жакка жылдыруу"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Жогорку оң жакка жылдырыңыз"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Төмөнкү сол жакка жылдыруу"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Төмөнкү оң жакка жылдырыңыз"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> жөндөөлөрү"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Калкып чыкма билдирмени жабуу"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Жазышууда калкып чыкма билдирмелер көрүнбөсүн"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Калкып чыкма билдирмелер аркылуу маектешүү"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Жаңы жазышуулар калкыма сүрөтчөлөр же калкып чыкма билдирмелер түрүндө көрүнөт. Калкып чыкма билдирмелерди ачуу үчүн таптап коюңуз. Жылдыруу үчүн сүйрөңүз."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Калкып чыкма билдирмелерди каалаган убакта көзөмөлдөңүз"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Бул колдонмодогу калкып чыкма билдирмелерди өчүрүү үчүн, \"Башкарууну\" басыңыз"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Азырынча эч нерсе жок"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Акыркы жана жабылган калкып чыкма билдирмелер ушул жерде көрүнөт"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Көбүк"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Башкаруу"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Калкып чыкма билдирме жабылды."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings_tv.xml b/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
new file mode 100644
index 000000000000..68376b12bd42
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ky/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Аталышы жок программа)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP\'ти жабуу"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Толук экран"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-land/dimens.xml b/libs/WindowManager/Shell/res/values-land/dimens.xml
index 77a601ddf440..aafba58cef59 100644
--- a/libs/WindowManager/Shell/res/values-land/dimens.xml
+++ b/libs/WindowManager/Shell/res/values-land/dimens.xml
@@ -18,4 +18,8 @@
<resources>
<dimen name="docked_divider_handle_width">2dp</dimen>
<dimen name="docked_divider_handle_height">16dp</dimen>
+
+ <!-- Padding between status bar and bubbles when displayed in expanded state, smaller
+ value in landscape since we have limited vertical space-->
+ <dimen name="bubble_padding_top">4dp</dimen>
</resources> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
new file mode 100644
index 000000000000..2973414c6ab3
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"ປິດ"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"ຂະຫຍາຍ"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"ການຕັ້ງຄ່າ"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"ເມນູ"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ແມ່ນເປັນການສະແດງຜົນຫຼາຍຢ່າງພ້ອມກັນ"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"ຫາກທ່ານບໍ່ຕ້ອງການ <xliff:g id="NAME">%s</xliff:g> ໃຫ້ໃຊ້ຄຸນສົມບັດນີ້, ໃຫ້ແຕະເພື່ອເປີດການຕັ້ງຄ່າ ແລ້ວປິດມັນໄວ້."</string>
+ <string name="pip_play" msgid="3496151081459417097">"ຫຼິ້ນ"</string>
+ <string name="pip_pause" msgid="690688849510295232">"ຢຸດຊົ່ວຄາວ"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"ຂ້າມໄປລາຍການໜ້າ"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"ຂ້າມໄປລາຍການກ່ອນນີ້"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ປ່ຽນຂະໜາດ"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ແອັບບໍ່ຮອງຮັບໜ້າຈໍແບບແຍກກັນ."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ແອັບອາດບໍ່ສາມາດໃຊ້ໄດ້ໃນໜ້າຈໍທີສອງ."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ແອັບບໍ່ຮອງຮັບການເປີດໃນໜ້າຈໍທີສອງ."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"ຕົວຂັ້ນການແບ່ງໜ້າຈໍ"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ເຕັມໜ້າຈໍຊ້າຍ"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ຊ້າຍ 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ຊ້າຍ 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ຊ້າຍ 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ເຕັມໜ້າຈໍຂວາ"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ເຕັມໜ້າຈໍເທິງສຸດ"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ເທິງສຸດ 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ເທິງສຸດ 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ເທິງສຸດ 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ເຕັມໜ້າຈໍລຸ່ມສຸດ"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"ການຕັ້ງຄ່າສຳລັບຟອງ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ລົ້ນ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"ເພີ່ມກັບໄປຫາການວາງຊ້ອນກັນ"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g> ແລະ ອີກ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ຍ້າຍຊ້າຍເທິງ"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ຍ້າຍຂວາເທິງ"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ຍ້າຍຊ້າຍລຸ່ມ"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ຍ້າຍຂວາລຸ່ມ"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"ການຕັ້ງຄ່າ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"ປິດຟອງໄວ້"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ຢ່າໃຊ້ຟອງໃນການສົນທະນາ"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"ສົນທະນາໂດຍໃຊ້ຟອງ"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"ການສົນທະນາໃໝ່ຈະປາກົດເປັນໄອຄອນ ຫຼື ຟອງແບບລອຍ. ແຕະເພື່ອເປີດຟອງ. ລາກເພື່ອຍ້າຍມັນ."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"ຄວບຄຸມຟອງຕອນໃດກໍໄດ້"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"ແຕະຈັດການ ເພື່ອປິດຟອງຈາກແອັບນີ້"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ບໍ່ມີຟອງຫຼ້າສຸດ"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ຟອງຫຼ້າສຸດ ແລະ ຟອງທີ່ປິດໄປຈະປາກົດຢູ່ບ່ອນນີ້"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"ຟອງ"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"ຈັດການ"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ປິດ Bubble ໄສ້ແລ້ວ."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings_tv.xml b/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
new file mode 100644
index 000000000000..d1322567a584
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-lo/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ໂປຣແກຣມບໍ່ມີຊື່)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"ປິດ PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"ເຕັມໜ້າຈໍ"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
new file mode 100644
index 000000000000..007d0695c03d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Uždaryti"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Išskleisti"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Nustatymai"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Meniu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> rodom. vaizdo vaizde"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Jei nenorite, kad „<xliff:g id="NAME">%s</xliff:g>“ naudotų šią funkciją, palietę atidarykite nustatymus ir išjunkite ją."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Leisti"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pristabdyti"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Praleisti ir eiti į kitą"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Praleisti ir eiti į ankstesnį"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Pakeisti dydį"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programoje nepalaikomas skaidytas ekranas."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Programa gali neveikti antriniame ekrane."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Programa nepalaiko paleisties antriniuose ekranuose."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Skaidyto ekrano daliklis"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Kairysis ekranas viso ekrano režimu"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kairysis ekranas 70 %"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kairysis ekranas 50 %"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kairysis ekranas 30 %"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Dešinysis ekranas viso ekrano režimu"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Viršutinis ekranas viso ekrano režimu"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Viršutinis ekranas 70 %"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Viršutinis ekranas 50 %"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Viršutinis ekranas 30 %"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Apatinis ekranas viso ekrano režimu"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ burbulų nustatymai"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Perpildymas"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Pridėti atgal į krūvą"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“ ir dar <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Perkelti į viršų kairėje"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Perkelti į viršų dešinėje"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Perkelti į apačią kairėje"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Perkelti į apačią dešinėje"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ nustatymai"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Atsisakyti burbulo"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nerodyti pokalbio burbule"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Pokalbis naudojant burbulus"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nauji pokalbiai rodomi kaip slankiosios piktogramos arba burbulai. Palieskite, kad atidarytumėte burbulą. Vilkite, kad perkeltumėte."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Bet kada valdyti burbulus"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Palieskite „Tvarkyti“, kad išjungtumėte burbulus šioje programoje"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nėra naujausių burbulų"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Naujausi ir atsisakyti burbulai bus rodomi čia"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Debesėlis"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Tvarkyti"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Debesėlio atsisakyta."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings_tv.xml b/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
new file mode 100644
index 000000000000..189f766a1b5f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-lt/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programa be pavadinimo)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Uždaryti PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Visas ekranas"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
new file mode 100644
index 000000000000..a7f96178b164
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Aizvērt"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Izvērst"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Iestatījumi"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Izvēlne"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ir attēlā attēlā"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ja nevēlaties lietotnē <xliff:g id="NAME">%s</xliff:g> izmantot šo funkciju, pieskarieties, lai atvērtu iestatījumus un izslēgtu funkciju."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Atskaņot"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Apturēt"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Pāriet uz nākamo"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Pāriet uz iepriekšējo"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Mainīt lielumu"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Lietotnē netiek atbalstīta ekrāna sadalīšana."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Lietotne, iespējams, nedarbosies sekundārajā displejā."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Lietotnē netiek atbalstīta palaišana sekundārajos displejos."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Ekrāna sadalītājs"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Kreisā daļa pa visu ekrānu"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Pa kreisi 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pa kreisi 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Pa kreisi 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Labā daļa pa visu ekrānu"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Augšdaļa pa visu ekrānu"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Augšdaļa 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Augšdaļa 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Augšdaļa 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Apakšdaļu pa visu ekrānu"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> burbuļu iestatījumi"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Pārpilde"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Pievienot atpakaļ kopai"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> no: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> no lietotnes “<xliff:g id="APP_NAME">%2$s</xliff:g>” un vēl <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Pārvietot augšpusē pa kreisi"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Pārvietot augšpusē pa labi"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Pārvietot apakšpusē pa kreisi"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Pārvietot apakšpusē pa labi"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Lietotnes <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iestatījumi"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Nerādīt burbuli"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nerādīt sarunu burbuļos"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Tērzēšana, izmantojot burbuļus"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Jaunas sarunas tiek rādītas kā peldošas ikonas vai burbuļi. Pieskarieties, lai atvērtu burbuli. Velciet, lai to pārvietotu."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Allaž pārvaldīt burbuļus"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Pieskarieties pogai “Pārvaldīt”, lai izslēgtu burbuļus no šīs lietotnes."</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nav nesen aizvērtu burbuļu"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Šeit būs redzami nesen rādītie burbuļi un aizvērtie burbuļi"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Burbulis"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Pārvaldīt"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbulis ir noraidīts."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings_tv.xml b/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
new file mode 100644
index 000000000000..614104b99a5f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-lv/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programma bez nosaukuma)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Aizvērt PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Pilnekrāna režīms"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
new file mode 100644
index 000000000000..9edb7bef681f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Затвори"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Проширете"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Поставки"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Мени"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> е во слика во слика"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ако не сакате <xliff:g id="NAME">%s</xliff:g> да ја користи функцијава, допрете за да ги отворите поставките и да ја исклучите."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Пушти"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Паузирај"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Прескокни до следната"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Прескокни до претходната"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Промени големина"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликацијата не поддржува поделен екран."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликацијата може да не функционира на друг екран."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Апликацијата не поддржува стартување на други екрани."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Разделник на поделен екран"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Левиот на цел екран"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Левиот 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левиот 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Левиот 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Десниот на цел екран"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Горниот на цел екран"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горниот 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горниот 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Горниот 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Долниот на цел екран"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Поставки за балончињата за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Прелевање"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Додајте назад во stack"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g> и уште <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Премести горе лево"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Премести горе десно"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Премести долу лево"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Премести долу десно"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Поставки за <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Отфрли балонче"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не прикажувај го разговорот во балончиња"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Разговор во балончиња"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Новите разговори ќе се појавуваат како лебдечки икони или балончиња. Допрете за отворање на балончето. Повлечете за да го преместите."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Контролирајте ги балончињата во секое време"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Допрете „Управувајте“ за да ги исклучите балончињата од апликацијава"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Нема неодамнешни балончиња"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Неодамнешните и отфрлените балончиња ќе се појавуваат тука"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Балонче"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Управувајте"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Балончето е отфрлено."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings_tv.xml b/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
new file mode 100644
index 000000000000..c279f7977b32
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-mk/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програма без наслов)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Затвори PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Цел екран"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
new file mode 100644
index 000000000000..dfa4b2287b10
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"അവസാനിപ്പിക്കുക"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"വികസിപ്പിക്കുക"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"ക്രമീകരണം"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"മെനു"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ചിത്രത്തിനുള്ളിൽ ചിത്രം രീതിയിലാണ്"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ഈ ഫീച്ചർ ഉപയോഗിക്കേണ്ടെങ്കിൽ, ടാപ്പ് ചെയ്‌ത് ക്രമീകരണം തുറന്ന് അത് ഓഫാക്കുക."</string>
+ <string name="pip_play" msgid="3496151081459417097">"പ്ലേ ചെയ്യുക"</string>
+ <string name="pip_pause" msgid="690688849510295232">"താൽക്കാലികമായി നിർത്തുക"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"അടുത്തതിലേക്ക് പോകുക"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"മുമ്പത്തേതിലേക്ക് പോകുക"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"വലുപ്പം മാറ്റുക"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"രണ്ടാം ഡിസ്‌പ്ലേയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"രണ്ടാം ഡിസ്‌പ്ലേകളിൽ സമാരംഭിക്കുന്നതിനെ ആപ്പ് അനുവദിക്കുന്നില്ല."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"സ്പ്ലിറ്റ്-സ്ക്രീൻ ഡിവൈഡർ"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ഇടത് പൂർണ്ണ സ്ക്രീൻ"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ഇടത് 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ഇടത് 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ഇടത് 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"വലത് പൂർണ്ണ സ്ക്രീൻ"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"മുകളിൽ പൂർണ്ണ സ്ക്രീൻ"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"മുകളിൽ 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"മുകളിൽ 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"മുകളിൽ 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"താഴെ പൂർണ്ണ സ്ക്രീൻ"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബബിളുകളുടെ ക്രമീകരണം"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ഓവർഫ്ലോ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"അടുക്കുകളിലേക്ക് തിരിച്ച് ചേർക്കുക"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g>-ൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> കൂടുതലും"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"മുകളിൽ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ചുവടെ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ക്രമീകരണം"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"ബബിൾ ഡിസ്മിസ് ചെയ്യൂ"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"സംഭാഷണം ബബിൾ ചെയ്യരുത്"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"ബബിളുകൾ ഉപയോഗിച്ച് ചാറ്റ് ചെയ്യുക"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"പുതിയ സംഭാഷണങ്ങൾ ഫ്ലോട്ടിംഗ് ഐക്കണുകളോ ബബിളുകളോ ആയി ദൃശ്യമാവുന്നു. ബബിൾ തുറക്കാൻ ടാപ്പ് ചെയ്യൂ. ഇത് നീക്കാൻ വലിച്ചിടുക."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"ബബിളുകൾ ഏതുസമയത്തും നിയന്ത്രിക്കുക"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"ഈ ആപ്പിൽ നിന്നുള്ള ബബിളുകൾ ഓഫാക്കാൻ മാനേജ് ചെയ്യുക ടാപ്പ് ചെയ്യുക"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"അടുത്തിടെയുള്ള ബബിളുകൾ ഒന്നുമില്ല"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"അടുത്തിടെയുള്ള ബബിളുകൾ, ഡിസ്മിസ് ചെയ്ത ബബിളുകൾ എന്നിവ ഇവിടെ ദൃശ്യമാവും"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"ബബ്ൾ"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"മാനേജ് ചെയ്യുക"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ബബ്ൾ ഡിസ്മിസ് ചെയ്തു."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings_tv.xml b/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
new file mode 100644
index 000000000000..7aaf79fb666e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ml/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(പേരില്ലാത്ത പ്രോഗ്രാം)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP അടയ്ക്കുക"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"പൂര്‍ണ്ണ സ്ക്രീന്‍"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
new file mode 100644
index 000000000000..071629fe0fb1
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Хаах"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Дэлгэх"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Тохиргоо"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Цэс"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> дэлгэцэн доторх дэлгэцэд байна"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Та <xliff:g id="NAME">%s</xliff:g>-д энэ онцлогийг ашиглуулахыг хүсэхгүй байвал тохиргоог нээгээд, үүнийг унтраана уу."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Тоглуулах"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Түр зогсоох"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Дараагийн медиад очих"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Өмнөх медиад очих"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Хэмжээг өөрчлөх"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Энэ апп нь дэлгэц хуваах тохиргоог дэмждэггүй."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апп хоёрдогч дэлгэцэд ажиллахгүй."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Аппыг хоёрдогч дэлгэцэд эхлүүлэх боломжгүй."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"\"Дэлгэц хуваах\" хуваагч"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Зүүн талын бүтэн дэлгэц"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Зүүн 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Зүүн 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Зүүн 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Баруун талын бүтэн дэлгэц"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Дээд талын бүтэн дэлгэц"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Дээд 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Дээд 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Дээд 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Доод бүтэн дэлгэц"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н бөмбөлгүүдийн тохиргоо"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Халих"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Өрөлтөд буцааж нэмэх"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g>-н <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g>-н <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> болон бусад <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Зүүн дээш зөөх"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Баруун дээш зөөх"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Зүүн доош зөөх"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Баруун доош зөөх"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-н тохиргоо"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Бөмбөлгийг хаах"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Харилцан яриаг бүү бөмбөлөг болго"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Бөмбөлөг ашиглан чатлаарай"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Шинэ харилцан яриа нь хөвөгч дүрс тэмдэг эсвэл бөмбөлөг хэлбэрээр харагддаг. Бөмбөлгийг нээхийн тулд товшино уу. Түүнийг зөөхийн тулд чирнэ үү."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Дурын үед бөмбөлгийг хянаарай"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Энэ аппын бөмбөлгүүдийг унтраахын тулд Удирдах дээр товшино уу"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Саяхны бөмбөлөг алга байна"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Саяхны бөмбөлгүүд болон үл хэрэгссэн бөмбөлгүүд энд харагдана"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Бөмбөлөг"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Удирдах"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Бөмбөлгийг үл хэрэгссэн."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings_tv.xml b/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
new file mode 100644
index 000000000000..e4b026269b9b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-mn/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Гарчиггүй хөтөлбөр)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP-г хаах"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Бүтэн дэлгэц"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
new file mode 100644
index 000000000000..bd28756e49b8
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"बंद करा"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"विस्तृत करा"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"सेटिंग्ज"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"मेनू"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> चित्रामध्ये चित्र मध्ये आहे"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g>ने हे वैशिष्ट्य वापरू नये असे तुम्हाला वाटत असल्यास, सेटिंग्ज उघडण्यासाठी टॅप करा आणि ते बंद करा."</string>
+ <string name="pip_play" msgid="3496151081459417097">"प्ले करा"</string>
+ <string name="pip_pause" msgid="690688849510295232">"थांबवा"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"डावलून पुढे जा"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"डावलून मागे जा"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदला"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अ‍ॅप स्क्रीन-विभाजनास समर्थन देत नाही."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"दुसऱ्या डिस्प्लेवर अ‍ॅप कदाचित चालणार नाही."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"दुसऱ्या डिस्प्लेवर अ‍ॅप लाँच होणार नाही."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"विभाजित-स्क्रीन विभाजक"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"डावी फुल स्क्रीन"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"डावी 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"डावी 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"डावी 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"उजवी फुल स्क्रीन"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"शीर्ष फुल स्क्रीन"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"शीर्ष 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"शीर्ष 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"शीर्ष 10"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"तळाशी फुल स्क्रीन"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> बबलसाठी सेटिंग्ज"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ओव्हरफ्लो"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"स्टॅकमध्ये परत जोडा"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> कडून <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> आणि आणखी <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> कडून <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"वर डावीकडे हलवा"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"वर उजवीकडे हलवा"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"तळाशी डावीकडे हलवा"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"तळाशी उजवीकडे हलवा"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> सेटिंग्ज"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"बबल डिसमिस करा"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"संभाषणाला बबल करू नका"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"बबल वापरून चॅट करा"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"नवीन संभाषणे फ्लोटिंग आयकन किंवा बबल म्हणून दिसतात. बबल उघडण्यासाठी टॅप करा. हे हलवण्यासाठी ड्रॅग करा."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"बबल कधीही नियंत्रित करा"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"या अ‍ॅपमधून बबल बंद करण्यासाठी व्यवस्थापित करा वर टॅप करा"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"अलीकडील कोणतेही बबल नाहीत"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"अलीकडील बबल आणि डिसमिस केलेले बबल येथे दिसतील"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापित करा"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल डिसमिस केला."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
new file mode 100644
index 000000000000..d9fc3b1793c2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(शीर्षक नसलेला कार्यक्रम)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP बंद करा"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"फुल स्क्रीन"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
new file mode 100644
index 000000000000..267809f7f9a7
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Tutup"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Kembangkan"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Tetapan"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> terdapat dalam gambar dalam gambar"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Jika anda tidak mahu <xliff:g id="NAME">%s</xliff:g> menggunakan ciri ini, ketik untuk membuka tetapan dan matikan ciri."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Main"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Jeda"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Langkau ke seterusnya"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Langkau ke sebelumnya"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ubah saiz"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Apl tidak menyokong skrin pisah."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Apl mungkin tidak berfungsi pada paparan kedua."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Apl tidak menyokong pelancaran pada paparan kedua."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Pembahagi skrin pisah"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Skrin penuh kiri"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kiri 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kiri 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kiri 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Skrin penuh kanan"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Skrin penuh atas"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Atas 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Atas 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Atas 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Skrin penuh bawah"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Tetapan untuk gelembung <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Limpahan"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Tambah kembali pada tindanan"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> daripada <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> daripada <xliff:g id="APP_NAME">%2$s</xliff:g> dan <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> lagi"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Alihkan ke atas sebelah kiri"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Alihkan ke atas sebelah kanan"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Alihkan ke bawah sebelah kiri"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Alihkan ke bawah sebelah kanan"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Tetapan <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ketepikan gelembung"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Jangan jadikan perbualan dalam bentuk gelembung"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Bersembang menggunakan gelembung"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Perbualan baharu muncul sebagai ikon terapung atau gelembung. Ketik untuk membuka gelembung. Seret untuk mengalihkan gelembung tersebut."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Kawal gelembung pada bila-bila masa"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Ketik Urus untuk mematikan gelembung daripada apl ini"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Tiada gelembung terbaharu"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Gelembung baharu dan gelembung yang diketepikan akan dipaparkan di sini"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Gelembung"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Urus"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Gelembung diketepikan."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings_tv.xml b/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
new file mode 100644
index 000000000000..9597a790b349
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ms/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program tiada tajuk)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Tutup PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Skrin penuh"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
new file mode 100644
index 000000000000..b913a6b503ff
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"ပိတ်ရန်"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"ချဲ့ရန်"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"ဆက်တင်များ"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"မီနူး"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> သည် တစ်ခုပေါ် တစ်ခုထပ်၍ ဖွင့်ထားသည်"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> အား ဤဝန်ဆောင်မှုကို အသုံးမပြုစေလိုလျှင် ဆက်တင်ကိုဖွင့်ရန် တို့ပြီး ၎င်းဝန်ဆောင်မှုကို ပိတ်လိုက်ပါ။"</string>
+ <string name="pip_play" msgid="3496151081459417097">"ဖွင့်ရန်"</string>
+ <string name="pip_pause" msgid="690688849510295232">"ခေတ္တရပ်ရန်"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"နောက်တစ်ခုသို့ ကျော်ရန်"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"ယခင်တစ်ခုသို့ ပြန်သွားရန်"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"အရွယ်အစားပြောင်းရန်"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"အက်ပ်သည် မျက်နှာပြင်ခွဲပြရန် ပံ့ပိုးထားခြင်းမရှိပါ။"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ဤအက်ပ်အနေဖြင့် ဒုတိယဖန်သားပြင်ပေါ်တွင် အလုပ်လုပ်မည် မဟုတ်ပါ။"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ဤအက်ပ်အနေဖြင့် ဖွင့်ရန်စနစ်ကို ဒုတိယဖန်သားပြင်မှ အသုံးပြုရန် ပံ့ပိုးမထားပါ။"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"မျက်နှာပြင်ခွဲခြမ်း ပိုင်းခြားပေးသည့်စနစ်"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ဘယ်ဘက် မျက်နှာပြင်အပြည့်"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ဘယ်ဘက်မျက်နှာပြင် ၇၀%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ဘယ်ဘက် မျက်နှာပြင် ၅၀%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ဘယ်ဘက် မျက်နှာပြင် ၃၀%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ညာဘက် မျက်နှာပြင်အပြည့်"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"အပေါ်ဘက် မျက်နှာပြင်အပြည့်"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"အပေါ်ဘက် မျက်နှာပြင် ၇၀%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"အပေါ်ဘက် မျက်နှာပြင် ၅၀%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"အပေါ်ဘက် မျက်နှာပြင် ၃၀%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"အောက်ခြေ မျက်နှာပြင်အပြည့်"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> ပူဖောင်းကွက်အတွက် ဆက်တင်များ"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"အပိုများပြရန်"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"ပူဖေါင်းတန်းသို့ ပြန်ထည့်ရန်"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> မှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> နှင့် နောက်ထပ် <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ခုမှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ဘယ်ဘက်ထိပ်သို့ ရွှေ့ရန်"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ညာဘက်ထိပ်သို့ ရွှေ့ပါ"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ဘယ်အောက်ခြေသို့ ရွှေ့ရန်"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ညာအောက်ခြေသို့ ရွှေ့ပါ"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ဆက်တင်များ"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"ပူဖောင်းကွက် ပယ်ရန်"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"စကားဝိုင်းကို ပူဖောင်းကွက် မပြုလုပ်ပါနှင့်"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"ပူဖောင်းကွက် သုံး၍ ချတ်လုပ်ခြင်း"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"စကားဝိုင်းအသစ်များကို မျောနေသည့် သင်္ကေတများ သို့မဟုတ် ပူဖောင်းကွက်များအဖြစ် မြင်ရပါမည်။ ပူဖောင်းကွက်ကိုဖွင့်ရန် တို့ပါ။ ရွှေ့ရန် ၎င်းကို ဖိဆွဲပါ။"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"ပူဖောင်းကွက်ကို အချိန်မရွေး ထိန်းချုပ်ရန်"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"ဤအက်ပ်မှနေ၍ ပူဖောင်းများကို ပိတ်ရန်အတွက် \'စီမံရန်\' ကို တို့ပါ"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"လတ်တလော ပူဖောင်းကွက်များ မရှိပါ"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"လတ်တလော ပူဖောင်းကွက်များနှင့် ပိတ်လိုက်သော ပူဖောင်းကွက်များကို ဤနေရာတွင် မြင်ရပါမည်"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"ပူဖောင်းဖောက်သံ"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"စီမံရန်"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ပူဖောင်းကွက် ဖယ်လိုက်သည်။"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-my/strings_tv.xml b/libs/WindowManager/Shell/res/values-my/strings_tv.xml
new file mode 100644
index 000000000000..6d4d6f04b8f4
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-my/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ခေါင်းစဉ်မဲ့ အစီအစဉ်)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP ကိုပိတ်ပါ"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"မျက်နှာပြင် အပြည့်"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
new file mode 100644
index 000000000000..cd601ea54832
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Lukk"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Vis"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Innstillinger"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Meny"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> er i bilde-i-bilde"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Hvis du ikke vil at <xliff:g id="NAME">%s</xliff:g> skal bruke denne funksjonen, kan du trykke for å åpne innstillingene og slå den av."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Spill av"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Sett på pause"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Hopp til neste"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Hopp til forrige"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Endre størrelse"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen støtter ikke delt skjerm."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer kanskje ikke på en sekundær skjerm."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan ikke kjøres på sekundære skjermer."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Skilleelement for delt skjerm"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Utvid den venstre delen av skjermen til hele skjermen"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Sett størrelsen på den venstre delen av skjermen til 70 %"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sett størrelsen på den venstre delen av skjermen til 50 %"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Sett størrelsen på den venstre delen av skjermen til 30 %"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Utvid den høyre delen av skjermen til hele skjermen"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Utvid den øverste delen av skjermen til hele skjermen"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Sett størrelsen på den øverste delen av skjermen til 70 %"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Sett størrelsen på den øverste delen av skjermen til 50 %"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Sett størrelsen på den øverste delen av skjermen til 30 %"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Utvid den nederste delen av skjermen til hele skjermen"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Innstillinger for <xliff:g id="APP_NAME">%1$s</xliff:g>-bobler"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Overflyt"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Legg tilbake i stabelen"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> flere"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Flytt til øverst til venstre"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Flytt til øverst til høyre"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Flytt til nederst til venstre"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Flytt til nederst til høyre"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-innstillinger"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Lukk boblen"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ikke vis samtaler i bobler"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat med bobler"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nye samtaler vises som flytende ikoner eller bobler. Trykk for å åpne bobler. Dra for å flytte dem."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Kontrollér bobler når som helst"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Trykk på Administrer for å slå av bobler for denne appen"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ingen nylige bobler"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nylige bobler og avviste bobler vises her"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Boble"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen er avvist."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings_tv.xml b/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
new file mode 100644
index 000000000000..849ccda1e983
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-nb/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program uten tittel)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Lukk PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Fullskjerm"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
new file mode 100644
index 000000000000..0c68bab04a8e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"बन्द गर्नुहोस्"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"विस्तृत गर्नुहोस्"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"सेटिङहरू"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"मेनु"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> Picture-in-picture मा छ"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"तपाईं <xliff:g id="NAME">%s</xliff:g> ले सुविधा प्रयोग नगरोस् भन्ने चाहनुहुन्छ भने ट्याप गरेर सेटिङहरू खोल्नुहोस् र यसलाई निष्क्रिय पार्नुहोस्।"</string>
+ <string name="pip_play" msgid="3496151081459417097">"प्ले गर्नुहोस्"</string>
+ <string name="pip_pause" msgid="690688849510295232">"पज गर्नुहोस्"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"अर्कोमा जानुहोस्"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"अघिल्लोमा जानुहोस्"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदल्नुहोस्"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अनुप्रयोगले विभाजित-स्क्रिनलाई समर्थन गर्दैन।"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"यो अनुप्रयोगले सहायक प्रदर्शनमा काम नगर्नसक्छ।"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"अनुप्रयोगले सहायक प्रदर्शनहरूमा लञ्च सुविधालाई समर्थन गर्दैन।"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"विभाजित-स्क्रिन छुट्याउने"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"बायाँ भाग फुल स्क्रिन"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"बायाँ भाग ७०%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बायाँ भाग ५०%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"बायाँ भाग ३०%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"दायाँ भाग फुल स्क्रिन"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"माथिल्लो भाग फुल स्क्रिन"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"माथिल्लो भाग ७०%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"माथिल्लो भाग ५०%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"माथिल्लो भाग ३०%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"तल्लो भाग फुल स्क्रिन"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> का बबलसम्बन्धी सेटिङहरू"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ओभरफ्लो देखाउनुहोस्"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"स्ट्याकमा फेरि थप्नुहोस्"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> को <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> का <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> र थप <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"शीर्ष भागको बायाँतिर सार्नुहोस्"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"सिरानमा दायाँतिर सार्नुहोस्"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"पुछारमा बायाँतिर सार्नुहोस्"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"पुछारमा दायाँतिर सार्नुहोस्"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> का सेटिङहरू"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"बबल खारेज गर्नुहोस्"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"वार्तालाप बबलको रूपमा नदेखाइयोस्"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"बबलहरू प्रयोग गरी कुराकानी गर्नुहोस्"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"नयाँ वार्तालापहरू तैरने आइकन वा बबलका रूपमा देखिन्छन्। बबल खोल्न ट्याप गर्नुहोस्। बबल सार्न सो बबललाई ड्र्याग गर्नुहोस्।"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"जुनसुकै बेला बबलहरू नियन्त्रण गर्नुहोस्"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"यो एपबाट आएका बबलहरू अफ गर्न \"व्यवस्थापन गर्नुहोस्\" बटनमा ट्याप गर्नुहोस्"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"हालैका बबलहरू छैनन्"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"हालैका बबल र खारेज गरिएका बबलहरू यहाँ देखिने छन्"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"व्यवस्थापन गर्नुहोस्"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"बबल हटाइयो।"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings_tv.xml b/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
new file mode 100644
index 000000000000..fc0221e9befc
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ne/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(शीर्षकविहीन कार्यक्रम)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP लाई बन्द गर्नुहोस्"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"फुल स्क्रिन"</string>
+</resources>
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/drawable/system_bar_background.xml b/libs/WindowManager/Shell/res/values-night/colors.xml
index 66da21ca23f8..24b364043938 100644
--- a/packages/CarSystemUI/samples/sample3/rro/res/drawable/system_bar_background.xml
+++ b/libs/WindowManager/Shell/res/values-night/colors.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -14,8 +13,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
- <solid
- android:color="#404040"
- />
-</shape> \ No newline at end of file
+
+<resources>
+ <!-- Bubbles -->
+ <color name="bubbles_icon_tint">@color/GM2_grey_200</color>
+</resources> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
new file mode 100644
index 000000000000..2ead58661467
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Sluiten"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Uitvouwen"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Instellingen"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> is in scherm-in-scherm"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Als je niet wilt dat <xliff:g id="NAME">%s</xliff:g> deze functie gebruikt, tik je om de instellingen te openen en schakel je de functie uit."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Afspelen"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Onderbreken"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Doorgaan naar volgende"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Teruggaan naar vorige"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Formaat aanpassen"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App biedt geen ondersteuning voor gesplitst scherm."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App werkt mogelijk niet op een secundair scherm."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App kan niet op secundaire displays worden gestart."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Scheiding voor gesplitst scherm"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Linkerscherm op volledig scherm"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Linkerscherm 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Linkerscherm 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Linkerscherm 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Rechterscherm op volledig scherm"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Bovenste scherm op volledig scherm"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Bovenste scherm 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bovenste scherm 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Bovenste scherm 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Onderste scherm op volledig scherm"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Instellingen voor <xliff:g id="APP_NAME">%1$s</xliff:g>-bubbels"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Overloop"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Weer toevoegen aan stack"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g> en nog <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Naar linksboven verplaatsen"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Naar rechtsboven verplaatsen"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Naar linksonder verplaatsen"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Naar rechtsonder verplaatsen"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Instellingen voor <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Bubbel sluiten"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Gesprekken niet in bubbels weergeven"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatten met bubbels"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nieuwe gesprekken worden weergegeven als zwevende iconen of \'bubbels\'. Tik om een bubbel te openen. Sleep om de bubbel te verplaatsen."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Beheer bubbels wanneer je wilt"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tik op Beheren om bubbels van deze app uit te schakelen"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Geen recente bubbels"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recente bubbels en gesloten bubbels worden hier weergegeven"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bubbel"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Beheren"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubbel gesloten."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings_tv.xml b/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
new file mode 100644
index 000000000000..281eaf08329e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-nl/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Naamloos programma)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP sluiten"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Volledig scherm"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
new file mode 100644
index 000000000000..2b27c9900130
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"ବଢ଼ାନ୍ତୁ"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"ସେଟିଂସ୍"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"ମେନୁ"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> \"ଛବି-ଭିତରେ-ଛବି\"ରେ ଅଛି"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"ଏହି ବୈଶିଷ୍ଟ୍ୟ <xliff:g id="NAME">%s</xliff:g> ବ୍ୟବହାର ନକରିବାକୁ ଯଦି ଆପଣ ଚାହାଁନ୍ତି, ସେଟିଙ୍ଗ ଖୋଲିବାକୁ ଟାପ୍‍ କରନ୍ତୁ ଏବଂ ଏହା ଅଫ୍‍ କରିଦିଅନ୍ତୁ।"</string>
+ <string name="pip_play" msgid="3496151081459417097">"ପ୍ଲେ କରନ୍ତୁ"</string>
+ <string name="pip_pause" msgid="690688849510295232">"ପଜ୍‍ କରନ୍ତୁ"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"ପରବର୍ତ୍ତୀକୁ ଯାଆନ୍ତୁ"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"ପୂର୍ବବର୍ତ୍ତୀକୁ ଛାଡ଼ନ୍ତୁ"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ରିସାଇଜ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ଆପ୍‍ ସ୍ପ୍ଲିଟ୍‍-ସ୍କ୍ରୀନକୁ ସପୋର୍ଟ କରେ ନାହିଁ।"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍‍ କାମ ନକରିପାରେ।"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍‍ ଲଞ୍ଚ ସପୋର୍ଟ କରେ ନାହିଁ।"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"ସ୍ପ୍ଲିଟ୍‍-ସ୍କ୍ରୀନ ବିଭାଜକ"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ବାମ ପଟକୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍ କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ବାମ ପଟକୁ 70% କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ବାମ ପଟକୁ 50% କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ବାମ ପଟେ 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ଡାହାଣ ପଟକୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍ କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ଉପର ଆଡ଼କୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍ କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ଉପର ଆଡ଼କୁ 70% କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ଉପର ଆଡ଼କୁ 50% କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ଉପର ଆଡ଼କୁ 30% କରନ୍ତୁ"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ତଳ ଅଂଶର ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବବଲ୍‌ଗୁଡ଼ିକ ପାଇଁ ସେଟିଂସ୍"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ଓଭରଫ୍ଲୋ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"ଷ୍ଟାକରେ ପୁଣି ଯୋଗ କରନ୍ତୁ"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g>ରୁ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> ଏବଂ ଅଧିକ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>ଟିରୁ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ଉପର ବାମକୁ ନିଅନ୍ତୁ"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ଉପର-ଡାହାଣକୁ ନିଅନ୍ତୁ"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ତଳ ବାମକୁ ନିଅନ୍ତୁ"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ତଳ ଡାହାଣକୁ ନିଅନ୍ତୁ"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ସେଟିଂସ୍"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"ବବଲ୍ ଖାରଜ କରନ୍ତୁ"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ବାର୍ତ୍ତାଳାପକୁ ବବଲ୍ କରନ୍ତୁ ନାହିଁ"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"ବବଲଗୁଡ଼ିକୁ ବ୍ୟବହାର କରି ଚାଟ୍ କରନ୍ତୁ"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"ନୂଆ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ଫ୍ଲୋଟିଂ ଆଇକନ୍ କିମ୍ବା ବବଲ୍ ଭାବେ ଦେଖାଯିବ। ବବଲ୍ ଖୋଲିବାକୁ ଟାପ୍ କରନ୍ତୁ। ଏହାକୁ ମୁଭ୍ କରିବାକୁ ଟାଣନ୍ତୁ।"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"ଯେ କୌଣସି ସମୟରେ ବବଲଗୁଡ଼ିକ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"ଏହି ଆପର ବବଲଗୁଡ଼ିକ ବନ୍ଦ କରିବା ପାଇଁ \'ପରିଚାଳନା କରନ୍ତୁ\' ବଟନରେ ଟାପ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ବର୍ତ୍ତମାନ କୌଣସି ବବଲ୍ ନାହିଁ"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ବର୍ତ୍ତମାନର ଏବଂ ଖାରଜ କରାଯାଇଥିବା ବବଲଗୁଡ଼ିକ ଏଠାରେ ଦେଖାଯିବ"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"ବବଲ୍"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"ପରିଚାଳନା କରନ୍ତୁ"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ବବଲ୍ ଖାରଜ କରାଯାଇଛି।"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-or/strings_tv.xml b/libs/WindowManager/Shell/res/values-or/strings_tv.xml
new file mode 100644
index 000000000000..b57dd934fc7d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-or/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(କୌଣସି ଟାଇଟଲ୍‍ ପ୍ରୋଗ୍ରାମ୍‍ ନାହିଁ)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP ବନ୍ଦ କରନ୍ତୁ"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
new file mode 100644
index 000000000000..b9cb65edc1aa
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"ਬੰਦ ਕਰੋ"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"ਵਿਸਤਾਰ ਕਰੋ"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"ਸੈਟਿੰਗਾਂ"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"ਮੀਨੂ"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ਤਸਵੀਰ-ਅੰਦਰ-ਤਸਵੀਰ ਵਿੱਚ ਹੈ"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"ਜੇਕਰ ਤੁਸੀਂ ਨਹੀਂ ਚਾਹੁੰਦੇ ਕਿ <xliff:g id="NAME">%s</xliff:g> ਐਪ ਇਸ ਵਿਸ਼ੇਸ਼ਤਾ ਦੀ ਵਰਤੋਂ ਕਰੇ, ਤਾਂ ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ ਅਤੇ ਇਸਨੂੰ ਬੰਦ ਕਰੋ।"</string>
+ <string name="pip_play" msgid="3496151081459417097">"ਚਲਾਓ"</string>
+ <string name="pip_pause" msgid="690688849510295232">"ਵਿਰਾਮ ਦਿਓ"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"ਅਗਲੇ \'ਤੇ ਜਾਓ"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"ਪਿਛਲੇ \'ਤੇ ਜਾਓ"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ਆਕਾਰ ਬਦਲੋ"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇ \'ਤੇ ਕੰਮ ਨਾ ਕਰੇ।"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇਆਂ \'ਤੇ ਲਾਂਚ ਕਰਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਡਿਵਾਈਡਰ"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ਖੱਬੇ ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ਖੱਬੇ 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ਖੱਬੇ 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ਖੱਬੇ 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ਸੱਜੇ ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ਉੱਪਰ ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ਉੱਪਰ 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ਉੱਪਰ 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ਉੱਪਰ 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"ਹੇਠਾਂ ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਬਬਲ ਲਈ ਸੈਟਿੰਗਾਂ"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ਓਵਰਫ਼ਲੋ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"ਸਟੈਕ ਵਿੱਚ ਵਾਪਸ ਸ਼ਾਮਲ ਕਰੋ"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਅਤੇ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ਹੋਰਾਂ ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ਉੱਪਰ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ਉੱਪਰ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ਹੇਠਾਂ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ਹੇਠਾਂ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ਸੈਟਿੰਗਾਂ"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕਰੋ"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ਗੱਲਬਾਤ \'ਤੇ ਬਬਲ ਨਾ ਲਾਓ"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"ਬਬਲ ਵਰਤਦੇ ਹੋਏ ਚੈਟ ਕਰੋ"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"ਨਵੀਆਂ ਗੱਲਾਂਬਾਤਾਂ ਫਲੋਟਿੰਗ ਪ੍ਰਤੀਕਾਂ ਜਾਂ ਬਬਲ ਦੇ ਰੂਪ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ। ਬਬਲ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਇਸਨੂੰ ਲਿਜਾਣ ਲਈ ਘਸੀਟੋ।"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"ਬਬਲ ਨੂੰ ਕਿਸੇ ਵੇਲੇ ਵੀ ਕੰਟਰੋਲ ਕਰੋ"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"ਇਸ ਐਪ \'ਤੇ ਬਬਲ ਬੰਦ ਕਰਨ ਲਈ \'ਪ੍ਰਬੰਧਨ ਕਰੋ\' \'ਤੇ ਟੈਪ ਕਰੋ"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ਕੋਈ ਹਾਲੀਆ ਬਬਲ ਨਹੀਂ"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ਹਾਲੀਆ ਬਬਲ ਅਤੇ ਖਾਰਜ ਕੀਤੇ ਬਬਲ ਇੱਥੇ ਦਿਸਣਗੇ"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"ਬੁਲਬੁਲਾ"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕੀਤਾ ਗਿਆ।"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings_tv.xml b/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
new file mode 100644
index 000000000000..028a0a0b4708
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-pa/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ਸਿਰਲੇਖ-ਰਹਿਤ ਪ੍ਰੋਗਰਾਮ)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP ਬੰਦ ਕਰੋ"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
new file mode 100644
index 000000000000..bc473b57fd21
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Zamknij"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Rozwiń"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Ustawienia"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"Aplikacja <xliff:g id="NAME">%s</xliff:g> działa w trybie obraz w obrazie"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Jeśli nie chcesz, by aplikacja <xliff:g id="NAME">%s</xliff:g> korzystała z tej funkcji, otwórz ustawienia i wyłącz ją."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Odtwórz"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Wstrzymaj"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Dalej"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Wstecz"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Zmień rozmiar"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacja nie obsługuje dzielonego ekranu."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacja może nie działać na dodatkowym ekranie."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacja nie obsługuje uruchamiania na dodatkowych ekranach."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Linia dzielenia ekranu"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lewa część ekranu na pełnym ekranie"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% lewej części ekranu"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% lewej części ekranu"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% lewej części ekranu"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Prawa część ekranu na pełnym ekranie"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Górna część ekranu na pełnym ekranie"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% górnej części ekranu"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% górnej części ekranu"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% górnej części ekranu"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Dolna część ekranu na pełnym ekranie"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Ustawienia dymków aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Przepełnienie"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Dodaj ponownie do stosu"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikacji <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikacji <xliff:g id="APP_NAME">%2$s</xliff:g> i jeszcze <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Przenieś w lewy górny róg"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Przenieś w prawy górny róg"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Przenieś w lewy dolny róg"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Przenieś w prawy dolny róg"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – ustawienia"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Zamknij dymek"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nie wyświetlaj rozmowy jako dymka"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Czatuj, korzystając z dymków"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nowe rozmowy będą wyświetlane jako pływające ikony lub dymki. Kliknij, by otworzyć dymek. Przeciągnij, by go przenieść."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Zarządzaj dymkami w dowolnym momencie"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Kliknij Zarządzaj, aby wyłączyć dymki z tej aplikacji"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Brak ostatnich dymków"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Tutaj będą pojawiać się ostatnie i odrzucone dymki"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Dymek"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Zarządzaj"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Zamknięto dymek"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings_tv.xml b/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
new file mode 100644
index 000000000000..4522ea1dcc77
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-pl/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez tytułu)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Zamknij PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Pełny ekran"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
new file mode 100644
index 000000000000..612377d00f64
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Fechar"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Expandir"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Configurações"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> está em picture-in-picture"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Se você não quer que o app <xliff:g id="NAME">%s</xliff:g> use este recurso, toque para abrir as configurações e desativá-lo."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Reproduzir"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pausar"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Pular para a próxima"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Pular para a anterior"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"O app não é compatível com a inicialização em telas secundárias."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Divisor de tela"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lado esquerdo em tela cheia"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Esquerda a 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Esquerda a 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Esquerda a 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Lado direito em tela cheia"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Parte superior em tela cheia"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Parte superior a 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Parte superior a 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Parte superior a 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Parte inferior em tela cheia"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Configurações de balões do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menu flutuante"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Devolver à pilha"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> mais <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Mover para canto superior esquerdo"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mover para canto superior direito"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mover para canto inferior esquerdo"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mover para canto inferior direito"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Configurações de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Dispensar balão"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Não criar balões de conversa"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Converse usando balões"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controle os balões a qualquer momento"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Toque em \"Gerenciar\" para desativar os balões desse app"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nenhum balão recente"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Os balões recentes e dispensados aparecerão aqui"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bolha"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
new file mode 100644
index 000000000000..951babe7f06e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(programa sem título)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Fechar PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Tela cheia"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
new file mode 100644
index 000000000000..bbd233e0f3e9
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Fechar"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Expandir"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Definições"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"A app <xliff:g id="NAME">%s</xliff:g> está no modo de ecrã no ecrã"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Se não pretende que a app <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Reproduzir"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pausar"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Mudar para o seguinte"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Mudar para o anterior"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A app não é compatível com o ecrã dividido."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"A app pode não funcionar num ecrã secundário."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"A app não é compatível com o início em ecrãs secundários."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Divisor do ecrã dividido"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ecrã esquerdo inteiro"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"70% no ecrã esquerdo"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% no ecrã esquerdo"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% no ecrã esquerdo"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ecrã direito inteiro"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ecrã superior inteiro"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% no ecrã superior"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% no ecrã superior"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"30% no ecrã superior"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ecrã inferior inteiro"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Definições dos balões da app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menu adicional"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Adicionar novamente à pilha"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> do <xliff:g id="APP_NAME">%2$s</xliff:g> e mais<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>."</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Mover p/ parte sup. esquerda"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mover parte superior direita"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mover p/ parte infer. esquerda"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mover parte inferior direita"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Definições de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignorar balão"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Não apresentar a conversa em balões"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Converse no chat através de balões"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"As novas conversas aparecem como ícones flutuantes ou balões. Toque para abrir o balão. Arraste para o mover."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controle os balões em qualquer altura"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Toque em Gerir para desativar os balões desta app."</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nenhum balão recente"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Os balões recentes e ignorados vão aparecer aqui."</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Balão"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Gerir"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão ignorado."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
new file mode 100644
index 000000000000..05d976c2a095
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Sem título do programa)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Fechar PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Ecrã inteiro"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
new file mode 100644
index 000000000000..612377d00f64
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Fechar"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Expandir"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Configurações"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> está em picture-in-picture"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Se você não quer que o app <xliff:g id="NAME">%s</xliff:g> use este recurso, toque para abrir as configurações e desativá-lo."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Reproduzir"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pausar"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Pular para a próxima"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Pular para a anterior"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"O app não é compatível com a inicialização em telas secundárias."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Divisor de tela"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Lado esquerdo em tela cheia"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Esquerda a 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Esquerda a 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Esquerda a 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Lado direito em tela cheia"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Parte superior em tela cheia"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Parte superior a 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Parte superior a 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Parte superior a 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Parte inferior em tela cheia"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Configurações de balões do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Menu flutuante"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Devolver à pilha"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> mais <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Mover para canto superior esquerdo"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mover para canto superior direito"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mover para canto inferior esquerdo"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mover para canto inferior direito"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Configurações de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Dispensar balão"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Não criar balões de conversa"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Converse usando balões"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controle os balões a qualquer momento"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Toque em \"Gerenciar\" para desativar os balões desse app"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nenhum balão recente"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Os balões recentes e dispensados aparecerão aqui"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bolha"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings_tv.xml b/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
new file mode 100644
index 000000000000..951babe7f06e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-pt/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(programa sem título)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Fechar PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Tela cheia"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
new file mode 100644
index 000000000000..a31b8a1ab704
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Închideți"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Extindeți"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Setări"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Meniu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> este în modul picture-in-picture"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Dacă nu doriți ca <xliff:g id="NAME">%s</xliff:g> să utilizeze această funcție, atingeți pentru a deschide setările și dezactivați-o."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Redați"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Întrerupeți"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Treceți la următorul"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Treceți la cel anterior"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionați"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplicația nu acceptă ecranul împărțit."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Este posibil ca aplicația să nu funcționeze pe un ecran secundar."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplicația nu acceptă lansare pe ecrane secundare."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Separator pentru ecranul împărțit"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Partea stângă pe ecran complet"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Partea stângă: 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Partea stângă: 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Partea stângă: 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Partea dreaptă pe ecran complet"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Partea de sus pe ecran complet"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Partea de sus: 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Partea de sus: 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Partea de sus: 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Partea de jos pe ecran complet"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Setări pentru baloanele <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Suplimentar"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Adăugați înapoi în stivă"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g> și încă <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Mutați în stânga sus"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mutați în dreapta sus"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mutați în stânga jos"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mutați în dreapta jos"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Setări <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Închideți balonul"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nu afișați conversația în balon"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat cu baloane"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Conversațiile noi apar ca pictograme flotante sau baloane. Atingeți pentru a deschide balonul. Trageți pentru a-l muta."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controlați oricând baloanele"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Atingeți Gestionați pentru a dezactiva baloanele din această aplicație"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nu există baloane recente"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Baloanele recente și baloanele respinse vor apărea aici"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionați"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balonul a fost respins."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings_tv.xml b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
new file mode 100644
index 000000000000..0dc28f0d408b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program fără titlu)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Închideți PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Ecran complet"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
new file mode 100644
index 000000000000..849ab288761b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Закрыть"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Развернуть"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Настройки"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> находится в режиме \"Картинка в картинке\""</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Чтобы отключить эту функцию для приложения \"<xliff:g id="NAME">%s</xliff:g>\", перейдите в настройки."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Воспроизвести"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Приостановить"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Перейти к следующему"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Перейти к предыдущему"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Изменить размер"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложение не поддерживает разделение экрана."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Приложение может не работать на дополнительном экране"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Приложение не поддерживает запуск на дополнительных экранах"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Разделитель экрана"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Левый во весь экран"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Левый на 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левый на 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Левый на 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Правый во весь экран"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Верхний во весь экран"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Верхний на 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхний на 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Верхний на 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Нижний во весь экран"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Настройки всплывающих чатов от приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Дополнительное меню"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Добавить обратно в стек"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> из приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> от приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" и ещё <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Перенести в левый верхний угол"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Перенести в правый верхний угол"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Перенести в левый нижний угол"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Перенести в правый нижний угол"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: настройки"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Скрыть всплывающий чат"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не показывать всплывающий чат для разговора"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Всплывающие чаты"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Новые разговоры будут появляться в виде плавающих значков, или всплывающих чатов. Чтобы открыть чат, нажмите на него, а чтобы переместить – перетащите."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Всплывающие чаты"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Чтобы отключить всплывающие чаты из этого приложения, нажмите \"Настроить\"."</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Нет недавних всплывающих чатов"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Здесь будут появляться недавние и скрытые всплывающие чаты."</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Всплывающая подсказка"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Настроить"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Всплывающий чат закрыт."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings_tv.xml b/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
new file mode 100644
index 000000000000..238d2d5e4f42
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ru/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Без названия)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"\"Кадр в кадре\" – выйти"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Во весь экран"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
new file mode 100644
index 000000000000..35c8388dc134
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"වසන්න"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"දිග හරින්න"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"සැකසීම්"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"මෙනුව"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> පින්තූරය-තුළ-පින්තූරය තුළ වේ"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"ඔබට <xliff:g id="NAME">%s</xliff:g> මෙම විශේෂාංගය භාවිත කිරීමට අවශ්‍ය නැති නම්, සැකසීම් විවෘත කිරීමට තට්ටු කර එය ක්‍රියාවිරහිත කරන්න."</string>
+ <string name="pip_play" msgid="3496151081459417097">"ධාවනය කරන්න"</string>
+ <string name="pip_pause" msgid="690688849510295232">"විරාම කරන්න"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"ඊළඟ එකට පනින්න"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"පෙර එකට පනින්න"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ප්‍රතිප්‍රමාණ කරන්න"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"යෙදුම බෙදුණු-තිරය සඳහා සහාය නොදක්වයි."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"යෙදුම ද්විතියික සංදර්ශකයක ක්‍රියා නොකළ හැකිය."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"යෙදුම ද්විතීයික සංදර්ශක මත දියත් කිරීම සඳහා සහාය නොදක්වයි."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"බෙදුම්-තිර වෙන්කරණය"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"වම් පූර්ණ තිරය"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"වම් 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"වම් 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"වම් 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"දකුණු පූර්ණ තිරය"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ඉහළම පූර්ණ තිරය"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ඉහළම 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ඉහළම 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ඉහළම 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"පහළ පූර්ණ තිරය"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> බුබුළු සඳහා සැකසීම්"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"පිටාර යාම"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"අට්ටිය වෙත ආපසු එක් කරන්න"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> වෙතින් <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> වෙතින් <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> සහ තවත් <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ක්"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ඉහළ වමට ගෙන යන්න"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ඉහළ දකුණට ගෙන යන්න"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"පහළ වමට ගෙන යන්න"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"පහළ දකුණට ගෙන යන්න"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> සැකසීම්"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"බුබුලු ඉවත ලන්න"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"සංවාදය බුබුලු නොදමන්න"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"බුබුලු භාවිතයෙන් කතාබහ කරන්න"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"නව සංවාද පාවෙන අයිකන හෝ බුබුලු ලෙස දිස් වේ. බුබුල විවෘත කිරීමට තට්ටු කරන්න. එය ගෙන යාමට අදින්න."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"ඕනෑම වේලාවක බුබුලු පාලනය කරන්න"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"මෙම යෙදුමෙන් බුබුලු ක්‍රියාවිරහිත කිරීමට කළමනාකරණය කරන්න තට්ටු කරන්න"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"මෑත බුබුලු නැත"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"මෑත බුබුලු සහ ඉවත ලූ බුබුලු මෙහි දිස් වනු ඇත"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"බුබුළු"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"කළමනා කරන්න"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"බුබුල ඉවත දමා ඇත."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-si/strings_tv.xml b/libs/WindowManager/Shell/res/values-si/strings_tv.xml
new file mode 100644
index 000000000000..4d8d97fff865
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-si/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(මාතෘකාවක් නැති වැඩසටහන)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP වසන්න"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"සම්පූර්ණ තිරය"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
new file mode 100644
index 000000000000..b3588944cece
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Zavrieť"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Rozbaliť"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Nastavenia"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Ponuka"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> je v režime obraz v obraze"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ak nechcete, aby aplikácia <xliff:g id="NAME">%s</xliff:g> používala túto funkciu, klepnutím otvorte nastavenia a vypnite ju."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Prehrať"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pozastaviť"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Preskočiť na ďalšie"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskočiť na predchádzajúce"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Zmeniť veľkosť"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikácia nepodporuje rozdelenú obrazovku."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikácia nemusí fungovať na sekundárnej obrazovke."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikácia nepodporuje spúšťanie na sekundárnych obrazovkách."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Rozdeľovač obrazovky"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ľavá – na celú obrazovku"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ľavá – 70 %"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ľavá – 50 %"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ľavá – 30 %"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pravá– na celú obrazovku"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Horná – na celú obrazovku"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Horná – 70 %"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Horná – 50 %"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Horná – 30 %"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Dolná – na celú obrazovku"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Nastavenia bublín aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Rozšírená ponuka"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Pridať späť do zásobníka"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikácie <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikácie <xliff:g id="APP_NAME">%2$s</xliff:g> a ďalšie (<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>)"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Presunúť doľava nahor"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Presunúť doprava nahor"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Presunúť doľava nadol"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Presunúť doprava nadol"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Nastavenia aplikácie <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Zavrieť bublinu"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nezobrazovať konverzáciu ako bublinu"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Čet pomocou bublín"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nové konverzácie sa zobrazujú ako plávajúce ikony či bubliny. Bublinu otvoríte klepnutím. Premiestnite ju presunutím."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Nastavenie bublín môžete kedykoľvek zmeniť"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Bubliny pre túto aplikáciu môžete vypnúť klepnutím na Spravovať"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Žiadne nedávne bubliny"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Tu sa budú zobrazovať nedávne a zavreté bubliny"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovať"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina bola zavretá."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings_tv.xml b/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
new file mode 100644
index 000000000000..1f9ee160b779
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sk/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program bez názvu)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Zavrieť režim PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Celá obrazovka"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
new file mode 100644
index 000000000000..d3b2c8177fe3
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Zapri"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Razširi"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Nastavitve"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Meni"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> je v načinu slika v sliki"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Če ne želite, da aplikacija <xliff:g id="NAME">%s</xliff:g> uporablja to funkcijo, se dotaknite, da odprete nastavitve, in funkcijo izklopite."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Predvajaj"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Začasno ustavi"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Preskoči na naslednjega"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskoči na prejšnjega"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Spremeni velikost"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podpira načina razdeljenega zaslona."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija morda ne bo delovala na sekundarnem zaslonu."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podpira zagona na sekundarnih zaslonih."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Razdelilnik zaslonov"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Levi v celozaslonski način"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Levi 70 %"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Levi 50 %"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Levi 30 %"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Desni v celozaslonski način"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Zgornji v celozaslonski način"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Zgornji 70 %"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Zgornji 50 %"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Zgornji 30 %"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Spodnji v celozaslonski način"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Nastavitve za oblačke aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Prelivanje"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Dodaj nazaj v sklad"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> in toliko drugih: <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Premakni zgoraj levo"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Premakni zgoraj desno"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Premakni spodaj levo"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Premakni spodaj desno"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Nastavitve za <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Opusti oblaček"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Pogovora ne prikaži v oblačku"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Klepet z oblački"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Novi pogovori so prikazani kot lebdeče ikone ali oblački. Če želite odpreti oblaček, se ga dotaknite. Če ga želite premakniti, ga povlecite."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Upravljanje oblačkov"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Dotaknite se »Upravljanje«, da izklopite oblačke iz te aplikacije"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ni nedavnih oblačkov"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Tukaj bodo prikazani tako nedavni kot tudi opuščeni oblački"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Mehurček"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Upravljanje"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Oblaček je bil opuščen."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings_tv.xml b/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
new file mode 100644
index 000000000000..88639ee071fa
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sl/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program brez naslova)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Zapri način PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Celozaslonsko"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
new file mode 100644
index 000000000000..61b6c3668647
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Mbyll"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Zgjero"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Cilësimet"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menyja"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> është në figurë brenda figurës"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Nëse nuk dëshiron që <xliff:g id="NAME">%s</xliff:g> ta përdorë këtë funksion, trokit për të hapur cilësimet dhe për ta çaktivizuar."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Luaj"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Ndërprit"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Kalo te tjetra"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Kalo tek e mëparshmja"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ndrysho përmasat"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacioni nuk mbështet ekranin e ndarë."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacioni mund të mos funksionojë në një ekran dytësor."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacioni nuk mbështet nisjen në ekrane dytësore."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Ndarësi i ekranit të ndarë"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ekrani i plotë majtas"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Majtas 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Majtas 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Majtas 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ekrani i plotë djathtas"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ekrani i plotë lart"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Lart 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Lart 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Lart 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ekrani i plotë poshtë"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Cilësimet për flluskat e <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Tejkalo"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Shto përsëri te stiva"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> nga <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> nga <xliff:g id="APP_NAME">%2$s</xliff:g> dhe <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> të tjera"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Zhvendos lart majtas"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Lëviz lart djathtas"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Zhvendos poshtë majtas"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Lëvize poshtë djathtas"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Cilësimet e <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Hiqe flluskën"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Mos e vendos bisedën në flluskë"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Bisedo duke përdorur flluskat"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Bisedat e reja shfaqen si ikona pluskuese ose flluska. Trokit për të hapur flluskën. Zvarrit për ta zhvendosur."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Kontrollo flluskat në çdo moment"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Trokit \"Menaxho\" për të çaktivizuar flluskat nga ky aplikacion"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nuk ka flluska të fundit"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Flluskat e fundit dhe flluskat e hequra do të shfaqen këtu"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Flluskë"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Menaxho"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Flluska u hoq."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings_tv.xml b/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
new file mode 100644
index 000000000000..e81275ed30e1
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sq/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Program pa titull)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Mbyll PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Ekrani i plotë"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
new file mode 100644
index 000000000000..32de8a3e8cde
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Затвори"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Прошири"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Подешавања"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Мени"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> је слика у слици"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ако не желите да <xliff:g id="NAME">%s</xliff:g> користи ову функцију, додирните да бисте отворили подешавања и искључили је."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Пусти"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Паузирај"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Пређи на следеће"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Пређи на претходно"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Промените величину"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликација не подржава подељени екран."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликација можда неће функционисати на секундарном екрану."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Апликација не подржава покретање на секундарним екранима."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Разделник подељеног екрана"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Режим целог екрана за леви екран"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Леви екран 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Леви екран 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Леви екран 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Режим целог екрана за доњи екран"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Режим целог екрана за горњи екран"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горњи екран 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горњи екран 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Горњи екран 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Режим целог екрана за доњи екран"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Подешавања за <xliff:g id="APP_NAME">%1$s</xliff:g> облачиће"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Преклапање"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Додај поново у групу"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> из апликације <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> из апликације <xliff:g id="APP_NAME">%2$s</xliff:g> и још <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Премести горе лево"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Премести горе десно"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Премести доле лево"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Премести доле десно"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Подешавања за <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Одбаци облачић"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не користи облачиће за конверзацију"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Ћаскајте у облачићима"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Нове конверзације се приказују као плутајуће иконе или облачићи. Додирните да бисте отворили облачић. Превуците да бисте га преместили."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Контролишите облачиће у било ком тренутку"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Додирните Управљајте да бисте искључили облачиће из ове апликације"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Нема недавних облачића"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Овде се приказују недавни и одбачени облачићи"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Облачић"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Управљајте"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Облачић је одбачен."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings_tv.xml b/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
new file mode 100644
index 000000000000..a06da11bd00d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sr/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програм без наслова)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Затвори PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Цео екран"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
new file mode 100644
index 000000000000..2ec7944d42cb
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Stäng"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Utöka"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Inställningar"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Meny"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> visas i bild-i-bild"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Om du inte vill att den här funktionen används i <xliff:g id="NAME">%s</xliff:g> öppnar du inställningarna genom att trycka. Sedan inaktiverar du funktionen."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Spela upp"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pausa"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Hoppa till nästa"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Hoppa till föregående"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ändra storlek"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen har inte stöd för delad skärm."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen kanske inte fungerar på en sekundär skärm."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan inte köras på en sekundär skärm."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Avdelare för delad skärm"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Helskärm på vänster skärm"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Vänster 70 %"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vänster 50 %"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vänster 30 %"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Helskärm på höger skärm"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Helskärm på övre skärm"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Övre 70 %"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Övre 50 %"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Övre 30 %"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Helskärm på nedre skärm"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Inställningar för <xliff:g id="APP_NAME">%1$s</xliff:g>-bubblor"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Fler menyalternativ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Lägg tillbaka på stack"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> från <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> från <xliff:g id="APP_NAME">%2$s</xliff:g> och <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> fler"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Flytta högst upp till vänster"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Flytta högst upp till höger"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Flytta längst ned till vänster"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Flytta längst ned till höger"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Inställningar för <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Stäng bubbla"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Visa inte konversationen i bubblor"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatta med bubblor"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Nya konversationer visas som flytande ikoner, så kallade bubblor. Tryck på bubblan om du vill öppna den. Dra den om du vill flytta den."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Styr bubblor när som helst"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Tryck på Hantera för att stänga av bubblor från den här appen"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Inga nya bubblor"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"De senaste bubblorna och ignorerade bubblor visas här"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bubbla"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Hantera"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bubblan ignorerades."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings_tv.xml b/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
new file mode 100644
index 000000000000..da0b121f509d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sv/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Namnlöst program)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Stäng PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Helskärm"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
new file mode 100644
index 000000000000..5815d5e4ed0a
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Funga"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Panua"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Mipangilio"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menyu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> iko katika hali ya picha ndani ya picha nyingine"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Ikiwa hutaki <xliff:g id="NAME">%s</xliff:g> itumie kipengele hiki, gusa ili ufungue mipangilio na uizime."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Cheza"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Sitisha"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Ruka ufikie inayofuata"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Ruka ufikie iliyotangulia"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Badilisha ukubwa"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programu haiwezi kutumia skrini iliyogawanywa."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Huenda programu isifanye kazi kwenye dirisha lingine."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Programu hii haiwezi kufunguliwa kwenye madirisha mengine."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Kitenganishi cha skrini inayogawanywa"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Skrini nzima ya kushoto"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kushoto 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kushoto 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kushoto 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Skrini nzima ya kulia"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Skrini nzima ya juu"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Juu 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Juu 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Juu 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Skrini nzima ya chini"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Mipangilio ya viputo vya <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Vipengee vya ziada"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Rejesha kwenye rafu"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kutoka kwa <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kutoka kwa <xliff:g id="APP_NAME">%2$s</xliff:g> na nyingine<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Sogeza juu kushoto"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Sogeza juu kulia"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Sogeza chini kushoto"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Sogeza chini kulia"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Mipangilio ya <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Ondoa kiputo"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Usiweke viputo kwenye mazungumzo"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Piga gumzo ukitumia viputo"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Mazungumzo mapya huonekena kama aikoni au viputo vinavyoelea. Gusa ili ufungue kiputo. Buruta ili ukisogeze."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Dhibiti viputo wakati wowote"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Gusa Dhibiti ili uzime viputo kwenye programu hii"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Hakuna viputo vya hivi majuzi"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Viputo vya hivi karibuni na vile vilivyoondolewa vitaonekana hapa"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Kiputo"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Dhibiti"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Umeondoa kiputo."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings_tv.xml b/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
new file mode 100644
index 000000000000..96195230cb36
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-sw/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Programu isiyo na jina)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Funga PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Skrini nzima"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
new file mode 100644
index 000000000000..81066ffa874d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"மூடு"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"விரி"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"அமைப்புகள்"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"மெனு"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> தற்போது பிக்ச்சர்-இன்-பிக்ச்சரில் உள்ளது"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> இந்த அம்சத்தைப் பயன்படுத்த வேண்டாம் என நினைத்தால் இங்கு தட்டி அமைப்புகளைத் திறந்து இதை முடக்கவும்."</string>
+ <string name="pip_play" msgid="3496151081459417097">"இயக்கு"</string>
+ <string name="pip_pause" msgid="690688849510295232">"இடைநிறுத்து"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"அடுத்ததற்குச் செல்"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"முந்தையதற்குச் செல்"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"அளவு மாற்று"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"திரையைப் பிரிப்பதைப் ஆப்ஸ் ஆதரிக்கவில்லை."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"இரண்டாம்நிலைத் திரையில் ஆப்ஸ் வேலை செய்யாமல் போகக்கூடும்."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"இரண்டாம்நிலைத் திரைகளில் பயன்பாட்டைத் தொடங்க முடியாது."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"திரையைப் பிரிக்கும் பிரிப்பான்"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"இடது புறம் முழுத் திரை"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"இடது புறம் 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"இடது புறம் 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"இடது புறம் 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"வலது புறம் முழுத் திரை"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"மேற்புறம் முழுத் திரை"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"மேலே 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"மேலே 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"மேலே 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"கீழ்ப்புறம் முழுத் திரை"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> குமிழ்களுக்கான அமைப்புகள்"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ஓவர்ஃப்லோ"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"மீண்டும் ஸ்டேக்கில் சேர்க்கவும்"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> இலிருந்து <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> மற்றும் மேலும் <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ஆப்ஸிலிருந்து வந்துள்ள அறிவிப்பு: <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"மேலே இடப்புறமாக நகர்த்து"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"மேலே வலப்புறமாக நகர்த்து"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"கீழே இடப்புறமாக நகர்த்து"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"கீழே வலதுபுறமாக நகர்த்து"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> அமைப்புகள்"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"குமிழை அகற்று"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"உரையாடலைக் குமிழாக்காதே"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"குமிழ்களைப் பயன்படுத்தி அரட்டையடியுங்கள்"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"புதிய உரையாடல்கள் மிதக்கும் ஐகான்களாகவோ குமிழ்களாகவோ தோன்றும். குமிழைத் திறக்க தட்டவும். நகர்த்த இழுக்கவும்."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"குமிழ்களை எப்போது வேண்டுமானாலும் கட்டுப்படுத்தலாம்"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"இந்த ஆப்ஸிலிருந்து வரும் குமிழ்களை முடக்க, நிர்வகி என்பதைத் தட்டவும்"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"சமீபத்திய குமிழ்கள் இல்லை"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"சமீபத்திய குமிழ்களும் நிராகரிக்கப்பட்ட குமிழ்களும் இங்கே தோன்றும்"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"பபிள்"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"நிர்வகி"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"குமிழ் நிராகரிக்கப்பட்டது."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings_tv.xml b/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
new file mode 100644
index 000000000000..f246069391fa
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ta/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(தலைப்பு இல்லை)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIPஐ மூடு"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"முழுத்திரை"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
new file mode 100644
index 000000000000..0d166d87f5c4
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"మూసివేయి"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"విస్తరింపజేయి"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"సెట్టింగ్‌లు"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"మెనూ"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> చిత్రంలో చిత్రం రూపంలో ఉంది"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ఈ లక్షణాన్ని ఉపయోగించకూడదు అని మీరు అనుకుంటే, సెట్టింగ్‌లను తెరవడానికి ట్యాప్ చేసి, దీన్ని ఆఫ్ చేయండి."</string>
+ <string name="pip_play" msgid="3496151081459417097">"ప్లే చేయి"</string>
+ <string name="pip_pause" msgid="690688849510295232">"పాజ్ చేయి"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"దాటవేసి తర్వాత దానికి వెళ్లు"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"దాటవేసి మునుపటి దానికి వెళ్లు"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"పరిమాణం మార్చు"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"అనువర్తనంలో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ప్రత్యామ్నాయ డిస్‌ప్లేలో యాప్ పని చేయకపోవచ్చు."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ప్రత్యామ్నాయ డిస్‌ప్లేల్లో ప్రారంభానికి యాప్ మద్దతు లేదు."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"విభజన స్క్రీన్ విభాగిని"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"ఎడమవైపు పూర్తి స్క్రీన్"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ఎడమవైపు 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ఎడమవైపు 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ఎడమవైపు 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"కుడివైపు పూర్తి స్క్రీన్"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ఎగువ పూర్తి స్క్రీన్"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ఎగువ 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ఎగువ 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ఎగువ 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"దిగువ పూర్తి స్క్రీన్"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> బబుల్స్ సెట్టింగ్‌లు"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"ఓవర్‌ఫ్లో"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"స్ట్యాక్‌కు తిరిగి జోడించండి"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> మరియు మరో <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ఎగువ ఎడమవైపునకు జరుపు"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ఎగువ కుడివైపునకు జరుపు"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"దిగువ ఎడమవైపునకు తరలించు"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"దిగవు కుడివైపునకు జరుపు"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> సెట్టింగ్‌లు"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"బబుల్‌ను విస్మరించు"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"సంభాషణను బబుల్ చేయవద్దు"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"బబుల్స్‌ను ఉపయోగించి చాట్ చేయండి"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"కొత్త సంభాషణలు తేలియాడే చిహ్నాలుగా లేదా బబుల్స్ లాగా కనిపిస్తాయి. బబుల్‌ని తెరవడానికి నొక్కండి. తరలించడానికి లాగండి."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"బబుల్స్‌ను ఎప్పుడైనా నియంత్రించండి"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"ఈ యాప్ నుండి వచ్చే బబుల్స్‌ను ఆఫ్ చేయడానికి మేనేజ్ బటన్‌ను ట్యాప్ చేయండి"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ఇటీవలి బబుల్స్ ఏవీ లేవు"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ఇటీవలి బబుల్స్ మరియు తీసివేసిన బబుల్స్ ఇక్కడ కనిపిస్తాయి"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"బబుల్"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"మేనేజ్ చేయండి"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"బబుల్ విస్మరించబడింది."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-te/strings_tv.xml b/libs/WindowManager/Shell/res/values-te/strings_tv.xml
new file mode 100644
index 000000000000..f3019945010c
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-te/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(శీర్షిక లేని ప్రోగ్రామ్)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIPని మూసివేయి"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"పూర్తి స్క్రీన్"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
new file mode 100644
index 000000000000..442c3ca58af0
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"ปิด"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"ขยาย"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"การตั้งค่า"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"เมนู"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> ใช้การแสดงภาพซ้อนภาพ"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"หากคุณไม่ต้องการให้ <xliff:g id="NAME">%s</xliff:g> ใช้ฟีเจอร์นี้ ให้แตะเพื่อเปิดการตั้งค่าแล้วปิดฟีเจอร์"</string>
+ <string name="pip_play" msgid="3496151081459417097">"เล่น"</string>
+ <string name="pip_pause" msgid="690688849510295232">"หยุดชั่วคราว"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"ข้ามไปรายการถัดไป"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"ข้ามไปรายการก่อนหน้า"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ปรับขนาด"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"แอปไม่สนับสนุนการแยกหน้าจอ"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"แอปอาจไม่ทำงานในจอแสดงผลรอง"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"แอปไม่รองรับการเรียกใช้ในจอแสดงผลรอง"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"เส้นแบ่งหน้าจอ"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"เต็มหน้าจอทางซ้าย"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"ซ้าย 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ซ้าย 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ซ้าย 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"เต็มหน้าจอทางขวา"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"เต็มหน้าจอด้านบน"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ด้านบน 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ด้านบน 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"ด้านบน 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"เต็มหน้าจอด้านล่าง"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"การตั้งค่าบับเบิล <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"รายการเพิ่มเติม"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"เพิ่มกลับไปที่สแต็ก"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g> และอีก <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> รายการ"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"ย้ายไปด้านซ้ายบน"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ย้ายไปด้านขวาบน"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ย้ายไปด้านซ้ายล่าง"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ย้ายไปด้านขาวล่าง"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"การตั้งค่า <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"ปิดบับเบิล"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ไม่ต้องแสดงการสนทนาเป็นบับเบิล"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"แชทโดยใช้บับเบิล"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"การสนทนาใหม่ๆ จะปรากฏเป็นไอคอนแบบลอยหรือบับเบิล แตะเพื่อเปิดบับเบิล ลากเพื่อย้ายที่"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"ควบคุมบับเบิลได้ทุกเมื่อ"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"แตะ \"จัดการ\" เพื่อปิดบับเบิลจากแอปนี้"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ไม่มีบับเบิลเมื่อเร็วๆ นี้"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"บับเบิลที่แสดงและที่ปิดไปเมื่อเร็วๆ นี้จะปรากฏที่นี่"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"บับเบิล"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"จัดการ"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"ปิดบับเบิลแล้ว"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-th/strings_tv.xml b/libs/WindowManager/Shell/res/values-th/strings_tv.xml
new file mode 100644
index 000000000000..cd1b6120d541
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-th/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(ไม่มีชื่อรายการ)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"ปิด PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"เต็มหน้าจอ"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
new file mode 100644
index 000000000000..1615aaefd9e1
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Isara"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Palawakin"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Mga Setting"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"Nasa picture-in-picture ang <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Kung ayaw mong magamit ni <xliff:g id="NAME">%s</xliff:g> ang feature na ito, i-tap upang buksan ang mga setting at i-off ito."</string>
+ <string name="pip_play" msgid="3496151081459417097">"I-play"</string>
+ <string name="pip_pause" msgid="690688849510295232">"I-pause"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Lumaktaw sa susunod"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Lumaktaw sa nakaraan"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"I-resize"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Hindi sinusuportahan ng app ang split-screen."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Maaaring hindi gumana ang app sa pangalawang display."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Hindi sinusuportahan ng app ang paglulunsad sa mga pangalawang display."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Divider ng split-screen"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"I-full screen ang nasa kaliwa"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Gawing 70% ang nasa kaliwa"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Gawing 50% ang nasa kaliwa"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Gawing 30% ang nasa kaliwa"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"I-full screen ang nasa kanan"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"I-full screen ang nasa itaas"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gawing 70% ang nasa itaas"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gawing 50% ang nasa itaas"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Gawing 30% ang nasa itaas"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"I-full screen ang nasa ibaba"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Mga setting para sa mga bubble ng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Overflow"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Idagdag ulit sa stack"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> mula sa <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> mula sa <xliff:g id="APP_NAME">%2$s</xliff:g> at <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> pa"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Ilipat sa kaliwa sa itaas"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Ilipat sa kanan sa itaas"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Ilipat sa kaliwa sa ibaba"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Ilipat sa kanan sa ibaba"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Mga setting ng <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"I-dismiss ang bubble"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Huwag ipakita sa bubble ang mga pag-uusap"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Mag-chat gamit ang bubbles"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Lumalabas bilang mga nakalutang na icon o bubble ang mga bagong pag-uusap. I-tap para buksan ang bubble. I-drag para ilipat ito."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Kontrolin ang mga bubble anumang oras"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"I-tap ang Pamahalaan para i-off ang mga bubble mula sa app na ito"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Walang kamakailang bubble"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Lalabas dito ang mga kamakailang bubble at na-dismiss na bubble"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Pamahalaan"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Na-dismiss na ang bubble."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings_tv.xml b/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
new file mode 100644
index 000000000000..d5ebb9e0b1c5
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-tl/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Walang pamagat na programa)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Isara ang PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Full screen"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
new file mode 100644
index 000000000000..3b987e586bb1
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Kapat"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Genişlet"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Ayarlar"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menü"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g>, pencere içinde pencere özelliğini kullanıyor"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> uygulamasının bu özelliği kullanmasını istemiyorsanız dokunarak ayarları açın ve söz konusu özelliği kapatın."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Oynat"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Duraklat"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Sonrakine atla"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Öncekine atla"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Yeniden boyutlandır"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uygulama bölünmüş ekranı desteklemiyor."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uygulama ikincil ekranda çalışmayabilir."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Uygulama ikincil ekranlarda başlatılmayı desteklemiyor."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Bölünmüş ekran ayırıcı"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Solda tam ekran"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Solda %70"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Solda %50"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Solda %30"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Sağda tam ekran"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Üstte tam ekran"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Üstte %70"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Üstte %50"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Üstte %30"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Altta tam ekran"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> baloncukları için ayarlar"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Taşma"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Yığına geri ekle"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> uygulamasından <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> uygulamasından <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ve diğer <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Sol üste taşı"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Sağ üste taşı"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Sol alta taşı"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Sağ alta taşı"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ayarları"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Baloncuğu kapat"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Görüşmeyi baloncuk olarak görüntüleme"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Baloncukları kullanarak sohbet edin"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Yeni görüşmeler kayan simgeler veya baloncuk olarak görünür. Açmak için baloncuğa dokunun. Baloncuğu taşımak için sürükleyin."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Baloncukları istediğiniz zaman kontrol edin"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Bu uygulamanın baloncuklarını kapatmak için Yönet\'e dokunun"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Son kapatılan baloncuk yok"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Son baloncuklar ve kapattığınız baloncuklar burada görünür"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Baloncuk"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Yönet"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balon kapatıldı."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings_tv.xml b/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
new file mode 100644
index 000000000000..8feb319e00a4
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-tr/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Başlıksız program)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"PIP\'yi kapat"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Tam ekran"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
new file mode 100644
index 000000000000..6d012af93b7d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Закрити"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Розгорнути"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Налаштування"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Меню"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"У додатку <xliff:g id="NAME">%s</xliff:g> є функція \"Картинка в картинці\""</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Щоб додаток <xliff:g id="NAME">%s</xliff:g> не використовував цю функцію, вимкніть її в налаштуваннях."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Відтворити"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Призупинити"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Перейти далі"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Перейти назад"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Змінити розмір"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Додаток не підтримує розділення екрана."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Додаток може не працювати на додатковому екрані."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Додаток не підтримує запуск на додаткових екранах."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Розділювач екрана"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Ліве вікно на весь екран"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Ліве вікно на 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ліве вікно на 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ліве вікно на 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Праве вікно на весь екран"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Верхнє вікно на весь екран"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Верхнє вікно на 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхнє вікно на 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Верхнє вікно на 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Нижнє вікно на весь екран"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Налаштування спливаючих чатів від додатка <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Додаткове меню"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Додати в список"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"Cповіщення \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" від додатка <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"Сповіщення \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" від додатка <xliff:g id="APP_NAME">%2$s</xliff:g> (і ще <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>)"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Перемістити ліворуч угору"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Перемістити праворуч угору"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Перемістити ліворуч униз"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Перемістити праворуч униз"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Налаштування параметра \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\""</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Закрити підказку"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не показувати спливаючі чати для розмов"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Спливаючий чат"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Нові повідомлення чату з\'являються у вигляді спливаючих значків. Щоб відкрити чат, натисніть його, а щоб перемістити – перетягніть."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Контроль спливаючих чатів"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Натисніть \"Налаштувати\", щоб вимкнути спливаючі чати від цього додатка"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Немає нещодавніх спливаючих чатів"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Тут з\'являтимуться нещодавні й закриті спливаючі чати"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Спливаюче сповіщення"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Налаштувати"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Спливаюче сповіщення закрито."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings_tv.xml b/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
new file mode 100644
index 000000000000..0cc154521869
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-uk/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Програма без назви)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Закрити PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"На весь екран"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
new file mode 100644
index 000000000000..cd6529f0bf94
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"بند کریں"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"پھیلائیں"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"ترتیبات"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"مینو"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> تصویر میں تصویر میں ہے"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"اگر آپ نہیں چاہتے ہیں کہ <xliff:g id="NAME">%s</xliff:g> اس خصوصیت کا استعمال کرے تو ترتیبات کھولنے کے لیے تھپتھپا کر اسے آف کرے۔"</string>
+ <string name="pip_play" msgid="3496151081459417097">"چلائیں"</string>
+ <string name="pip_pause" msgid="690688849510295232">"موقوف کریں"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"نظرانداز کرکے اگلے پر جائیں"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"نظرانداز کرکے پچھلے پر جائیں"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"سائز تبدیل کریں"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ایپ سپلٹ اسکرین کو سپورٹ نہیں کرتی۔"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن ہے ایپ ثانوی ڈسپلے پر کام نہ کرے۔"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ایپ ثانوی ڈسپلیز پر شروعات کا تعاون نہیں کرتی۔"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"سپلٹ اسکرین تقسیم کار"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"بائیں فل اسکرین"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"بائیں %70"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"بائیں %50"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"بائیں %30"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"دائیں فل اسکرین"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"بالائی فل اسکرین"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"اوپر %70"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"اوپر %50"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"اوپر %30"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"نچلی فل اسکرین"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> بلبلوں کے لیے ترتیبات"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"اوورفلو"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"انبار میں واپس شامل کریں"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g> کی جانب سے <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> اور <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> مزید سے <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"اوپر بائیں جانب لے جائیں"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"اوپر دائیں جانب لے جائيں"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"نیچے بائیں جانب لے جائیں"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"نیچے دائیں جانب لے جائیں"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ترتیبات"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"بلبلہ برخاست کریں"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"گفتگو بلبلہ نہ کریں"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"بلبلے کے ذریعے چیٹ کریں"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"نئی گفتگوئیں فلوٹنگ آئیکن یا بلبلے کے طور پر ظاہر ہوں گی۔ بلبلہ کھولنے کے لیے تھپتھپائیں۔ اسے منتقل کرنے کے لیے گھسیٹیں۔"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"کسی بھی وقت بلبلے کو کنٹرول کریں"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"اس ایپ سے بلبلوں کو آف کرنے کے لیے نظم کریں پر تھپتھپائیں"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"کوئی حالیہ بلبلہ نہیں"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"حالیہ بلبلے اور برخاست شدہ بلبلے یہاں ظاہر ہوں گے"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"بلبلہ"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"نظم کریں"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"بلبلہ برخاست کر دیا گیا۔"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings_tv.xml b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
new file mode 100644
index 000000000000..64e5db5ae10a
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-ur/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(بلا عنوان پروگرام)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"‏PIP بند کریں"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"فُل اسکرین"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
new file mode 100644
index 000000000000..b714f59be3d9
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Yopish"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Yoyish"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Sozlamalar"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menyu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> tasvir ustida tasvir rejimida"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"<xliff:g id="NAME">%s</xliff:g> ilovasi uchun bu funksiyani sozlamalar orqali faolsizlantirish mumkin."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Ijro"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Pauza"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Keyingisiga o‘tish"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Avvalgisiga qaytish"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Oʻlchamini oʻzgartirish"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Bu ilova ekranni bo‘lish xususiyatini qo‘llab-quvvatlamaydi."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Bu ilova qo‘shimcha ekranda ishlamasligi mumkin."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Bu ilova qo‘shimcha ekranlarda ishga tushmaydi."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Ekranni ikkiga bo‘lish chizig‘i"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Chapda to‘liq ekran"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Chapda 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Chapda 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Chapda 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"O‘ngda to‘liq ekran"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Tepada to‘liq ekran"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Tepada 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Tepada 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Tepada 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Pastda to‘liq ekran"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g> bulutchalari uchun sozlamalar"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Kengaytirilgan"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Yana toʻplamga kiritish"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g> ilovasidan <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> va yana <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ta bildirishnoma"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Yuqori chapga surish"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Yuqori oʻngga surish"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Quyi chapga surish"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Quyi oʻngga surish"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> sozlamalari"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Bulutchani yopish"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Suhbatlar bulutchalar shaklida chiqmasin"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Bulutchalar yordamida subhatlashish"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Yangi xabarlar qalqib chiquvchi belgilar yoki bulutchalar kabi chiqadi. Xabarni ochish uchun bildirishnoma ustiga bosing. Xabarni qayta joylash uchun bildirishnomani suring."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Bulutchalardagi bildirishnomalar"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Bu ilova bulutchalarini faolsizlantirish uchun Boshqarish tugmasini bosing"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Avvalgi bulutchalar topilmadi"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Bu yerda oxirgi va yopilgan bulutcha shaklidagi bildirishnomalar chiqadi"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Pufaklar"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Boshqarish"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulutcha yopildi."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings_tv.xml b/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
new file mode 100644
index 000000000000..a0abb3d45d7b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-uz/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Nomsiz)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Kadr ichida kadr – chiqish"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Butun ekran"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
new file mode 100644
index 000000000000..be6f8444c493
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Đóng"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Mở rộng"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Cài đặt"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Menu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> đang ở chế độ ảnh trong ảnh"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Nếu bạn không muốn <xliff:g id="NAME">%s</xliff:g> sử dụng tính năng này, hãy nhấn để mở cài đặt và tắt tính năng này."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Phát"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Tạm dừng"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Chuyển tới mục tiếp theo"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Chuyển về mục trước"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Đổi kích thước"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Ứng dụng không hỗ trợ chia đôi màn hình."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Ứng dụng có thể không hoạt động trên màn hình phụ."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Ứng dụng không hỗ trợ khởi chạy trên màn hình phụ."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Bộ chia chia đôi màn hình"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Toàn màn hình bên trái"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Trái 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Trái 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Trái 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Toàn màn hình bên phải"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Toàn màn hình phía trên"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Trên 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Trên 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Trên 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Toàn màn hình phía dưới"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Tùy chọn cài đặt cho bong bóng trò chuyện <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Trình đơn mục bổ sung"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Thêm lại vào ngăn xếp"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> của <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> từ <xliff:g id="APP_NAME">%2$s</xliff:g> và <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> bong bóng khác"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Chuyển lên trên cùng bên trái"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Chuyển lên trên cùng bên phải"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Chuyển tới dưới cùng bên trái"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Chuyển tới dưới cùng bên phải"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"Cài đặt <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Đóng bong bóng"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Dừng sử dụng bong bóng cho cuộc trò chuyện"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Trò chuyện bằng bong bóng trò chuyện"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Các cuộc trò chuyện mới sẽ xuất hiện dưới dạng biểu tượng nổi hoặc bong bóng trò chuyện. Nhấn để mở bong bóng trò chuyện. Kéo để di chuyển bong bóng trò chuyện."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Kiểm soát bong bóng bất cứ lúc nào"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Nhấn vào nút Quản lý để tắt bong bóng trò chuyện từ ứng dụng này"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Không có bong bóng trò chuyện nào gần đây"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Bong bóng trò chuyện đã đóng và bong bóng trò chuyện gần đây sẽ xuất hiện ở đây"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Bong bóng"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Quản lý"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Đã đóng bong bóng."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings_tv.xml b/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
new file mode 100644
index 000000000000..093ef13961de
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-vi/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Không có chương trình tiêu đề)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Đóng PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Toàn màn hình"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
new file mode 100644
index 000000000000..b17e35e8ef6e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"关闭"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"展开"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"设置"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"菜单"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g>目前位于“画中画”中"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"如果您不想让“<xliff:g id="NAME">%s</xliff:g>”使用此功能,请点按以打开设置,然后关闭此功能。"</string>
+ <string name="pip_play" msgid="3496151081459417097">"播放"</string>
+ <string name="pip_pause" msgid="690688849510295232">"暂停"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"跳到下一个"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"跳到上一个"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"调整大小"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"应用不支持分屏。"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"应用可能无法在辅显示屏上正常运行。"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"应用不支持在辅显示屏上启动。"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"分屏分隔线"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"左侧全屏"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"左侧 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左侧 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左侧 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右侧全屏"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"顶部全屏"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"顶部 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"顶部 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"顶部 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"底部全屏"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g>对话泡的设置"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"菜单"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"重新加入叠放"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g>:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="APP_NAME">%2$s</xliff:g>和另外 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 个应用:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"移至左上角"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"移至右上角"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"移至左下角"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"移至右下角"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>设置"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"关闭对话泡"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不以对话泡形式显示对话"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"使用对话泡聊天"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"新对话会以浮动图标或对话泡形式显示。点按即可打开对话泡。拖动即可移动对话泡。"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"随时控制对话泡"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"点按“管理”按钮,可关闭来自此应用的对话泡"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近没有对话泡"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"此处会显示最近的对话泡和已关闭的对话泡"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"气泡"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已关闭对话泡。"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
new file mode 100644
index 000000000000..0b65fd391414
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(节目没有标题)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"关闭画中画"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"全屏"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
new file mode 100644
index 000000000000..88d28df813ee
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"關閉"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"展開"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"設定"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"選單"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"「<xliff:g id="NAME">%s</xliff:g>」目前在畫中畫模式"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"如果您不想「<xliff:g id="NAME">%s</xliff:g>」使用此功能,請輕按以開啟設定,然後停用此功能。"</string>
+ <string name="pip_play" msgid="3496151081459417097">"播放"</string>
+ <string name="pip_pause" msgid="690688849510295232">"暫停"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"跳到下一個"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"跳到上一個"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"調整大小"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"應用程式不支援分割畫面。"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示屏上運作。"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"應用程式無法在次要顯示屏上啟動。"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"分割畫面分隔線"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"左邊全螢幕"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"左邊 70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左邊 50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左邊 30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右邊全螢幕"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"頂部全螢幕"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"頂部 70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"頂部 50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"頂部 30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"底部全螢幕"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」小視窗設定"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"顯示更多"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"加回堆疊"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"來自「<xliff:g id="APP_NAME">%2$s</xliff:g>」的 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"來自「<xliff:g id="APP_NAME">%2$s</xliff:g>」及另外 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 個應用程式的<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"移去左上角"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"移去右上角"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"移去左下角"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"移去右下角"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」設定"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"關閉小視窗氣泡"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不要透過小視窗顯示對話"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"使用小視窗進行即時通訊"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"新對話會以浮動圖示 (小視窗) 顯示。輕按即可開啟小視窗。拖曳即可移動小視窗。"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"隨時控制小視窗設定"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"輕按「管理」即可關閉此應用程式的小視窗"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"沒有最近曾使用的小視窗"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"最近使用和關閉的小視窗會在這裡顯示"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"氣泡"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"對話氣泡已關閉。"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
new file mode 100644
index 000000000000..74fc3749c73f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(沒有標題的節目)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"關閉 PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"全螢幕"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
new file mode 100644
index 000000000000..2530db722546
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"關閉"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"展開"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"設定"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"選單"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"「<xliff:g id="NAME">%s</xliff:g>」目前在子母畫面中"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"如果你不想讓「<xliff:g id="NAME">%s</xliff:g>」使用這項功能,請輕觸開啟設定頁面,然後停用此功能。"</string>
+ <string name="pip_play" msgid="3496151081459417097">"播放"</string>
+ <string name="pip_pause" msgid="690688849510295232">"暫停"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"跳到下一個"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"跳到上一個"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"調整大小"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"這個應用程式不支援分割畫面。"</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示器上運作。"</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"應用程式無法在次要顯示器上啟動。"</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"分割畫面分隔線"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"以全螢幕顯示左側畫面"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"以 70% 的螢幕空間顯示左側畫面"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"以 50% 的螢幕空間顯示左側畫面"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"以 30% 的螢幕空間顯示左側畫面"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"以全螢幕顯示右側畫面"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"以全螢幕顯示頂端畫面"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"以 70% 的螢幕空間顯示頂端畫面"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"以 50% 的螢幕空間顯示頂端畫面"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"以 30% 的螢幕空間顯示頂端畫面"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"以全螢幕顯示底部畫面"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」對話框的設定"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"溢位"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"重新加入堆疊"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="APP_NAME">%2$s</xliff:g>:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"「<xliff:g id="APP_NAME">%2$s</xliff:g>」和其他 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 個應用程式:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"移至左上方"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"移至右上方"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"移至左下方"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"移至右下方"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」設定"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"關閉對話框"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不要以對話框形式顯示對話"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"透過對話框來聊天"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"新的對話會以浮動圖示或對話框形式顯示。輕觸即可開啟對話框,拖曳則可移動對話框。"</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"你隨時可以控管對話框的各項設定"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"輕觸 [管理] 即可關閉來自這個應用程式的對話框"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近沒有任何對話框"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"最近的對話框和已關閉的對話框會顯示在這裡"</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"泡泡"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"管理"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"已關閉泡泡。"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
new file mode 100644
index 000000000000..e7d1ca98334b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(無標題的節目)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"關閉子母畫面"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"全螢幕"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
new file mode 100644
index 000000000000..72fdc9c82fa5
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -0,0 +1,78 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="pip_phone_close" msgid="5783752637260411309">"Vala"</string>
+ <string name="pip_phone_expand" msgid="2579292903468287504">"Nweba"</string>
+ <string name="pip_phone_settings" msgid="5468987116750491918">"Izilungiselelo"</string>
+ <string name="pip_menu_title" msgid="5393619322111827096">"Imenyu"</string>
+ <string name="pip_notification_title" msgid="1347104727641353453">"U-<xliff:g id="NAME">%s</xliff:g> ungaphakathi kwesithombe esiphakathi kwesithombe"</string>
+ <string name="pip_notification_message" msgid="8854051911700302620">"Uma ungafuni i-<xliff:g id="NAME">%s</xliff:g> ukuthi isebenzise lesi sici, thepha ukuze uvule izilungiselelo uphinde uyivale."</string>
+ <string name="pip_play" msgid="3496151081459417097">"Dlala"</string>
+ <string name="pip_pause" msgid="690688849510295232">"Misa isikhashana"</string>
+ <string name="pip_skip_to_next" msgid="8403429188794867653">"Yeqela kokulandelayo"</string>
+ <string name="pip_skip_to_prev" msgid="7172158111196394092">"Yeqela kokwangaphambilini"</string>
+ <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Shintsha usayizi"</string>
+ <!-- no translation found for dock_forced_resizable (1749750436092293116) -->
+ <skip />
+ <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uhlelo lokusebenza alusekeli isikrini esihlukanisiwe."</string>
+ <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uhlelo lokusebenza kungenzeka lungasebenzi kusibonisi sesibili."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Uhlelo lokusebenza alusekeli ukuqalisa kuzibonisi zesibili."</string>
+ <string name="accessibility_divider" msgid="703810061635792791">"Isihlukanisi sokuhlukanisa isikrini"</string>
+ <string name="accessibility_action_divider_left_full" msgid="1792313656305328536">"Isikrini esigcwele esingakwesokunxele"</string>
+ <string name="accessibility_action_divider_left_70" msgid="8859845045360659250">"Kwesokunxele ngo-70%"</string>
+ <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kwesokunxele ngo-50%"</string>
+ <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kwesokunxele ngo-30%"</string>
+ <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Isikrini esigcwele esingakwesokudla"</string>
+ <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Isikrini esigcwele esiphezulu"</string>
+ <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Okuphezulu okungu-70%"</string>
+ <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Okuphezulu okungu-50%"</string>
+ <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Okuphezulu okungu-30%"</string>
+ <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Ngaphansi kwesikrini esigcwele"</string>
+ <!-- no translation found for one_handed_tutorial_title (4583241688067426350) -->
+ <skip />
+ <!-- no translation found for one_handed_tutorial_description (3486582858591353067) -->
+ <skip />
+ <!-- no translation found for accessibility_action_start_one_handed (5070337354072861426) -->
+ <skip />
+ <!-- no translation found for accessibility_action_stop_one_handed (1369940261782179442) -->
+ <skip />
+ <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Izilungiselelo zamabhamuza e-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Ukuphuphuma"</string>
+ <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Engeza emuva kusitaki"</string>
+ <string name="bubble_content_description_single" msgid="8495748092720065813">"I-<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kusuka ku-<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_content_description_stack" msgid="8071515017164630429">"I-<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kusukela ku-<xliff:g id="APP_NAME">%2$s</xliff:g> nokungu-<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ngaphezulu"</string>
+ <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Hambisa phezulu kwesokunxele"</string>
+ <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Hambisa phezulu ngakwesokudla"</string>
+ <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Hambisa inkinobho ngakwesokunxele"</string>
+ <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Hambisa inkinobho ngakwesokudla"</string>
+ <string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> izilungiselelo"</string>
+ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Cashisa ibhamuza"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ungayibhamuzi ingxoxo"</string>
+ <string name="bubbles_user_education_title" msgid="2112319053732691899">"Xoxa usebenzisa amabhamuza"</string>
+ <string name="bubbles_user_education_description" msgid="4215862563054175407">"Izingxoxo ezintsha zivela njengezithonjana ezintantayo, noma amabhamuza. Thepha ukuze uvule ibhamuza. Hudula ukuze ulihambise."</string>
+ <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Lawula amabhamuza noma nini"</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Thepha okuthi Phatha ukuvala amabhamuza kusuka kulolu hlelo lokusebenza"</string>
+ <!-- no translation found for bubbles_user_education_got_it (3382046149225428296) -->
+ <skip />
+ <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Awekho amabhamuza akamuva"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Amabhamuza akamuva namabhamuza asusiwe azobonakala lapha."</string>
+ <string name="notification_bubble_title" msgid="6082910224488253378">"Ibhamuza"</string>
+ <string name="manage_bubbles_text" msgid="7730624269650594419">"Phatha"</string>
+ <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Ibhamuza licashisiwe."</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings_tv.xml b/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
new file mode 100644
index 000000000000..62fc4c47cfd1
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-zu/strings_tv.xml
@@ -0,0 +1,25 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for notification_channel_tv_pip (2576686079160402435) -->
+ <skip />
+ <string name="pip_notification_unknown_title" msgid="2729870284350772311">"(Alukho uhlelo lwesihloko)"</string>
+ <string name="pip_close" msgid="9135220303720555525">"Vala i-PIP"</string>
+ <string name="pip_fullscreen" msgid="7278047353591302554">"Iskrini esigcwele"</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index cc3bf2a09454..1674d0bf78be 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -25,4 +25,14 @@
<!-- Background for the various drop targets when handling drag and drop. -->
<color name="drop_outline_background">#330000FF</color>
+
+ <!-- Bubbles -->
+ <color name="bubbles_light">#FFFFFF</color>
+ <color name="bubbles_dark">@color/GM2_grey_800</color>
+ <color name="bubbles_icon_tint">@color/GM2_grey_700</color>
+
+ <!-- GM2 colors -->
+ <color name="GM2_grey_200">#E8EAED</color>
+ <color name="GM2_grey_700">#5F6368</color>
+ <color name="GM2_grey_800">#3C4043</color>
</resources> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index b87a642a8dc7..25d034c51f46 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -75,4 +75,96 @@
<!-- The amount to inset the drop target regions from the edge of the display -->
<dimen name="drop_layout_display_margin">16dp</dimen>
+
+ <!-- The menu grid size for bubble menu. -->
+ <dimen name="bubble_grid_item_icon_width">20dp</dimen>
+ <dimen name="bubble_grid_item_icon_height">20dp</dimen>
+ <dimen name="bubble_grid_item_icon_top_margin">12dp</dimen>
+ <dimen name="bubble_grid_item_icon_bottom_margin">4dp</dimen>
+ <dimen name="bubble_grid_item_icon_side_margin">22dp</dimen>
+
+ <!-- How much each bubble is elevated. -->
+ <dimen name="bubble_elevation">1dp</dimen>
+ <!-- How much the bubble flyout text container is elevated. -->
+ <dimen name="bubble_flyout_elevation">4dp</dimen>
+ <!-- How much padding is around the left and right sides of the flyout text. -->
+ <dimen name="bubble_flyout_padding_x">12dp</dimen>
+ <!-- How much padding is around the top and bottom of the flyout text. -->
+ <dimen name="bubble_flyout_padding_y">10dp</dimen>
+ <!-- Size of the triangle that points from the flyout to the bubble stack. -->
+ <dimen name="bubble_flyout_pointer_size">6dp</dimen>
+ <!-- How much space to leave between the flyout (tip of the arrow) and the bubble stack. -->
+ <dimen name="bubble_flyout_space_from_bubble">8dp</dimen>
+ <!-- How much space to leave between the flyout text and the avatar displayed in the flyout. -->
+ <dimen name="bubble_flyout_avatar_message_space">6dp</dimen>
+ <!-- Padding between status bar and bubbles when displayed in expanded state -->
+ <dimen name="bubble_padding_top">16dp</dimen>
+ <!-- Max amount of space between bubbles when expanded. -->
+ <dimen name="bubble_max_spacing">16dp</dimen>
+ <!-- Size of individual bubbles. -->
+ <dimen name="individual_bubble_size">60dp</dimen>
+ <!-- Size of bubble bitmap. -->
+ <dimen name="bubble_bitmap_size">52dp</dimen>
+ <!-- Extra padding added to the touchable rect for bubbles so they are easier to grab. -->
+ <dimen name="bubble_touch_padding">12dp</dimen>
+ <!-- Size of the circle around the bubbles when they're in the dismiss target. -->
+ <dimen name="bubble_dismiss_encircle_size">52dp</dimen>
+ <!-- Padding around the view displayed when the bubble is expanded -->
+ <dimen name="bubble_expanded_view_padding">4dp</dimen>
+ <!-- This should be at least the size of bubble_expanded_view_padding; it is used to include
+ a slight touch slop around the expanded view. -->
+ <dimen name="bubble_expanded_view_slop">8dp</dimen>
+ <!-- Default (and minimum) height of the expanded view shown when the bubble is expanded -->
+ <dimen name="bubble_expanded_default_height">180dp</dimen>
+ <!-- Default height of bubble overflow -->
+ <dimen name="bubble_overflow_height">480dp</dimen>
+ <!-- Bubble overflow padding when there are no bubbles -->
+ <dimen name="bubble_overflow_empty_state_padding">16dp</dimen>
+ <!-- Padding of container for overflow bubbles -->
+ <dimen name="bubble_overflow_padding">15dp</dimen>
+ <!-- Padding of label for bubble overflow view -->
+ <dimen name="bubble_overflow_text_padding">7dp</dimen>
+ <!-- Height of bubble overflow empty state illustration -->
+ <dimen name="bubble_empty_overflow_image_height">200dp</dimen>
+ <!-- Padding of bubble overflow empty state subtitle -->
+ <dimen name="bubble_empty_overflow_subtitle_padding">50dp</dimen>
+ <!-- Height of the triangle that points to the expanded bubble -->
+ <dimen name="bubble_pointer_height">8dp</dimen>
+ <!-- Width of the triangle that points to the expanded bubble -->
+ <dimen name="bubble_pointer_width">12dp</dimen>
+ <!-- Extra padding around the dismiss target for bubbles -->
+ <dimen name="bubble_dismiss_slop">16dp</dimen>
+ <!-- Height of button allowing users to adjust settings for bubbles. -->
+ <dimen name="bubble_manage_button_height">48dp</dimen>
+ <!-- Height of an item in the bubble manage menu. -->
+ <dimen name="bubble_menu_item_height">60dp</dimen>
+ <!-- Max width of the message bubble-->
+ <dimen name="bubble_message_max_width">144dp</dimen>
+ <!-- Min width of the message bubble -->
+ <dimen name="bubble_message_min_width">32dp</dimen>
+ <!-- Interior padding of the message bubble -->
+ <dimen name="bubble_message_padding">4dp</dimen>
+ <!-- Offset between bubbles in their stacked position. -->
+ <dimen name="bubble_stack_offset">10dp</dimen>
+ <!-- Offset between stack y and animation y for bubble swap. -->
+ <dimen name="bubble_swap_animation_offset">15dp</dimen>
+ <!-- How far offscreen the bubble stack rests. Cuts off padding and part of icon bitmap. -->
+ <dimen name="bubble_stack_offscreen">9dp</dimen>
+ <!-- How far down the screen the stack starts. -->
+ <dimen name="bubble_stack_starting_offset_y">120dp</dimen>
+ <!-- Space between the pointer triangle and the bubble expanded view -->
+ <dimen name="bubble_pointer_margin">8dp</dimen>
+ <!-- Padding applied to the bubble dismiss target. Touches in this padding cause the bubbles to
+ snap to the dismiss target. -->
+ <dimen name="bubble_dismiss_target_padding_x">40dp</dimen>
+ <dimen name="bubble_dismiss_target_padding_y">20dp</dimen>
+ <dimen name="bubble_manage_menu_elevation">4dp</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. -->
+ <dimen name="bubbles_manage_education_top_inset">65dp</dimen>
+ <!-- Size of padding for the user education cling, this should at minimum be larger than
+ individual_bubble_size + some padding. -->
+ <dimen name="bubble_stack_user_education_side_inset">72dp</dimen>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/ids.xml b/libs/WindowManager/Shell/res/values/ids.xml
index fb892388cf74..434a000010c4 100644
--- a/libs/WindowManager/Shell/res/values/ids.xml
+++ b/libs/WindowManager/Shell/res/values/ids.xml
@@ -23,4 +23,21 @@
<item type="id" name="action_move_tl_50" />
<item type="id" name="action_move_tl_30" />
<item type="id" name="action_move_rb_full" />
+
+ <!-- For saving PhysicsAnimationLayout animations/animators as view tags. -->
+ <item type="id" name="translation_x_dynamicanimation_tag"/>
+ <item type="id" name="translation_y_dynamicanimation_tag"/>
+ <item type="id" name="translation_z_dynamicanimation_tag"/>
+ <item type="id" name="alpha_dynamicanimation_tag"/>
+ <item type="id" name="scale_x_dynamicanimation_tag"/>
+ <item type="id" name="scale_y_dynamicanimation_tag"/>
+ <item type="id" name="physics_animator_tag"/>
+ <item type="id" name="target_animator_tag" />
+ <item type="id" name="reorder_animator_tag"/>
+
+ <!-- Accessibility actions for bubbles. -->
+ <item type="id" name="action_move_top_left"/>
+ <item type="id" name="action_move_top_right"/>
+ <item type="id" name="action_move_bottom_left"/>
+ <item type="id" name="action_move_bottom_right"/>
</resources>
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/values/attrs.xml b/libs/WindowManager/Shell/res/values/integers.xml
index 7ba333468422..583bf3341a69 100644
--- a/packages/CarSystemUI/samples/sample2/rro/res/values/attrs.xml
+++ b/libs/WindowManager/Shell/res/values/integers.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -14,15 +13,13 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
<resources>
- <attr name="broadcast" format="boolean"/>
- <attr name="icon" format="reference"/>
- <attr name="selectedIcon" format="reference"/>
- <attr name="intent" format="string"/>
- <attr name="longIntent" format="string"/>
- <attr name="componentNames" format="string" />
- <attr name="highlightWhenSelected" format="boolean" />
- <attr name="categories" format="string"/>
- <attr name="packages" format="string" />
-</resources>
+ <!-- Maximum number of bubbles to render and animate at one time. While the animations used are
+ lightweight translation animations, this number can be reduced on lower end devices if any
+ performance issues arise. -->
+ <integer name="bubbles_max_rendered">5</integer>
+ <!-- Number of columns in bubble overflow. -->
+ <integer name="bubbles_overflow_columns">4</integer>
+ <!-- Maximum number of bubbles we allow in overflow before we dismiss the oldest one. -->
+ <integer name="bubbles_max_overflow">16</integer>
+</resources> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index da5965dab71a..30ef72c2a352 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -97,4 +97,53 @@
<string name="accessibility_action_start_one_handed">Start one-handed mode</string>
<!-- Accessibility description for stop one-handed mode [CHAR LIMIT=NONE] -->
<string name="accessibility_action_stop_one_handed">Exit one-handed mode</string>
+
+ <!-- Text used for content description of settings button in the header of expanded bubble
+ view. [CHAR_LIMIT=NONE] -->
+ <string name="bubbles_settings_button_description">Settings for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> bubbles</string>
+ <!-- Content description for button that shows bubble overflow on click [CHAR LIMIT=NONE] -->
+ <string name="bubble_overflow_button_content_description">Overflow</string>
+ <!-- Action to add overflow bubble back to stack. [CHAR LIMIT=NONE] -->
+ <string name="bubble_accessibility_action_add_back">Add back to stack</string>
+ <!-- Content description when a bubble is focused. [CHAR LIMIT=NONE] -->
+ <string name="bubble_content_description_single"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g></string>
+ <!-- Content description when the stack of bubbles is focused. [CHAR LIMIT=NONE] -->
+ <string name="bubble_content_description_stack"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g> and <xliff:g id="bubble_count" example="4">%3$d</xliff:g> more</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the top left of the screen. [CHAR LIMIT=30] -->
+ <string name="bubble_accessibility_action_move_top_left">Move top left</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the top right of the screen. [CHAR LIMIT=30] -->
+ <string name="bubble_accessibility_action_move_top_right">Move top right</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the bottom left of the screen. [CHAR LIMIT=30]-->
+ <string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]-->
+ <string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string>
+ <!-- Label for the button that takes the user to the notification settings for the given app. -->
+ <string name="bubbles_app_settings"><xliff:g id="notification_title" example="Android Messages">%1$s</xliff:g> settings</string>
+ <!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=30] -->
+ <string name="bubble_dismiss_text">Dismiss bubble</string>
+ <!-- Button text to stop a conversation from bubbling [CHAR LIMIT=60]-->
+ <string name="bubbles_dont_bubble_conversation">Don\u2019t bubble conversation</string>
+ <!-- Title text for the bubbles feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=60]-->
+ <string name="bubbles_user_education_title">Chat using bubbles</string>
+ <!-- Descriptive text for the bubble feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=NONE] -->
+ <string name="bubbles_user_education_description">New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it.</string>
+ <!-- Title text for the bubble "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=60]-->
+ <string name="bubbles_user_education_manage_title">Control bubbles anytime</string>
+ <!-- Descriptive text for the bubble "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=80]-->
+ <string name="bubbles_user_education_manage">Tap Manage to turn off bubbles from this app</string>
+ <!-- Button text for dismissing the bubble "manage" button tool tip [CHAR LIMIT=20]-->
+ <string name="bubbles_user_education_got_it">Got it</string>
+ <!-- [CHAR LIMIT=NONE] Empty overflow title -->
+ <string name="bubble_overflow_empty_title">No recent bubbles</string>
+ <!-- [CHAR LIMIT=NONE] Empty overflow subtitle -->
+ <string name="bubble_overflow_empty_subtitle">Recent bubbles and dismissed bubbles will appear here</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance title -->
+ <string name="notification_bubble_title">Bubble</string>
+
+ <!-- The text for the manage bubbles link. [CHAR LIMIT=NONE] -->
+ <string name="manage_bubbles_text">Manage</string>
+
+ <!-- Content description to tell the user a bubble has been dismissed. -->
+ <string name="accessibility_bubble_dismissed">Bubble dismissed.</string>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellDump.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellDump.java
index 4ba842239242..13089affd058 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellDump.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellDump.java
@@ -16,8 +16,8 @@
package com.android.wm.shell;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.draganddrop.DragAndDropController;
+import com.android.wm.shell.apppairs.AppPairs;
+import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -33,16 +33,22 @@ public class ShellDump {
private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<Pip> mPipOptional;
private final Optional<OneHanded> mOneHandedOptional;
+ private final Optional<HideDisplayCutout> mHideDisplayCutout;
private final ShellTaskOrganizer mShellTaskOrganizer;
+ private final Optional<AppPairs> mAppPairsOptional;
public ShellDump(ShellTaskOrganizer shellTaskOrganizer,
Optional<SplitScreen> splitScreenOptional,
Optional<Pip> pipOptional,
- Optional<OneHanded> oneHandedOptional) {
+ Optional<OneHanded> oneHandedOptional,
+ Optional<HideDisplayCutout> hideDisplayCutout,
+ Optional<AppPairs> appPairsOptional) {
mShellTaskOrganizer = shellTaskOrganizer;
mSplitScreenOptional = splitScreenOptional;
mPipOptional = pipOptional;
mOneHandedOptional = oneHandedOptional;
+ mHideDisplayCutout = hideDisplayCutout;
+ mAppPairsOptional = appPairsOptional;
}
public void dump(PrintWriter pw) {
@@ -52,5 +58,9 @@ public class ShellDump {
mPipOptional.ifPresent(pip -> pip.dump(pw));
mSplitScreenOptional.ifPresent(splitScreen -> splitScreen.dump(pw));
mOneHandedOptional.ifPresent(oneHanded -> oneHanded.dump(pw));
+ mHideDisplayCutout.ifPresent(hideDisplayCutout -> hideDisplayCutout.dump(pw));
+ pw.println();
+ pw.println();
+ mAppPairsOptional.ifPresent(appPairs -> appPairs.dump(pw, ""));
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java
index 4269a905a0fe..d654f8adc153 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInit.java
@@ -16,6 +16,7 @@
package com.android.wm.shell;
+import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -31,15 +32,18 @@ public class ShellInit {
private final DragAndDropController mDragAndDropController;
private final ShellTaskOrganizer mShellTaskOrganizer;
private final Optional<SplitScreen> mSplitScreenOptional;
+ private final Optional<AppPairs> mAppPairsOptional;
public ShellInit(DisplayImeController displayImeController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
- Optional<SplitScreen> splitScreenOptional) {
+ Optional<SplitScreen> splitScreenOptional,
+ Optional<AppPairs> appPairsOptional) {
mDisplayImeController = displayImeController;
mDragAndDropController = dragAndDropController;
mShellTaskOrganizer = shellTaskOrganizer;
mSplitScreenOptional = splitScreenOptional;
+ mAppPairsOptional = appPairsOptional;
}
public void init() {
@@ -47,6 +51,7 @@ public class ShellInit {
mDisplayImeController.startMonitorDisplays();
// Register the shell organizer
mShellTaskOrganizer.registerOrganizer();
+ mAppPairsOptional.ifPresent(AppPairs::onOrganizerRegistered);
// Bind the splitscreen impl to the drag drop controller
mDragAndDropController.setSplitScreenController(mSplitScreenOptional);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 51ddb17daa00..006fd9d35a28 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -26,7 +26,7 @@ import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG
import android.annotation.IntDef;
import android.app.ActivityManager.RunningTaskInfo;
-import android.app.WindowConfiguration.WindowingMode;
+import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.util.ArrayMap;
@@ -38,12 +38,14 @@ import android.window.TaskAppearedInfo;
import android.window.TaskOrganizer;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -104,21 +106,26 @@ public class ShellTaskOrganizer extends TaskOrganizer {
private final Transitions mTransitions;
private final Object mLock = new Object();
+ private final StartingSurfaceDrawer mStartingSurfaceDrawer;
public ShellTaskOrganizer(SyncTransactionQueue syncQueue, TransactionPool transactionPool,
- ShellExecutor mainExecutor, ShellExecutor animExecutor) {
- this(null, syncQueue, transactionPool, mainExecutor, animExecutor);
+ ShellExecutor mainExecutor, ShellExecutor animExecutor, Context context) {
+ this(null, syncQueue, transactionPool, mainExecutor, animExecutor, context);
}
@VisibleForTesting
ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController,
SyncTransactionQueue syncQueue, TransactionPool transactionPool,
- ShellExecutor mainExecutor, ShellExecutor animExecutor) {
+ ShellExecutor mainExecutor, ShellExecutor animExecutor, Context context) {
super(taskOrganizerController, mainExecutor);
addListenerForType(new FullscreenTaskListener(syncQueue), TASK_LISTENER_TYPE_FULLSCREEN);
addListenerForType(new LetterboxTaskListener(syncQueue), TASK_LISTENER_TYPE_LETTERBOX);
mTransitions = new Transitions(this, transactionPool, mainExecutor, animExecutor);
if (Transitions.ENABLE_SHELL_TRANSITIONS) registerTransitionPlayer(mTransitions);
+ // TODO(b/131727939) temporarily live here, the starting surface drawer should be controlled
+ // by a controller, that class should be create while porting
+ // ActivityRecord#addStartingWindow to WMShell.
+ mStartingSurfaceDrawer = new StartingSurfaceDrawer(context);
}
@Override
@@ -235,6 +242,16 @@ public class ShellTaskOrganizer extends TaskOrganizer {
}
@Override
+ public void addStartingWindow(RunningTaskInfo taskInfo, IBinder appToken) {
+ mStartingSurfaceDrawer.addStartingWindow(taskInfo, appToken);
+ }
+
+ @Override
+ public void removeStartingWindow(RunningTaskInfo taskInfo) {
+ mStartingSurfaceDrawer.removeStartingWindow(taskInfo);
+ }
+
+ @Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
synchronized (mLock) {
onTaskAppeared(new TaskAppearedInfo(taskInfo, leash));
@@ -292,6 +309,15 @@ public class ShellTaskOrganizer extends TaskOrganizer {
}
}
+ /** Gets running task by taskId. Returns {@code null} if no such task observed. */
+ @Nullable
+ public RunningTaskInfo getRunningTaskInfo(int taskId) {
+ synchronized (mLock) {
+ final TaskAppearedInfo info = mTasks.get(taskId);
+ return info != null ? info.getTaskInfo() : null;
+ }
+ }
+
private boolean updateTaskListenerIfNeeded(RunningTaskInfo taskInfo, SurfaceControl leash,
TaskListener oldListener, TaskListener newListener) {
if (oldListener == newListener) return false;
@@ -346,15 +372,9 @@ public class ShellTaskOrganizer extends TaskOrganizer {
return mTaskListeners.get(taskListenerType);
}
- @WindowingMode
- public static int getWindowingMode(RunningTaskInfo taskInfo) {
- return taskInfo.configuration.windowConfiguration.getWindowingMode();
- }
-
@VisibleForTesting
static @TaskListenerType int taskInfoToTaskListenerType(RunningTaskInfo runningTaskInfo) {
- final int windowingMode = getWindowingMode(runningTaskInfo);
- switch (windowingMode) {
+ switch (runningTaskInfo.getWindowingMode()) {
case WINDOWING_MODE_FULLSCREEN:
return runningTaskInfo.letterboxActivityBounds != null
? TASK_LISTENER_TYPE_LETTERBOX
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
index 0a2cfbfffd9e..59a765d49a14 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/TaskView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -30,26 +30,23 @@ import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.os.Binder;
+import android.util.CloseGuard;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.wm.shell.ShellTaskOrganizer;
-
-import dalvik.system.CloseGuard;
-
import java.io.PrintWriter;
import java.util.concurrent.Executor;
/**
* View that can display a task.
*/
-// TODO: Place in com.android.wm.shell vs. com.android.wm.shell.bubbles on shell migration.
public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
ShellTaskOrganizer.TaskListener {
+ /** Callback for listening task state. */
public interface Listener {
/** Called when the container is ready for launching activities. */
default void onInitialized() {}
@@ -70,7 +67,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback,
default void onBackPressedOnTaskRoot(int taskId) {}
}
- private final CloseGuard mGuard = CloseGuard.get();
+ private final CloseGuard mGuard = new CloseGuard();
private final ShellTaskOrganizer mTaskOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index a3b720c457c6..8aca01d2467b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -56,4 +56,10 @@ public class Interpolators {
* Interpolator to be used when animating a move based on a click. Pair with enough duration.
*/
public static final Interpolator TOUCH_RESPONSE = new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
+ /**
+ * Interpolator to be used when animating a panel closing.
+ */
+ public static final Interpolator PANEL_CLOSE_ACCELERATED =
+ new PathInterpolator(0.3f, 0, 0.5f, 1);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
new file mode 100644
index 000000000000..d30acee4be6a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java
@@ -0,0 +1,208 @@
+/*
+ * 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.wm.shell.apppairs;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
+
+import android.app.ActivityManager;
+import android.graphics.Rect;
+import android.view.SurfaceControl;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+import java.io.PrintWriter;
+
+/**
+ * An app-pairs consisting of {@link #mRootTaskInfo} that acts as the hierarchy parent of
+ * {@link #mTaskInfo1} and {@link #mTaskInfo2} in the pair.
+ * Also includes all UI for managing the pair like the divider.
+ */
+// TODO: Add divider
+// TODO: Handle display rotation
+class AppPair implements ShellTaskOrganizer.TaskListener {
+ private static final String TAG = AppPair.class.getSimpleName();
+
+ private ActivityManager.RunningTaskInfo mRootTaskInfo;
+ private SurfaceControl mRootTaskLeash;
+ private ActivityManager.RunningTaskInfo mTaskInfo1;
+ private SurfaceControl mTaskLeash1;
+ private ActivityManager.RunningTaskInfo mTaskInfo2;
+ private SurfaceControl mTaskLeash2;
+
+ private final AppPairsController mController;
+ private final SyncTransactionQueue mSyncQueue;
+
+ AppPair(AppPairsController controller) {
+ mController = controller;
+ mSyncQueue = controller.getSyncTransactionQueue();
+ }
+
+ int getRootTaskId() {
+ return mRootTaskInfo != null ? mRootTaskInfo.taskId : INVALID_TASK_ID;
+ }
+
+ private int getTaskId1() {
+ return mTaskInfo1 != null ? mTaskInfo1.taskId : INVALID_TASK_ID;
+ }
+
+ private int getTaskId2() {
+ return mTaskInfo2 != null ? mTaskInfo2.taskId : INVALID_TASK_ID;
+ }
+
+ boolean contains(int taskId) {
+ return taskId == getRootTaskId() || taskId == getTaskId1() || taskId == getTaskId2();
+ }
+
+ boolean pair(ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
+ ProtoLog.v(WM_SHELL_TASK_ORG, "pair task1=%d task2=%d in AppPair=%s",
+ task1.taskId, task2.taskId, this);
+
+ if (!task1.isResizeable || !task2.isResizeable) {
+ ProtoLog.e(WM_SHELL_TASK_ORG,
+ "Can't pair unresizeable tasks task1.isResizeable=%b task1.isResizeable=%b",
+ task1.isResizeable, task2.isResizeable);
+ return false;
+ }
+
+ mTaskInfo1 = task1;
+ mTaskInfo2 = task2;
+
+ // TODO: properly calculate bounds for pairs.
+ final Rect rootBounds = mRootTaskInfo.configuration.windowConfiguration.getBounds();
+ final Rect bounds1 = new Rect(
+ rootBounds.left, rootBounds.top, rootBounds.right / 2, rootBounds.bottom / 2);
+ final Rect bounds2 = new Rect(
+ bounds1.right, bounds1.bottom, rootBounds.right, rootBounds.bottom);
+ final WindowContainerToken token1 = task1.token;
+ final WindowContainerToken token2 = task2.token;
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+ wct.setHidden(mRootTaskInfo.token, false)
+ .reparent(token1, mRootTaskInfo.token, true /* onTop */)
+ .reparent(token2, mRootTaskInfo.token, true /* onTop */)
+ .setWindowingMode(token1, WINDOWING_MODE_MULTI_WINDOW)
+ .setWindowingMode(token2, WINDOWING_MODE_MULTI_WINDOW)
+ .setBounds(token1, bounds1)
+ .setBounds(token2, bounds2)
+ // Moving the root task to top after the child tasks were repareted , or the root
+ // task cannot be visible and focused.
+ .reorder(mRootTaskInfo.token, true);
+ mController.getTaskOrganizer().applyTransaction(wct);
+ return true;
+ }
+
+ void unpair() {
+ final WindowContainerToken token1 = mTaskInfo1.token;
+ final WindowContainerToken token2 = mTaskInfo2.token;
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+ // Reparent out of this container and reset windowing mode.
+ wct.setHidden(mRootTaskInfo.token, true)
+ .reorder(mRootTaskInfo.token, false)
+ .reparent(token1, null, false /* onTop */)
+ .reparent(token2, null, false /* onTop */)
+ .setWindowingMode(token1, WINDOWING_MODE_UNDEFINED)
+ .setWindowingMode(token2, WINDOWING_MODE_UNDEFINED);
+ mController.getTaskOrganizer().applyTransaction(wct);
+
+ mTaskInfo1 = null;
+ mTaskInfo2 = null;
+ }
+
+ @Override
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
+ if (mRootTaskInfo == null || taskInfo.taskId == mRootTaskInfo.taskId) {
+ mRootTaskInfo = taskInfo;
+ mRootTaskLeash = leash;
+ } else if (taskInfo.taskId == getTaskId1()) {
+ mTaskInfo1 = taskInfo;
+ mTaskLeash1 = leash;
+ } else if (taskInfo.taskId == getTaskId2()) {
+ mTaskInfo2 = taskInfo;
+ mTaskLeash2 = leash;
+ } else {
+ throw new IllegalStateException("Unknown task=" + taskInfo.taskId);
+ }
+
+ if (mTaskLeash1 == null || mTaskLeash2 == null) return;
+
+ // TODO: Is there more we need to do here?
+ mSyncQueue.runInSync(t -> t
+ .setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x,
+ mTaskInfo1.positionInParent.y)
+ .setPosition(mTaskLeash2, mTaskInfo2.positionInParent.x,
+ mTaskInfo2.positionInParent.y)
+ .show(mRootTaskLeash)
+ .show(mTaskLeash1)
+ .show(mTaskLeash2));
+ }
+
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ if (taskInfo.taskId == getRootTaskId()) {
+ mRootTaskInfo = taskInfo;
+ } else if (taskInfo.taskId == getTaskId1()) {
+ mTaskInfo1 = taskInfo;
+ } else if (taskInfo.taskId == getTaskId2()) {
+ mTaskInfo2 = taskInfo;
+ } else {
+ throw new IllegalStateException("Unknown task=" + taskInfo.taskId);
+ }
+ }
+
+ @Override
+ public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ if (taskInfo.taskId == getRootTaskId()) {
+ // We don't want to release this object back to the pool since the root task went away.
+ mController.unpair(mRootTaskInfo.taskId, false /* releaseToPool */);
+ } else if (taskInfo.taskId == getTaskId1() || taskInfo.taskId == getTaskId2()) {
+ mController.unpair(mRootTaskInfo.taskId);
+ }
+ }
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ final String childPrefix = innerPrefix + " ";
+ pw.println(prefix + this);
+ pw.println(innerPrefix + "Root taskId=" + getRootTaskId()
+ + " winMode=" + mRootTaskInfo.getWindowingMode());
+ if (mTaskInfo1 != null) {
+ pw.println(innerPrefix + "1 taskId=" + mTaskInfo1.taskId
+ + " winMode=" + mTaskInfo1.getWindowingMode());
+ }
+ if (mTaskInfo2 != null) {
+ pw.println(innerPrefix + "2 taskId=" + mTaskInfo2.taskId
+ + " winMode=" + mTaskInfo2.getWindowingMode());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return TAG + "#" + getRootTaskId();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
new file mode 100644
index 000000000000..ef3e3e0220e7
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairs.java
@@ -0,0 +1,39 @@
+/*
+ * 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.wm.shell.apppairs;
+
+import android.app.ActivityManager;
+
+import androidx.annotation.NonNull;
+
+import java.io.PrintWriter;
+
+/**
+ * Interface to engage app pairs feature.
+ */
+public interface AppPairs {
+ /** Pairs indicated tasks. */
+ boolean pair(int task1, int task2);
+ /** Pairs indicated tasks. */
+ boolean pair(ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2);
+ /** Unpairs any app-pair containing this task id. */
+ void unpair(int taskId);
+ /** Dumps current status of app pairs. */
+ void dump(@NonNull PrintWriter pw, String prefix);
+ /** Called when the shell organizer has been registered. */
+ void onOrganizerRegistered();
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
new file mode 100644
index 000000000000..e0c7ba9234b2
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java
@@ -0,0 +1,150 @@
+/*
+ * 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.wm.shell.apppairs;
+
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
+
+import android.app.ActivityManager;
+import android.util.SparseArray;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+import java.io.PrintWriter;
+
+/**
+ * Class manages app-pairs multitasking mode and implements the main interface {@link AppPairs}.
+ */
+public class AppPairsController implements AppPairs {
+ private static final String TAG = AppPairsController.class.getSimpleName();
+
+ private final ShellTaskOrganizer mTaskOrganizer;
+ private final SyncTransactionQueue mSyncQueue;
+
+ private AppPairsPool mPairsPool;
+ // Active app-pairs mapped by root task id key.
+ private final SparseArray<AppPair> mActiveAppPairs = new SparseArray<>();
+
+ public AppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue) {
+ mTaskOrganizer = organizer;
+ mSyncQueue = syncQueue;
+ }
+
+ @Override
+ public void onOrganizerRegistered() {
+ if (mPairsPool == null) {
+ setPairsPool(new AppPairsPool(this));
+ }
+ }
+
+ @VisibleForTesting
+ void setPairsPool(AppPairsPool pool) {
+ mPairsPool = pool;
+ }
+
+ @Override
+ public boolean pair(int taskId1, int taskId2) {
+ final ActivityManager.RunningTaskInfo task1 = mTaskOrganizer.getRunningTaskInfo(taskId1);
+ final ActivityManager.RunningTaskInfo task2 = mTaskOrganizer.getRunningTaskInfo(taskId2);
+ if (task1 == null || task2 == null) {
+ return false;
+ }
+ return pair(task1, task2);
+ }
+
+ @Override
+ public boolean pair(ActivityManager.RunningTaskInfo task1,
+ ActivityManager.RunningTaskInfo task2) {
+ return pairInner(task1, task2) != null;
+ }
+
+ @VisibleForTesting
+ AppPair pairInner(
+ @NonNull ActivityManager.RunningTaskInfo task1,
+ @NonNull ActivityManager.RunningTaskInfo task2) {
+ final AppPair pair = mPairsPool.acquire();
+ if (!pair.pair(task1, task2)) {
+ mPairsPool.release(pair);
+ return null;
+ }
+
+ mActiveAppPairs.put(pair.getRootTaskId(), pair);
+ return pair;
+ }
+
+ @Override
+ public void unpair(int taskId) {
+ unpair(taskId, true /* releaseToPool */);
+ }
+
+ void unpair(int taskId, boolean releaseToPool) {
+ AppPair pair = mActiveAppPairs.get(taskId);
+ if (pair == null) {
+ for (int i = mActiveAppPairs.size() - 1; i >= 0; --i) {
+ final AppPair candidate = mActiveAppPairs.valueAt(i);
+ if (candidate.contains(taskId)) {
+ pair = candidate;
+ break;
+ }
+ }
+ }
+ if (pair == null) {
+ ProtoLog.v(WM_SHELL_TASK_ORG, "taskId %d isn't isn't in an app-pair.", taskId);
+ return;
+ }
+
+ ProtoLog.v(WM_SHELL_TASK_ORG, "unpair taskId=%d pair=%s", taskId, pair);
+ mActiveAppPairs.remove(pair.getRootTaskId());
+ pair.unpair();
+ if (releaseToPool) {
+ mPairsPool.release(pair);
+ }
+ }
+
+ ShellTaskOrganizer getTaskOrganizer() {
+ return mTaskOrganizer;
+ }
+
+ SyncTransactionQueue getSyncTransactionQueue() {
+ return mSyncQueue;
+ }
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ final String childPrefix = innerPrefix + " ";
+ pw.println(prefix + this);
+
+ for (int i = mActiveAppPairs.size() - 1; i >= 0; --i) {
+ mActiveAppPairs.valueAt(i).dump(pw, childPrefix);
+ }
+
+ if (mPairsPool != null) {
+ mPairsPool.dump(pw, prefix);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return TAG + "#" + mActiveAppPairs.size();
+ }
+
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsPool.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsPool.java
new file mode 100644
index 000000000000..5c6037ea0702
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsPool.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.apppairs;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ProtoLog;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Class that manager pool of {@link AppPair} objects. Helps reduce the need to call system_server
+ * to create a root task for the app-pair when needed since we always have one ready to go.
+ */
+class AppPairsPool {
+ private static final String TAG = AppPairsPool.class.getSimpleName();
+
+ @VisibleForTesting
+ final AppPairsController mController;
+ // The pool
+ private final ArrayList<AppPair> mPool = new ArrayList();
+
+ AppPairsPool(AppPairsController controller) {
+ mController = controller;
+ incrementPool();
+ }
+
+ AppPair acquire() {
+ final AppPair entry = mPool.remove(mPool.size() - 1);
+ ProtoLog.v(WM_SHELL_TASK_ORG, "acquire entry.taskId=%s listener=%s size=%d",
+ entry.getRootTaskId(), entry, mPool.size());
+ if (mPool.size() == 0) {
+ incrementPool();
+ }
+ return entry;
+ }
+
+ void release(AppPair entry) {
+ mPool.add(entry);
+ ProtoLog.v(WM_SHELL_TASK_ORG, "release entry.taskId=%s listener=%s size=%d",
+ entry.getRootTaskId(), entry, mPool.size());
+ }
+
+ @VisibleForTesting
+ void incrementPool() {
+ ProtoLog.v(WM_SHELL_TASK_ORG, "incrementPool size=%d", mPool.size());
+ final AppPair entry = new AppPair(mController);
+ // TODO: multi-display...
+ mController.getTaskOrganizer().createRootTask(
+ DEFAULT_DISPLAY, WINDOWING_MODE_FULLSCREEN, entry);
+ mPool.add(entry);
+ }
+
+ @VisibleForTesting
+ int poolSize() {
+ return mPool.size();
+ }
+
+ public void dump(@NonNull PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ final String childPrefix = innerPrefix + " ";
+ pw.println(prefix + this);
+ for (int i = mPool.size() - 1; i >= 0; --i) {
+ mPool.get(i).dump(pw, childPrefix);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return TAG + "#" + mPool.size();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java
index 8bcffc8ece1a..32c6e368583d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.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.
@@ -13,7 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
+
+import static android.graphics.Paint.DITHER_FLAG;
+import static android.graphics.Paint.FILTER_BITMAP_FLAG;
import android.annotation.Nullable;
import android.content.Context;
@@ -28,14 +31,10 @@ import android.util.PathParser;
import android.widget.ImageView;
import com.android.launcher3.icons.DotRenderer;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
+import com.android.wm.shell.animation.Interpolators;
import java.util.EnumSet;
-import static android.graphics.Paint.DITHER_FLAG;
-import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-
/**
* View that displays an adaptive icon with an app-badge and a dot.
*
@@ -75,9 +74,8 @@ public class BadgedImageView extends ImageView {
private boolean mDotIsAnimating = false;
private BubbleViewProvider mBubble;
+ private BubblePositioner mPositioner;
- private int mBubbleBitmapSize;
- private int mBubbleSize;
private DotRenderer mDotRenderer;
private DotRenderer.DrawParams mDrawParams;
private boolean mOnLeft;
@@ -101,18 +99,21 @@ public class BadgedImageView extends ImageView {
public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mBubbleBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size);
- mBubbleSize = getResources().getDimensionPixelSize(R.dimen.individual_bubble_size);
mDrawParams = new DotRenderer.DrawParams();
- Path iconPath = PathParser.createPathFromPathData(
- getResources().getString(com.android.internal.R.string.config_icon_mask));
- mDotRenderer = new DotRenderer(mBubbleBitmapSize, iconPath, DEFAULT_PATH_SIZE);
-
setFocusable(true);
setClickable(true);
}
+ public void initialize(BubblePositioner positioner) {
+ mPositioner = positioner;
+
+ Path iconPath = PathParser.createPathFromPathData(
+ getResources().getString(com.android.internal.R.string.config_icon_mask));
+ mDotRenderer = new DotRenderer(mPositioner.getBubbleBitmapSize(),
+ iconPath, DEFAULT_PATH_SIZE);
+ }
+
public void showDotAndBadge(boolean onLeft) {
removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.BEHIND_STACK);
animateDotBadgePositions(onLeft);
@@ -186,7 +187,8 @@ public class BadgedImageView extends ImageView {
* @param iconPath The new icon path to use when calculating dot position.
*/
void drawDot(Path iconPath) {
- mDotRenderer = new DotRenderer(mBubbleBitmapSize, iconPath, DEFAULT_PATH_SIZE);
+ mDotRenderer = new DotRenderer(mPositioner.getBubbleBitmapSize(),
+ iconPath, DEFAULT_PATH_SIZE);
invalidate();
}
@@ -310,13 +312,13 @@ public class BadgedImageView extends ImageView {
bubbleCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG));
bubbleCanvas.setBitmap(bubble);
-
- final int badgeSize = (int) (ICON_BADGE_SCALE * mBubbleSize);
+ final int bubbleSize = bubble.getWidth();
+ final int badgeSize = (int) (ICON_BADGE_SCALE * bubbleSize);
if (mOnLeft) {
- badge.setBounds(0, mBubbleSize - badgeSize, badgeSize, mBubbleSize);
+ badge.setBounds(0, bubbleSize - badgeSize, badgeSize, bubbleSize);
} else {
- badge.setBounds(mBubbleSize - badgeSize, mBubbleSize - badgeSize,
- mBubbleSize, mBubbleSize);
+ badge.setBounds(bubbleSize - badgeSize, bubbleSize - badgeSize,
+ bubbleSize, bubbleSize);
}
badge.draw(bubbleCanvas);
bubbleCanvas.setBitmap(null);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 09d9e03cb0cb..122f91720bbd 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.os.AsyncTask.Status.FINISHED;
@@ -310,7 +310,7 @@ public class Bubble implements BubbleViewProvider {
*
* @param callback the callback to notify one the bubble is ready to be displayed.
* @param context the context for the bubble.
- * @param controller
+ * @param controller the bubble controller.
* @param stackView the stackView the bubble is eventually added to.
* @param iconFactory the iconfactory use to create badged images for the bubble.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 598a604099ac..eb3a3a276727 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.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.bubbles;
+package com.android.wm.shell.bubbles;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
@@ -22,8 +22,8 @@ import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -59,8 +59,6 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.bubbles.dagger.BubbleModule;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -97,12 +95,6 @@ public class BubbleController implements Bubbles {
private BubblePositioner mBubblePositioner;
private SysuiProxy mSysuiProxy;
- /**
- * The relative position of the stack when we removed it and nulled it out. If the stack is
- * re-created, it will re-appear at this position.
- */
- @Nullable private BubbleStackView.RelativeStackPosition mPositionFromRemovedStack;
-
// Tracks the id of the current (foreground) user.
private int mCurrentUserId;
// Saves notification keys of active bubbles when users are switched.
@@ -165,7 +157,7 @@ public class BubbleController implements Bubbles {
private boolean mIsStatusBarShade = true;
/**
- * Injected constructor. See {@link BubbleModule}.
+ * Injected constructor.
*/
public static BubbleController create(Context context,
@Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
@@ -175,15 +167,15 @@ public class BubbleController implements Bubbles {
WindowManagerShellWrapper windowManagerShellWrapper,
LauncherApps launcherApps,
UiEventLogger uiEventLogger,
- @Main Handler mainHandler,
+ Handler mainHandler,
ShellTaskOrganizer organizer) {
BubbleLogger logger = new BubbleLogger(uiEventLogger);
- return new BubbleController(context,
- new BubbleData(context, logger), synchronizer,
- floatingContentCoordinator, new BubbleDataRepository(context, launcherApps),
- statusBarService, windowManager,
- windowManagerShellWrapper, launcherApps, logger, mainHandler, organizer,
- new BubblePositioner(context, windowManager));
+ BubblePositioner positioner = new BubblePositioner(context, windowManager);
+ BubbleData data = new BubbleData(context, logger, positioner);
+ return new BubbleController(context, data, synchronizer, floatingContentCoordinator,
+ new BubbleDataRepository(context, launcherApps),
+ statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
+ logger, mainHandler, organizer, positioner);
}
/**
@@ -209,6 +201,7 @@ public class BubbleController implements Bubbles {
mLogger = bubbleLogger;
mMainHandler = mainHandler;
+ mBubblePositioner = positioner;
mBubbleData = data;
mBubbleData.setListener(mBubbleDataListener);
mBubbleData.setSuppressionChangedListener(bubble -> {
@@ -251,7 +244,6 @@ public class BubbleController implements Bubbles {
mBubbleIconFactory = new BubbleIconFactory(context);
mTaskOrganizer = organizer;
- mBubblePositioner = positioner;
launcherApps.registerCallback(new LauncherApps.Callback() {
@Override
@@ -390,8 +382,6 @@ public class BubbleController implements Bubbles {
if (mStackView == null) {
mStackView = new BubbleStackView(
mContext, this, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator);
- mStackView.setStackStartPosition(mPositionFromRemovedStack);
- mStackView.addView(mBubbleScrim);
mStackView.onOrientationChanged();
if (mExpandListener != null) {
mStackView.setExpandListener(mExpandListener);
@@ -431,7 +421,11 @@ public class BubbleController implements Bubbles {
try {
mAddedToWindowManager = true;
+ mBubbleData.getOverflow().initialize(this);
+ mStackView.addView(mBubbleScrim);
mWindowManager.addView(mStackView, mWmLayoutParams);
+ // Position info is dependent on us being attached to a window
+ mBubblePositioner.update(mOrientation);
} catch (IllegalStateException e) {
// This means the stack has already been added. This shouldn't happen...
e.printStackTrace();
@@ -451,10 +445,9 @@ public class BubbleController implements Bubbles {
try {
mAddedToWindowManager = false;
if (mStackView != null) {
- mPositionFromRemovedStack = mStackView.getRelativeStackPosition();
mWindowManager.removeView(mStackView);
mStackView.removeView(mBubbleScrim);
- mStackView = null;
+ mBubbleData.getOverflow().cleanUpExpandedState();
} else {
Log.w(TAG, "StackView added to WindowManager, but was null when removing!");
}
@@ -546,7 +539,7 @@ public class BubbleController implements Bubbles {
}
if (newConfig.fontScale != mFontScale) {
mFontScale = newConfig.fontScale;
- mStackView.updateFlyout(mFontScale);
+ mStackView.updateFontScale(mFontScale);
}
if (newConfig.getLayoutDirection() != mLayoutDirection) {
mLayoutDirection = newConfig.getLayoutDirection();
@@ -586,7 +579,7 @@ public class BubbleController implements Bubbles {
if (mStackView == null) {
return false;
}
- return mBubbleData.hasBubbles();
+ return mBubbleData.hasBubbles() || mBubbleData.isShowingOverflow();
}
@Override
@@ -903,7 +896,7 @@ public class BubbleController implements Bubbles {
}
if (!mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
if (!mBubbleData.hasOverflowBubbleWithKey(bubble.getKey())
- && (!bubble.showInShade()
+ && (!bubble.showInShade()
|| reason == DISMISS_NOTIF_CANCEL
|| reason == DISMISS_GROUP_CANCELLED)) {
// The bubble is now gone & the notification is hidden from the shade, so
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 8cacc8f2ef01..e24ff063b661 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.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.
@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.NonNull;
import android.app.PendingIntent;
@@ -33,8 +33,8 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.systemui.R;
-import com.android.systemui.bubbles.Bubbles.DismissReason;
+import com.android.wm.shell.R;
+import com.android.wm.shell.bubbles.Bubbles.DismissReason;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -69,7 +69,7 @@ public class BubbleData {
boolean selectionChanged;
boolean orderChanged;
boolean expanded;
- @Nullable Bubble selectedBubble;
+ @Nullable BubbleViewProvider selectedBubble;
@Nullable Bubble addedBubble;
@Nullable Bubble updatedBubble;
@Nullable Bubble addedOverflowBubble;
@@ -116,13 +116,15 @@ public class BubbleData {
}
private final Context mContext;
+ private final BubblePositioner mPositioner;
/** Bubbles that are actively in the stack. */
private final List<Bubble> mBubbles;
/** Bubbles that aged out to overflow. */
private final List<Bubble> mOverflowBubbles;
/** Bubbles that are being loaded but haven't been added to the stack just yet. */
private final HashMap<String, Bubble> mPendingBubbles;
- private Bubble mSelectedBubble;
+ private BubbleViewProvider mSelectedBubble;
+ private final BubbleOverflow mOverflow;
private boolean mShowingOverflow;
private boolean mExpanded;
private final int mMaxBubbles;
@@ -153,9 +155,11 @@ public class BubbleData {
*/
private HashMap<String, String> mSuppressedGroupKeys = new HashMap<>();
- public BubbleData(Context context, BubbleLogger bubbleLogger) {
+ public BubbleData(Context context, BubbleLogger bubbleLogger, BubblePositioner positioner) {
mContext = context;
mLogger = bubbleLogger;
+ mPositioner = positioner;
+ mOverflow = new BubbleOverflow(context, positioner);
mBubbles = new ArrayList<>();
mOverflowBubbles = new ArrayList<>();
mPendingBubbles = new HashMap<>();
@@ -178,6 +182,10 @@ public class BubbleData {
return !mBubbles.isEmpty();
}
+ public boolean hasOverflowBubbles() {
+ return !mOverflowBubbles.isEmpty();
+ }
+
public boolean isExpanded() {
return mExpanded;
}
@@ -195,10 +203,14 @@ public class BubbleData {
}
@Nullable
- public Bubble getSelectedBubble() {
+ public BubbleViewProvider getSelectedBubble() {
return mSelectedBubble;
}
+ public BubbleOverflow getOverflow() {
+ return mOverflow;
+ }
+
/** Return a read-only current active bubble lists. */
public List<Bubble> getActiveBubbles() {
return Collections.unmodifiableList(mBubbles);
@@ -212,7 +224,7 @@ public class BubbleData {
dispatchPendingChanges();
}
- public void setSelectedBubble(Bubble bubble) {
+ public void setSelectedBubble(BubbleViewProvider bubble) {
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "setSelectedBubble: " + bubble);
}
@@ -224,6 +236,10 @@ public class BubbleData {
mShowingOverflow = showingOverflow;
}
+ boolean isShowingOverflow() {
+ return mShowingOverflow && (isExpanded() || mPositioner.showingInTaskbar());
+ }
+
/**
* Constructs a new bubble or returns an existing one. Does not add new bubbles to
* bubble data, must go through {@link #notificationEntryUpdated(Bubble, boolean, boolean)}
@@ -264,8 +280,8 @@ public class BubbleData {
/**
* When this method is called it is expected that all info in the bubble has completed loading.
- * @see Bubble#inflate(BubbleViewInfoTask.Callback, Context,
- * BubbleStackView, BubbleIconFactory, boolean).
+ * @see Bubble#inflate(BubbleViewInfoTask.Callback, Context, BubbleController, BubbleStackView,
+ * BubbleIconFactory, boolean)
*/
void notificationEntryUpdated(Bubble bubble, boolean suppressFlyout, boolean showInShade) {
if (DEBUG_BUBBLE_DATA) {
@@ -484,10 +500,17 @@ public class BubbleData {
Bubble bubbleToRemove = mBubbles.get(indexToRemove);
bubbleToRemove.stopInflation();
if (mBubbles.size() == 1) {
- // Going to become empty, handle specially.
- setExpandedInternal(false);
- // Don't use setSelectedBubbleInternal because we don't want to trigger an applyUpdate
- mSelectedBubble = null;
+ if (hasOverflowBubbles() && (mPositioner.showingInTaskbar() || isExpanded())) {
+ // No more active bubbles but we have stuff in the overflow -- select that view
+ // if we're already expanded or always showing.
+ setShowingOverflow(true);
+ setSelectedBubbleInternal(mOverflow);
+ } else {
+ setExpandedInternal(false);
+ // Don't use setSelectedBubbleInternal because we don't want to trigger an
+ // applyUpdate
+ mSelectedBubble = null;
+ }
}
if (indexToRemove < mBubbles.size() - 1) {
// Removing anything but the last bubble means positions will change.
@@ -505,7 +528,7 @@ public class BubbleData {
if (Objects.equals(mSelectedBubble, bubbleToRemove)) {
// Move selection to the new bubble at the same position.
int newIndex = Math.min(indexToRemove, mBubbles.size() - 1);
- Bubble newSelected = mBubbles.get(newIndex);
+ BubbleViewProvider newSelected = mBubbles.get(newIndex);
setSelectedBubbleInternal(newSelected);
}
maybeSendDeleteIntent(reason, bubbleToRemove);
@@ -564,7 +587,7 @@ public class BubbleData {
*
* @param bubble the new selected bubble
*/
- private void setSelectedBubbleInternal(@Nullable Bubble bubble) {
+ private void setSelectedBubbleInternal(@Nullable BubbleViewProvider bubble) {
if (DEBUG_BUBBLE_DATA) {
Log.d(TAG, "setSelectedBubbleInternal: " + bubble);
}
@@ -572,14 +595,17 @@ public class BubbleData {
return;
}
// Otherwise, if we are showing the overflow menu, return to the previously selected bubble.
-
- if (bubble != null && !mBubbles.contains(bubble) && !mOverflowBubbles.contains(bubble)) {
+ boolean isOverflow = bubble != null && BubbleOverflow.KEY.equals(bubble.getKey());
+ if (bubble != null
+ && !mBubbles.contains(bubble)
+ && !mOverflowBubbles.contains(bubble)
+ && !isOverflow) {
Log.e(TAG, "Cannot select bubble which doesn't exist!"
+ " (" + bubble + ") bubbles=" + mBubbles);
return;
}
- if (mExpanded && bubble != null) {
- bubble.markAsAccessedAt(mTimeSource.currentTimeMillis());
+ if (mExpanded && bubble != null && !isOverflow) {
+ ((Bubble) bubble).markAsAccessedAt(mTimeSource.currentTimeMillis());
}
mSelectedBubble = bubble;
mStateChange.selectedBubble = bubble;
@@ -629,7 +655,7 @@ public class BubbleData {
return;
}
if (shouldExpand) {
- if (mBubbles.isEmpty()) {
+ if (mBubbles.isEmpty() && !mShowingOverflow) {
Log.e(TAG, "Attempt to expand stack when empty!");
return;
}
@@ -637,7 +663,9 @@ public class BubbleData {
Log.e(TAG, "Attempt to expand stack without selected bubble!");
return;
}
- mSelectedBubble.markAsAccessedAt(mTimeSource.currentTimeMillis());
+ if (mSelectedBubble instanceof Bubble) {
+ ((Bubble) mSelectedBubble).markAsAccessedAt(mTimeSource.currentTimeMillis());
+ }
mStateChange.orderChanged |= repackAll();
} else if (!mBubbles.isEmpty()) {
// Apply ordering and grouping rules from expanded -> collapsed, then save
@@ -647,14 +675,18 @@ public class BubbleData {
if (mShowingOverflow) {
// Show previously selected bubble instead of overflow menu on next expansion.
- setSelectedBubbleInternal(mSelectedBubble);
+ if (!mSelectedBubble.getKey().equals(mOverflow.getKey())) {
+ setSelectedBubbleInternal(mSelectedBubble);
+ } else {
+ setSelectedBubbleInternal(mBubbles.get(0));
+ }
}
if (mBubbles.indexOf(mSelectedBubble) > 0) {
// Move the selected bubble to the top while collapsed.
int index = mBubbles.indexOf(mSelectedBubble);
if (index != 0) {
- mBubbles.remove(mSelectedBubble);
- mBubbles.add(0, mSelectedBubble);
+ mBubbles.remove((Bubble) mSelectedBubble);
+ mBubbles.add(0, (Bubble) mSelectedBubble);
mStateChange.orderChanged = true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index 2ab9e8734bef..fc565f17546d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles
+package com.android.wm.shell.bubbles
import android.annotation.SuppressLint
import android.annotation.UserIdInt
@@ -24,9 +24,9 @@ import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC
import android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
import android.os.UserHandle
import android.util.Log
-import com.android.systemui.bubbles.storage.BubbleEntity
-import com.android.systemui.bubbles.storage.BubblePersistentRepository
-import com.android.systemui.bubbles.storage.BubbleVolatileRepository
+import com.android.wm.shell.bubbles.storage.BubbleEntity
+import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
+import com.android.wm.shell.bubbles.storage.BubbleVolatileRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.java
index 3937422750cc..dc2ace949f0c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDebugConfig.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.bubbles;
+package com.android.wm.shell.bubbles;
import android.content.Context;
import android.provider.Settings;
@@ -45,6 +45,7 @@ public class BubbleDebugConfig {
static final boolean DEBUG_EXPERIMENTS = true;
static final boolean DEBUG_OVERFLOW = false;
static final boolean DEBUG_USER_EDUCATION = false;
+ static final boolean DEBUG_POSITIONER = false;
private static final boolean FORCE_SHOW_USER_EDUCATION = false;
private static final String FORCE_SHOW_USER_EDUCATION_SETTING =
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleEntry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java
index a0d3391f8347..ff68861eb40c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleEntry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEntry.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static android.app.Notification.FLAG_BUBBLE;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index ae3c683cb165..45ffe6b20984 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.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,21 +14,22 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.systemui.bubbles.BubbleOverflowActivity.EXTRA_BUBBLE_CONTROLLER;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_EXPANDED_VIEW;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleOverflowActivity.EXTRA_BUBBLE_CONTROLLER;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -41,6 +42,7 @@ import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
import android.os.Bundle;
+import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceControl;
@@ -54,10 +56,11 @@ import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.systemui.R;
-import com.android.systemui.recents.TriangleShape;
-import com.android.systemui.statusbar.AlphaOptimizedButton;
+import com.android.wm.shell.R;
+import com.android.wm.shell.TaskView;
+import com.android.wm.shell.common.AlphaOptimizedButton;
import com.android.wm.shell.common.HandlerExecutor;
+import com.android.wm.shell.common.TriangleShape;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -638,12 +641,21 @@ public class BubbleExpandedView extends LinearLayout {
}
/**
- * Cleans up anything related to the task and TaskView.
+ * Cleans up anything related to the task and TaskView. If this view should be reused after this
+ * method is called, then {@link #initialize(BubbleController, BubbleStackView)} must be invoked
+ * first.
*/
public void cleanUpExpandedState() {
if (DEBUG_BUBBLE_EXPANDED_VIEW) {
Log.d(TAG, "cleanUpExpandedState: bubble=" + getBubbleKey() + " task=" + mTaskId);
}
+ if (getTaskId() != INVALID_TASK_ID) {
+ try {
+ ActivityTaskManager.getService().removeTask(getTaskId());
+ } catch (RemoteException e) {
+ Log.w(TAG, e.getMessage());
+ }
+ }
if (mTaskView != null) {
mTaskView.release();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java
index d8b32500db85..19c3cf9c462a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.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,12 +14,13 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static android.graphics.Paint.ANTI_ALIAS_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
-import static com.android.systemui.Interpolators.ALPHA_IN;
-import static com.android.systemui.Interpolators.ALPHA_OUT;
+
+import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
+import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
import android.animation.ArgbEvaluator;
import android.content.Context;
@@ -47,8 +48,8 @@ import android.widget.TextView;
import androidx.annotation.Nullable;
-import com.android.systemui.R;
-import com.android.systemui.recents.TriangleShape;
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.TriangleShape;
/**
* Flyout view that appears as a 'chat bubble' alongside the bubble stack. The flyout can visually
@@ -67,9 +68,8 @@ public class BubbleFlyoutView extends FrameLayout {
private final int mFlyoutPadding;
private final int mFlyoutSpaceFromBubble;
private final int mPointerSize;
- private final int mBubbleSize;
- private final int mBubbleBitmapSize;
- private final float mBubbleIconTopPadding;
+ private int mBubbleSize;
+ private int mBubbleBitmapSize;
private final int mFlyoutElevation;
private final int mBubbleElevation;
@@ -82,9 +82,9 @@ public class BubbleFlyoutView extends FrameLayout {
private final TextView mMessageText;
/** Values related to the 'new' dot which we use to figure out where to collapse the flyout. */
- private final float mNewDotRadius;
- private final float mNewDotSize;
- private final float mOriginalDotSize;
+ private float mNewDotRadius;
+ private float mNewDotSize;
+ private float mOriginalDotSize;
/**
* The paint used to draw the background, whose color changes as the flyout transitions to the
@@ -168,17 +168,9 @@ public class BubbleFlyoutView extends FrameLayout {
mFlyoutSpaceFromBubble = res.getDimensionPixelSize(R.dimen.bubble_flyout_space_from_bubble);
mPointerSize = res.getDimensionPixelSize(R.dimen.bubble_flyout_pointer_size);
- mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
- mBubbleBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_bitmap_size);
- mBubbleIconTopPadding = (mBubbleSize - mBubbleBitmapSize) / 2f;
-
mBubbleElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
mFlyoutElevation = res.getDimensionPixelSize(R.dimen.bubble_flyout_elevation);
- mOriginalDotSize = SIZE_PERCENTAGE * mBubbleBitmapSize;
- mNewDotRadius = (DOT_SCALE * mOriginalDotSize) / 2f;
- mNewDotSize = mNewDotRadius * 2f;
-
final TypedArray ta = mContext.obtainStyledAttributes(
new int[] {
android.R.attr.colorBackgroundFloating,
@@ -305,7 +297,15 @@ public class BubbleFlyoutView extends FrameLayout {
@Nullable Runnable onLayoutComplete,
@Nullable Runnable onHide,
float[] dotCenter,
- boolean hideDot) {
+ boolean hideDot,
+ BubblePositioner positioner) {
+
+ mBubbleBitmapSize = positioner.getBubbleBitmapSize();
+ mBubbleSize = positioner.getBubbleSize();
+
+ mOriginalDotSize = SIZE_PERCENTAGE * mBubbleBitmapSize;
+ mNewDotRadius = (DOT_SCALE * mOriginalDotSize) / 2f;
+ mNewDotSize = mNewDotRadius * 2f;
updateFlyoutMessage(flyoutMessage, parentWidth);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java
index 371e8490d235..2d9da215efb7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,14 +26,13 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.ShadowGenerator;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
/**
* Factory for creating normalized bubble icons.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
index a24f5c2b54c5..3361c4ce11da 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEvent;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index 297144a86143..8ab2f6325d2b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles
+package com.android.wm.shell.bubbles
import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.content.Context
@@ -29,14 +29,18 @@ import android.graphics.drawable.InsetDrawable
import android.util.PathParser
import android.util.TypedValue
import android.view.LayoutInflater
-import android.view.View
import android.widget.FrameLayout
-import com.android.systemui.R
+import com.android.wm.shell.R
+
+/**
+ * The icon in the bubble overflow is scaled down, this is the percent of the normal bubble bitmap
+ * size to use.
+ */
+const val ICON_BITMAP_SIZE_PERCENT = 0.46f
class BubbleOverflow(
private val context: Context,
- private val controller: BubbleController,
- private val stack: BubbleStackView
+ private val positioner: BubblePositioner
) : BubbleViewProvider {
private lateinit var bitmap: Bitmap
@@ -48,41 +52,42 @@ class BubbleOverflow(
private var showDot = false
private val inflater: LayoutInflater = LayoutInflater.from(context)
- private val expandedView: BubbleExpandedView = inflater
- .inflate(R.layout.bubble_expanded_view, null /* root */, false /* attachToRoot */)
- as BubbleExpandedView
- private val overflowBtn: BadgedImageView = inflater
- .inflate(R.layout.bubble_overflow_button, null /* root */, false /* attachToRoot */)
- as BadgedImageView
+ private var expandedView: BubbleExpandedView?
+ private var overflowBtn: BadgedImageView?
+
init {
updateResources()
- with(expandedView) {
- initialize(controller, stack)
- setOverflow(true)
- applyThemeAttrs()
- }
- with(overflowBtn) {
- setContentDescription(context.resources.getString(
- R.string.bubble_overflow_button_content_description))
- updateBtnTheme()
- }
+ bitmapSize = positioner.bubbleBitmapSize
+ iconBitmapSize = (bitmapSize * ICON_BITMAP_SIZE_PERCENT).toInt()
+ expandedView = null
+ overflowBtn = null
+ }
+
+ /** Call before use and again if cleanUpExpandedState was called. */
+ fun initialize(controller: BubbleController) {
+ getExpandedView()?.initialize(controller, controller.stackView)
+ getExpandedView()?.setOverflow(true)
+ }
+
+ fun cleanUpExpandedState() {
+ expandedView?.cleanUpExpandedState()
+ expandedView = null
}
fun update() {
updateResources()
- expandedView.applyThemeAttrs()
+ getExpandedView()?.applyThemeAttrs()
// Apply inset and new style to fresh icon drawable.
- overflowBtn.setImageResource(R.drawable.ic_bubble_overflow_button)
+ getIconView()?.setImageResource(R.drawable.bubble_ic_overflow_button)
updateBtnTheme()
}
fun updateResources() {
- bitmapSize = context.resources.getDimensionPixelSize(R.dimen.bubble_bitmap_size)
- iconBitmapSize = context.resources.getDimensionPixelSize(
- R.dimen.bubble_overflow_icon_bitmap_size)
- val bubbleSize = context.resources.getDimensionPixelSize(R.dimen.individual_bubble_size)
- overflowBtn.setLayoutParams(FrameLayout.LayoutParams(bubbleSize, bubbleSize))
- expandedView.updateDimensions()
+ bitmapSize = positioner.bubbleBitmapSize
+ iconBitmapSize = (bitmapSize * 0.46f).toInt()
+ val bubbleSize = positioner.bubbleSize
+ overflowBtn?.setLayoutParams(FrameLayout.LayoutParams(bubbleSize, bubbleSize))
+ expandedView?.updateDimensions()
}
private fun updateBtnTheme() {
@@ -92,7 +97,7 @@ class BubbleOverflow(
val typedValue = TypedValue()
context.theme.resolveAttribute(android.R.attr.colorAccent, typedValue, true)
val colorAccent = res.getColor(typedValue.resourceId)
- overflowBtn.drawable?.setTint(colorAccent)
+ overflowBtn?.drawable?.setTint(colorAccent)
dotColor = colorAccent
val iconFactory = BubbleIconFactory(context)
@@ -103,7 +108,7 @@ class BubbleOverflow(
val bg = ColorDrawable(res.getColor(
if (nightMode) R.color.bubbles_dark else R.color.bubbles_light))
- val fg = InsetDrawable(overflowBtn.drawable,
+ val fg = InsetDrawable(overflowBtn?.drawable,
bitmapSize - iconBitmapSize /* inset */)
bitmap = iconFactory.createBadgedIconBitmap(AdaptiveIconDrawable(bg, fg),
null /* user */, true /* shrinkNonAdaptiveIcons */).icon
@@ -111,7 +116,7 @@ class BubbleOverflow(
// Update dot path
dotPath = PathParser.createPathFromPathData(
res.getString(com.android.internal.R.string.config_icon_mask))
- val scale = iconFactory.normalizer.getScale(overflowBtn.getDrawable(),
+ val scale = iconFactory.normalizer.getScale(getIconView()!!.getDrawable(),
null /* outBounds */, null /* path */, null /* outMaskShape */)
val radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f
val matrix = Matrix()
@@ -120,20 +125,26 @@ class BubbleOverflow(
dotPath.transform(matrix)
// Attach BubbleOverflow to BadgedImageView
- overflowBtn.setRenderedBubble(this)
- overflowBtn.removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE)
+ overflowBtn?.setRenderedBubble(this)
+ overflowBtn?.removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE)
}
fun setVisible(visible: Int) {
- overflowBtn.visibility = visible
+ overflowBtn?.visibility = visible
}
fun setShowDot(show: Boolean) {
showDot = show
- overflowBtn.updateDotVisibility(true /* animate */)
+ overflowBtn?.updateDotVisibility(true /* animate */)
}
override fun getExpandedView(): BubbleExpandedView? {
+ if (expandedView == null) {
+ expandedView = inflater.inflate(R.layout.bubble_expanded_view,
+ null /* root */, false /* attachToRoot */) as BubbleExpandedView
+ expandedView?.applyThemeAttrs()
+ updateResources()
+ }
return expandedView
}
@@ -158,10 +169,20 @@ class BubbleOverflow(
}
override fun setContentVisibility(visible: Boolean) {
- expandedView.setContentVisibility(visible)
- }
-
- override fun getIconView(): View? {
+ expandedView?.setContentVisibility(visible)
+ }
+
+ override fun getIconView(): BadgedImageView? {
+ if (overflowBtn == null) {
+ overflowBtn = inflater.inflate(R.layout.bubble_overflow_button,
+ null /* root */, false /* attachToRoot */) as BadgedImageView
+ overflowBtn?.initialize(positioner)
+ overflowBtn?.setContentDescription(context.resources.getString(
+ R.string.bubble_overflow_button_content_description))
+ val bubbleSize = positioner.bubbleSize
+ overflowBtn?.setLayoutParams(FrameLayout.LayoutParams(bubbleSize, bubbleSize))
+ updateBtnTheme()
+ }
return overflowBtn
}
@@ -170,7 +191,7 @@ class BubbleOverflow(
}
override fun getTaskId(): Int {
- return if (expandedView != null) expandedView.getTaskId() else INVALID_TASK_ID
+ return if (expandedView != null) expandedView!!.getTaskId() else INVALID_TASK_ID
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java
index bc841730833c..cfd0066e0fc3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowActivity.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_OVERFLOW;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_OVERFLOW;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.app.Activity;
import android.content.Context;
@@ -43,13 +43,12 @@ import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
-
/**
* Activity for showing aged out bubbles.
* Must be public to be accessible to androidx...AppComponentFactory
@@ -112,11 +111,11 @@ public class BubbleOverflowActivity extends Activity {
IBinder binder = intent.getExtras().getBinder(EXTRA_BUBBLE_CONTROLLER);
if (binder instanceof ObjectWrapper) {
mController = ((ObjectWrapper<BubbleController>) binder).get();
+ updateOverflow();
}
} else {
Log.w(TAG, "Bubble overflow activity created without bubble controller!");
}
- updateOverflow();
}
void updateOverflow() {
@@ -139,7 +138,9 @@ public class BubbleOverflowActivity extends Activity {
final int viewHeight = recyclerViewHeight / rows;
mAdapter = new BubbleOverflowAdapter(getApplicationContext(), mOverflowBubbles,
- mController::promoteBubbleFromOverflow, viewWidth, viewHeight);
+ mController::promoteBubbleFromOverflow,
+ mController.getPositioner(),
+ viewWidth, viewHeight);
mRecyclerView.setAdapter(mAdapter);
mOverflowBubbles.clear();
@@ -168,8 +169,8 @@ public class BubbleOverflowActivity extends Activity {
final boolean isNightMode = (mode == Configuration.UI_MODE_NIGHT_YES);
mEmptyStateImage.setImageDrawable(isNightMode
- ? res.getDrawable(R.drawable.ic_empty_bubble_overflow_dark)
- : res.getDrawable(R.drawable.ic_empty_bubble_overflow_light));
+ ? res.getDrawable(R.drawable.bubble_ic_empty_overflow_dark)
+ : res.getDrawable(R.drawable.bubble_ic_empty_overflow_light));
findViewById(android.R.id.content)
.setBackgroundColor(isNightMode
@@ -258,15 +259,20 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V
private Context mContext;
private Consumer<Bubble> mPromoteBubbleFromOverflow;
+ private BubblePositioner mPositioner;
private List<Bubble> mBubbles;
private int mWidth;
private int mHeight;
- public BubbleOverflowAdapter(Context context, List<Bubble> list, Consumer<Bubble> promoteBubble,
+ BubbleOverflowAdapter(Context context,
+ List<Bubble> list,
+ Consumer<Bubble> promoteBubble,
+ BubblePositioner positioner,
int width, int height) {
mContext = context;
mBubbles = list;
mPromoteBubbleFromOverflow = promoteBubble;
+ mPositioner = positioner;
mWidth = width;
mHeight = height;
}
@@ -296,7 +302,7 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V
TextView viewName = overflowView.findViewById(R.id.bubble_view_name);
viewName.setTextColor(textColor);
- return new ViewHolder(overflowView);
+ return new ViewHolder(overflowView, mPositioner);
}
@Override
@@ -349,9 +355,10 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V
public BadgedImageView iconView;
public TextView textView;
- public ViewHolder(LinearLayout v) {
+ ViewHolder(LinearLayout v, BubblePositioner positioner) {
super(v);
iconView = v.findViewById(R.id.bubble_view);
+ iconView.initialize(positioner);
textView = v.findViewById(R.id.bubble_view_name);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
new file mode 100644
index 000000000000..46e8e11610ac
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -0,0 +1,272 @@
+/*
+ * 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.wm.shell.bubbles;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Insets;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.wm.shell.R;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Keeps track of display size, configuration, and specific bubble sizes. One place for all
+ * placement and positioning calculations to refer to.
+ */
+public class BubblePositioner {
+ private static final String TAG = BubbleDebugConfig.TAG_WITH_CLASS_NAME
+ ? "BubblePositioner"
+ : BubbleDebugConfig.TAG_BUBBLES;
+
+ @Retention(SOURCE)
+ @IntDef({TASKBAR_POSITION_RIGHT, TASKBAR_POSITION_LEFT, TASKBAR_POSITION_BOTTOM})
+ @interface TaskbarPosition {}
+ public static final int TASKBAR_POSITION_RIGHT = 0;
+ public static final int TASKBAR_POSITION_LEFT = 1;
+ public static final int TASKBAR_POSITION_BOTTOM = 2;
+
+ /**
+ * The bitmap in the bubble is slightly smaller than the overall size of the bubble.
+ * This is the percentage to scale the image down based on the overall bubble size.
+ */
+ private static final float BUBBLE_BITMAP_SIZE_PERCENT = 0.86f;
+
+ private Context mContext;
+ private WindowManager mWindowManager;
+ private Rect mPositionRect;
+ private int mOrientation;
+ private Insets mInsets;
+
+ private int mBubbleSize;
+ private int mBubbleBitmapSize;
+
+ private PointF mPinLocation;
+ private PointF mRestingStackPosition;
+
+ private boolean mShowingInTaskbar;
+ private @TaskbarPosition int mTaskbarPosition;
+ private int mTaskbarIconSize;
+
+ public BubblePositioner(Context context, WindowManager windowManager) {
+ mContext = context;
+ mWindowManager = windowManager;
+ update(Configuration.ORIENTATION_UNDEFINED);
+ }
+
+ /**
+ * Updates orientation, available space, and inset information. Call this when config changes
+ * occur or when added to a window.
+ */
+ public void update(int orientation) {
+ WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
+ if (windowMetrics == null) {
+ return;
+ }
+ WindowInsets metricInsets = windowMetrics.getWindowInsets();
+
+ Insets insets = metricInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
+ | WindowInsets.Type.statusBars()
+ | WindowInsets.Type.displayCutout());
+
+ if (BubbleDebugConfig.DEBUG_POSITIONER) {
+ Log.w(TAG, "update positioner:"
+ + " landscape= " + (orientation == Configuration.ORIENTATION_LANDSCAPE)
+ + " insets: " + insets
+ + " bounds: " + windowMetrics.getBounds()
+ + " showingInTaskbar: " + mShowingInTaskbar);
+ }
+ updateInternal(orientation, insets, windowMetrics.getBounds());
+ }
+
+ @VisibleForTesting
+ public void updateInternal(int orientation, Insets insets, Rect bounds) {
+ mOrientation = orientation;
+ mInsets = insets;
+
+ mPositionRect = new Rect(bounds);
+ mPositionRect.left += mInsets.left;
+ mPositionRect.top += mInsets.top;
+ mPositionRect.right -= mInsets.right;
+ mPositionRect.bottom -= mInsets.bottom;
+
+ Resources res = mContext.getResources();
+ mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
+ mBubbleBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_bitmap_size);
+ adjustForTaskbar();
+ }
+
+ /**
+ * Updates position information to account for taskbar state.
+ *
+ * @param taskbarPosition which position the taskbar is displayed in.
+ * @param showingInTaskbar whether the taskbar is being shown.
+ */
+ public void updateForTaskbar(int iconSize,
+ @TaskbarPosition int taskbarPosition, boolean showingInTaskbar) {
+ mShowingInTaskbar = showingInTaskbar;
+ mTaskbarIconSize = iconSize;
+ mTaskbarPosition = taskbarPosition;
+ update(mOrientation);
+ }
+
+ /**
+ * Taskbar insets appear as navigationBar insets, however, unlike navigationBar this should
+ * not inset bubbles UI as bubbles floats above the taskbar. This adjust the available space
+ * and insets to account for the taskbar.
+ */
+ // TODO(b/171559950): When the insets are reported correctly we can remove this logic
+ private void adjustForTaskbar() {
+ // When bar is showing on edges... subtract that inset because we appear on top
+ if (mShowingInTaskbar && mTaskbarPosition != TASKBAR_POSITION_BOTTOM) {
+ WindowInsets metricInsets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
+ Insets navBarInsets = metricInsets.getInsetsIgnoringVisibility(
+ WindowInsets.Type.navigationBars());
+ int newInsetLeft = mInsets.left;
+ int newInsetRight = mInsets.right;
+ if (mTaskbarPosition == TASKBAR_POSITION_LEFT) {
+ mPositionRect.left -= navBarInsets.left;
+ newInsetLeft -= navBarInsets.left;
+ } else if (mTaskbarPosition == TASKBAR_POSITION_RIGHT) {
+ mPositionRect.right += navBarInsets.right;
+ newInsetRight -= navBarInsets.right;
+ }
+ mInsets = Insets.of(newInsetLeft, mInsets.top, newInsetRight, mInsets.bottom);
+ }
+ }
+
+ /**
+ * @return a rect of available screen space accounting for orientation, system bars and cutouts.
+ * Does not account for IME.
+ */
+ public Rect getAvailableRect() {
+ return mPositionRect;
+ }
+
+ /**
+ * @return the relevant insets (status bar, nav bar, cutouts). If taskbar is showing, its
+ * inset is not included here.
+ */
+ public Insets getInsets() {
+ return mInsets;
+ }
+
+ /**
+ * @return whether the device is in landscape orientation.
+ */
+ public boolean isLandscape() {
+ return mOrientation == Configuration.ORIENTATION_LANDSCAPE;
+ }
+
+ /**
+ * Indicates how bubbles appear when expanded.
+ *
+ * When false, bubbles display at the top of the screen with the expanded view
+ * below them. When true, bubbles display at the edges of the screen with the expanded view
+ * to the left or right side.
+ */
+ public boolean showBubblesVertically() {
+ return mOrientation == Configuration.ORIENTATION_LANDSCAPE
+ || mShowingInTaskbar;
+ }
+
+ /** Size of the bubble account for badge & dot. */
+ public int getBubbleSize() {
+ int bsize = (mShowingInTaskbar && mTaskbarIconSize > 0)
+ ? mTaskbarIconSize
+ : mBubbleSize;
+ return bsize;
+ }
+
+ /** Size of the bitmap within the bubble */
+ public int getBubbleBitmapSize() {
+ float size = (mShowingInTaskbar && mTaskbarIconSize > 0)
+ ? (mTaskbarIconSize * BUBBLE_BITMAP_SIZE_PERCENT)
+ : mBubbleBitmapSize;
+ return (int) size;
+ }
+
+ /**
+ * Sets 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.
+ */
+ public void setRestingPosition(PointF position) {
+ if (mRestingStackPosition == null) {
+ mRestingStackPosition = new PointF(position);
+ } else {
+ mRestingStackPosition.set(position);
+ }
+ }
+
+ /** The position the bubble stack should rest at when collapsed. */
+ public PointF getRestingPosition() {
+ if (mPinLocation != null) {
+ return mPinLocation;
+ }
+ if (mRestingStackPosition == null) {
+ return getDefaultStartPosition();
+ }
+ return mRestingStackPosition;
+ }
+
+ /**
+ * @return the stack position to use if we don't have a saved location or if user education
+ * is being shown.
+ */
+ public PointF getDefaultStartPosition() {
+ // Start on the left if we're in LTR, right otherwise.
+ final boolean startOnLeft =
+ mContext.getResources().getConfiguration().getLayoutDirection()
+ != View.LAYOUT_DIRECTION_RTL;
+ final float startingVerticalOffset = mContext.getResources().getDimensionPixelOffset(
+ R.dimen.bubble_stack_starting_offset_y);
+ // TODO: placement bug here because mPositionRect doesn't handle the overhanging edge
+ return new BubbleStackView.RelativeStackPosition(
+ startOnLeft,
+ startingVerticalOffset / mPositionRect.height())
+ .getAbsolutePositionInRegion(new RectF(mPositionRect));
+ }
+
+ /**
+ * @return whether the bubble stack is pinned to the taskbar.
+ */
+ public boolean showingInTaskbar() {
+ return mShowingInTaskbar;
+ }
+
+ /**
+ * In some situations bubbles will be pinned to a specific onscreen location. This sets the
+ * location to anchor the stack to.
+ */
+ public void setPinnedLocation(PointF point) {
+ mPinLocation = point;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 69ed5b72c1b2..cbe98458df86 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 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,14 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_STACK_VIEW;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -30,7 +30,6 @@ import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.ColorMatrix;
@@ -71,13 +70,13 @@ import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.bubbles.animation.AnimatableScaleMatrix;
-import com.android.systemui.bubbles.animation.ExpandedAnimationController;
-import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
-import com.android.systemui.bubbles.animation.StackAnimationController;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix;
+import com.android.wm.shell.bubbles.animation.ExpandedAnimationController;
+import com.android.wm.shell.bubbles.animation.PhysicsAnimationLayout;
+import com.android.wm.shell.bubbles.animation.StackAnimationController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
@@ -228,7 +227,7 @@ public class BubbleStackView extends FrameLayout
* once it collapses.
*/
@Nullable
- private Bubble mBubbleToExpandAfterFlyoutCollapse = null;
+ private BubbleViewProvider mBubbleToExpandAfterFlyoutCollapse = null;
/** Layout change listener that moves the stack to the nearest valid position on rotation. */
private OnLayoutChangeListener mOrientationChangedListener;
@@ -572,6 +571,16 @@ public class BubbleStackView extends FrameLayout
mBubbleContainer.setActiveController(mStackAnimationController);
hideFlyoutImmediate();
+ if (!mPositioner.showingInTaskbar()) {
+ // Also, save the magnetized stack so we can dispatch touch events to it.
+ mMagnetizedObject = mStackAnimationController.getMagnetizedStack(
+ mMagneticTarget);
+ mMagnetizedObject.setMagnetListener(mStackMagnetListener);
+ } else {
+ // In taskbar, the stack isn't draggable so we shouldn't dispatch touch events.
+ mMagnetizedObject = null;
+ }
+
// Also, save the magnetized stack so we can dispatch touch events to it.
mMagnetizedObject = mStackAnimationController.getMagnetizedStack(mMagneticTarget);
mMagnetizedObject.setMagnetListener(mStackMagnetListener);
@@ -593,7 +602,9 @@ public class BubbleStackView extends FrameLayout
public void onMove(@NonNull View v, @NonNull MotionEvent ev, float viewInitialX,
float viewInitialY, float dx, float dy) {
// If we're expanding or collapsing, ignore all touch events.
- if (mIsExpansionAnimating) {
+ if (mIsExpansionAnimating
+ // Also ignore events if we shouldn't be draggable.
+ || (mPositioner.showingInTaskbar() && !mIsExpanded)) {
return;
}
@@ -603,7 +614,7 @@ public class BubbleStackView extends FrameLayout
// First, see if the magnetized object consumes the event - if so, we shouldn't move the
// bubble since it's stuck to the target.
if (!passEventToMagnetizedObject(ev)) {
- if (mBubbleData.isExpanded()) {
+ if (mBubbleData.isExpanded() || mPositioner.showingInTaskbar()) {
mExpandedAnimationController.dragBubbleOut(
v, viewInitialX + dx, viewInitialY + dy);
} else {
@@ -701,7 +712,6 @@ public class BubbleStackView extends FrameLayout
}
};
- @Nullable
private BubbleOverflow mBubbleOverflow;
private StackEducationView mStackEduView;
private ManageEducationView mManageEduView;
@@ -745,7 +755,7 @@ public class BubbleStackView extends FrameLayout
ta.recycle();
final Runnable onBubbleAnimatedOut = () -> {
- if (getBubbleCount() == 0) {
+ if (getBubbleCount() == 0 && !mBubbleData.isShowingOverflow()) {
mBubbleController.onAllBubblesAnimatedOut();
}
};
@@ -818,15 +828,16 @@ public class BubbleStackView extends FrameLayout
setFocusable(true);
mBubbleContainer.bringToFront();
- mBubbleOverflow = new BubbleOverflow(getContext(), bubbleController, this);
+ mBubbleOverflow = mBubbleData.getOverflow();
mBubbleContainer.addView(mBubbleOverflow.getIconView(),
mBubbleContainer.getChildCount() /* index */,
- new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
+ new FrameLayout.LayoutParams(mPositioner.getBubbleSize(),
+ mPositioner.getBubbleSize()));
updateOverflow();
mBubbleOverflow.getIconView().setOnClickListener((View v) -> {
- setSelectedBubble(mBubbleOverflow);
- showManageMenu(false);
+ mBubbleData.setShowingOverflow(true);
+ mBubbleData.setSelectedBubble(mBubbleOverflow);
+ mBubbleData.setExpanded(true);
});
setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
@@ -997,11 +1008,12 @@ public class BubbleStackView extends FrameLayout
mManageMenu.findViewById(R.id.bubble_manage_menu_settings_container).setOnClickListener(
view -> {
showManageMenu(false /* show */);
- final Bubble bubble = mBubbleData.getSelectedBubble();
+ final BubbleViewProvider bubble = mBubbleData.getSelectedBubble();
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
- final Intent intent = bubble.getSettingsIntent(mContext);
+ // If it's in the stack it's a proper Bubble.
+ final Intent intent = ((Bubble) bubble).getSettingsIntent(mContext);
mBubbleData.setExpanded(false);
- mContext.startActivityAsUser(intent, bubble.getUser());
+ mContext.startActivityAsUser(intent, ((Bubble) bubble).getUser());
logBubbleEvent(bubble,
FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
}
@@ -1067,7 +1079,7 @@ public class BubbleStackView extends FrameLayout
mStackEduView = new StackEducationView(mContext);
addView(mStackEduView);
}
- return mStackEduView.show(mStackAnimationController.getStartPosition());
+ return mStackEduView.show(mPositioner.getDefaultStartPosition());
}
private void updateUserEdu() {
@@ -1093,7 +1105,7 @@ public class BubbleStackView extends FrameLayout
addView(mFlyout, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
}
- void updateFlyout(float fontScale) {
+ void updateFontScale(float fontScale) {
mFlyout.updateFontSize(fontScale);
}
@@ -1130,7 +1142,9 @@ public class BubbleStackView extends FrameLayout
Resources res = getContext().getResources();
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
- mRelativeStackPositionBeforeRotation = mStackAnimationController.getRelativeStackPosition();
+ mRelativeStackPositionBeforeRotation = new RelativeStackPosition(
+ mPositioner.getRestingPosition(),
+ mStackAnimationController.getAllowableStackPositionRegion());
mManageMenu.setVisibility(View.INVISIBLE);
mShowingManage = false;
@@ -1157,7 +1171,7 @@ public class BubbleStackView extends FrameLayout
Resources res = getContext().getResources();
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
- mBubbleSize = getResources().getDimensionPixelSize(R.dimen.individual_bubble_size);
+ mBubbleSize = mPositioner.getBubbleSize();
for (Bubble b : mBubbleData.getBubbles()) {
if (b.getIconView() == null) {
Log.d(TAG, "Display size changed. Icon null: " + b);
@@ -1165,6 +1179,7 @@ public class BubbleStackView extends FrameLayout
}
b.getIconView().setLayoutParams(new LayoutParams(mBubbleSize, mBubbleSize));
}
+ mBubbleOverflow.getIconView().setLayoutParams(new LayoutParams(mBubbleSize, mBubbleSize));
mExpandedAnimationController.updateResources();
mStackAnimationController.updateResources();
mDismissView.updateResources();
@@ -1199,8 +1214,8 @@ public class BubbleStackView extends FrameLayout
super.onDetachedFromWindow();
getViewTreeObserver().removeOnPreDrawListener(mViewUpdater);
getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
- if (mBubbleOverflow != null && mBubbleOverflow.getExpandedView() != null) {
- mBubbleOverflow.getExpandedView().cleanUpExpandedState();
+ if (mBubbleOverflow != null) {
+ mBubbleOverflow.cleanUpExpandedState();
}
}
@@ -1390,8 +1405,7 @@ public class BubbleStackView extends FrameLayout
if (getBubbleCount() == 0 && shouldShowStackEdu()) {
// Override the default stack position if we're showing user education.
- mStackAnimationController.setStackPosition(
- mStackAnimationController.getStartPosition());
+ mStackAnimationController.setStackPosition(mPositioner.getDefaultStartPosition());
}
if (getBubbleCount() == 0) {
@@ -1410,7 +1424,8 @@ public class BubbleStackView extends FrameLayout
bubble.getIconView().setOnTouchListener(mBubbleTouchListener);
mBubbleContainer.addView(bubble.getIconView(), 0,
- new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+ new FrameLayout.LayoutParams(mPositioner.getBubbleSize(),
+ mPositioner.getBubbleSize()));
animateInFlyoutForBubble(bubble);
requestUpdate();
logBubbleEvent(bubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
@@ -1441,10 +1456,9 @@ public class BubbleStackView extends FrameLayout
}
private void updateOverflowVisibility() {
- if (mBubbleOverflow == null) {
- return;
- }
- mBubbleOverflow.setVisible(mIsExpanded ? VISIBLE : GONE);
+ mBubbleOverflow.setVisible((mIsExpanded || mBubbleData.isShowingOverflow())
+ ? VISIBLE
+ : GONE);
}
// via BubbleData.Listener
@@ -1614,6 +1628,11 @@ public class BubbleStackView extends FrameLayout
mBubbleController.hideCurrentInputMethod();
}
+ /** Set the stack position to whatever the positioner says. */
+ void updateStackPosition() {
+ mStackAnimationController.setStackPosition(mPositioner.getRestingPosition());
+ }
+
private void beforeExpandedViewAnimation() {
mIsExpansionAnimating = true;
hideFlyoutImmediate();
@@ -1629,8 +1648,7 @@ public class BubbleStackView extends FrameLayout
private void animateExpansion() {
cancelDelayedExpandCollapseSwitchAnimations();
- final boolean isLandscape =
- mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE;
+ final boolean showVertically = mPositioner.showBubblesVertically();
mIsExpanded = true;
if (mStackEduView != null) {
mStackEduView.hide(true /* fromExpansion */);
@@ -1650,14 +1668,19 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer.setTranslationY(getExpandedViewY());
mExpandedViewContainer.setAlpha(1f);
- // X-value of the bubble we're expanding, once it's settled in its row.
+ int index;
+ if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) {
+ index = mBubbleData.getBubbles().size();
+ } else {
+ index = getBubbleIndex(mExpandedBubble);
+ }
+ // Position of the bubble we're expanding, once it's settled in its row.
final float bubbleWillBeAt =
- mExpandedAnimationController.getBubbleXOrYForOrientation(
- mBubbleData.getBubbles().indexOf(mExpandedBubble));
+ mExpandedAnimationController.getBubbleXOrYForOrientation(index);
// How far horizontally the bubble will be animating. We'll wait a bit longer for bubbles
// that are animating farther, so that the expanded view doesn't move as much.
- final float relevantStackPosition = isLandscape
+ final float relevantStackPosition = showVertically
? mStackAnimationController.getStackPosition().y
: mStackAnimationController.getStackPosition().x;
final float distanceAnimated = Math.abs(bubbleWillBeAt - relevantStackPosition);
@@ -1674,7 +1697,7 @@ public class BubbleStackView extends FrameLayout
}
// Set the pivot point for the scale, so the expanded view animates out from the bubble.
- if (isLandscape) {
+ if (showVertically) {
float pivotX;
float pivotY = bubbleWillBeAt + mBubbleSize / 2f;
if (mStackOnLeftOrWillBe) {
@@ -1709,7 +1732,7 @@ public class BubbleStackView extends FrameLayout
if (mExpandedBubble == null || mExpandedBubble.getIconView() == null) {
return;
}
- float translation = isLandscape
+ float translation = showVertically
? mExpandedBubble.getIconView().getTranslationY()
: mExpandedBubble.getIconView().getTranslationX();
mExpandedViewContainerMatrix.postTranslate(
@@ -1761,13 +1784,17 @@ public class BubbleStackView extends FrameLayout
// We want to visually collapse into this bubble during the animation.
final View expandingFromBubble = mExpandedBubble.getIconView();
+ int index;
+ if (mExpandedBubble != null && BubbleOverflow.KEY.equals(mExpandedBubble.getKey())) {
+ index = mBubbleData.getBubbles().size();
+ } else {
+ index = mBubbleData.getBubbles().indexOf(mExpandedBubble);
+ }
// Value the bubble is animating from (back into the stack).
final float expandingFromBubbleAt =
- mExpandedAnimationController.getBubbleXOrYForOrientation(
- mBubbleData.getBubbles().indexOf(mExpandedBubble));
- final boolean isLandscape =
- mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE;
- if (isLandscape) {
+ mExpandedAnimationController.getBubbleXOrYForOrientation(index);
+ final boolean showVertically = mPositioner.showBubblesVertically();
+ if (mPositioner.showBubblesVertically()) {
float pivotX;
float pivotY = expandingFromBubbleAt + mBubbleSize / 2f;
if (mStackOnLeftOrWillBe) {
@@ -1792,7 +1819,7 @@ public class BubbleStackView extends FrameLayout
.addUpdateListener((target, values) -> {
if (expandingFromBubble != null) {
// Follow the bubble as it translates!
- if (isLandscape) {
+ if (showVertically) {
mExpandedViewContainerMatrix.postTranslate(
0f, expandingFromBubble.getTranslationY()
- expandingFromBubbleAt);
@@ -1849,7 +1876,7 @@ public class BubbleStackView extends FrameLayout
.spring(DynamicAnimation.SCALE_Y, 0f, mScaleOutSpringConfig)
.withEndActions(this::releaseAnimatingOutBubbleBuffer);
- if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) {
+ if (mPositioner.showBubblesVertically()) {
float translationX = mStackAnimationController.isStackOnLeftSide()
? mAnimatingOutSurfaceContainer.getTranslationX() + mBubbleSize * 2
: mAnimatingOutSurfaceContainer.getTranslationX();
@@ -1874,7 +1901,7 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer.setAlpha(1f);
mExpandedViewContainer.setVisibility(View.VISIBLE);
- if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) {
+ if (mPositioner.showBubblesVertically()) {
float pivotX;
float pivotY = expandingFromBubbleDestination + mBubbleSize / 2f;
if (mStackOnLeftOrWillBe) {
@@ -2113,7 +2140,7 @@ public class BubbleStackView extends FrameLayout
}
}
- private void dismissBubbleIfExists(@Nullable Bubble bubble) {
+ private void dismissBubbleIfExists(@Nullable BubbleViewProvider bubble) {
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
mBubbleData.dismissBubbleWithKey(bubble.getKey(), Bubbles.DISMISS_USER_GESTURE);
}
@@ -2180,7 +2207,7 @@ public class BubbleStackView extends FrameLayout
*/
float getExpandedViewY() {
final int top = mPositioner.getAvailableRect().top;
- if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) {
+ if (mPositioner.showBubblesVertically()) {
return top + mExpandedViewPadding;
} else {
return top + mBubbleSize + mBubblePaddingTop;
@@ -2278,7 +2305,8 @@ public class BubbleStackView extends FrameLayout
expandFlyoutAfterDelay /* onLayoutComplete */,
mAfterFlyoutHidden,
bubble.getIconView().getDotCenter(),
- !bubble.showDot());
+ !bubble.showDot(),
+ mPositioner);
}
mFlyout.bringToFront();
});
@@ -2321,7 +2349,7 @@ public class BubbleStackView extends FrameLayout
}
if (!mIsExpanded) {
- if (getBubbleCount() > 0) {
+ if (getBubbleCount() > 0 || mBubbleData.isShowingOverflow()) {
mBubbleContainer.getChildAt(0).getBoundsOnScreen(outRect);
// Increase the touch target size of the bubble
outRect.top -= mBubbleTouchPadding;
@@ -2550,7 +2578,7 @@ public class BubbleStackView extends FrameLayout
Insets insets = mPositioner.getInsets();
int leftPadding = insets.left + mExpandedViewPadding;
int rightPadding = insets.right + mExpandedViewPadding;
- if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) {
+ if (mPositioner.showBubblesVertically()) {
if (!mStackAnimationController.isStackOnLeftSide()) {
rightPadding += mPointerHeight + mBubbleSize;
} else {
@@ -2581,7 +2609,9 @@ public class BubbleStackView extends FrameLayout
bv.setZ((mMaxBubbles * mBubbleElevation) - i);
if (mIsExpanded) {
- bv.showDotAndBadge(false /* onLeft */);
+ // If we're not displaying vertically, we always show the badge on the left.
+ boolean onLeft = mPositioner.showBubblesVertically() && !mStackOnLeftOrWillBe;
+ bv.showDotAndBadge(onLeft);
} else if (i == 0) {
bv.showDotAndBadge(!mStackOnLeftOrWillBe);
} else {
@@ -2599,7 +2629,7 @@ public class BubbleStackView extends FrameLayout
return;
}
float bubblePosition = mExpandedAnimationController.getBubbleXOrYForOrientation(index);
- if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) {
+ if (mPositioner.showBubblesVertically()) {
float x = mStackOnLeftOrWillBe
? mPositioner.getAvailableRect().left
: mPositioner.getAvailableRect().right
@@ -2661,18 +2691,11 @@ public class BubbleStackView extends FrameLayout
.floatValue();
}
- public void setStackStartPosition(RelativeStackPosition position) {
- mStackAnimationController.setStackStartPosition(position);
- }
-
+ /** @return the position of the bubble stack. */
public PointF getStackPosition() {
return mStackAnimationController.getStackPosition();
}
- public RelativeStackPosition getRelativeStackPosition() {
- return mStackAnimationController.getRelativeStackPosition();
- }
-
/**
* Logs the bubble UI event.
*
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index a3e6a1ecc387..e21ba6392e95 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.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,12 +14,12 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
-import static com.android.systemui.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
-import static com.android.systemui.bubbles.BadgedImageView.WHITE_SCRIM_ALPHA;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.wm.shell.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
+import static com.android.wm.shell.bubbles.BadgedImageView.WHITE_SCRIM_ALPHA;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.NonNull;
import android.content.Context;
@@ -42,7 +42,7 @@ import androidx.annotation.Nullable;
import com.android.internal.graphics.ColorUtils;
import com.android.launcher3.icons.BitmapInfo;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
import java.lang.ref.WeakReference;
import java.util.Objects;
@@ -134,6 +134,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask
LayoutInflater inflater = LayoutInflater.from(c);
info.imageView = (BadgedImageView) inflater.inflate(
R.layout.bubble_view, stackView, false /* attachToRoot */);
+ info.imageView.initialize(controller.getPositioner());
info.expandedView = (BubbleExpandedView) inflater.inflate(
R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java
index 589017242311..ec900be13658 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import android.graphics.Bitmap;
import android.graphics.Path;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 415edb1b647c..79c42d83d7ea 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
index b3c552d24dcd..04b5ad6dddf9 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/DismissView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/DismissView.kt
@@ -1,4 +1,20 @@
-package com.android.systemui.bubbles
+/*
+ * 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.wm.shell.bubbles
import android.content.Context
import android.graphics.drawable.TransitionDrawable
@@ -9,9 +25,9 @@ import android.widget.FrameLayout
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY
import androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW
-import com.android.systemui.R
-import com.android.wm.shell.common.DismissCircleView
+import com.android.wm.shell.R
import com.android.wm.shell.animation.PhysicsAnimator
+import com.android.wm.shell.common.DismissCircleView
/*
* View that handles interactions between DismissCircleView and BubbleStackView.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
index 3db07c227d02..4cc67025fff4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/ManageEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles
+package com.android.wm.shell.bubbles
import android.content.Context
import android.graphics.Color
@@ -24,8 +24,8 @@ import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import com.android.internal.util.ContrastColorUtil
-import com.android.systemui.Interpolators
-import com.android.systemui.R
+import com.android.wm.shell.R
+import com.android.wm.shell.animation.Interpolators
/**
* User education view to highlight the manage button that allows a user to configure the settings
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/ObjectWrapper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ObjectWrapper.java
index f054122eaa47..528907f5e483 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/ObjectWrapper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ObjectWrapper.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import android.os.Binder;
import android.os.IBinder;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/RelativeTouchListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
index b1291a507b57..b34732901648 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/RelativeTouchListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RelativeTouchListener.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles
+package com.android.wm.shell.bubbles
import android.graphics.PointF
import android.os.Handler
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
index 216df2e1f402..04c4dfb9b08d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles
+package com.android.wm.shell.bubbles
import android.content.Context
import android.graphics.Color
@@ -23,8 +23,8 @@ import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
import com.android.internal.util.ContrastColorUtil
-import com.android.systemui.Interpolators
-import com.android.systemui.R
+import com.android.wm.shell.R
+import com.android.wm.shell.animation.Interpolators
/**
* User education view to highlight the collapsed stack of bubbles.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/AnimatableScaleMatrix.java
index 07acb710c6d7..2612b81aae00 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/AnimatableScaleMatrix.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import android.graphics.Matrix;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 5a70401abb4a..18aaa9677be6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -28,10 +28,10 @@ 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.BubblePositioner;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
import com.google.android.collect.Sets;
@@ -84,7 +84,11 @@ public class ExpandedAnimationController
private float mBubbleSizePx;
/** Max number of bubbles shown in row above expanded view. */
private int mBubblesMaxRendered;
-
+ /** Max amount of space to have between bubbles when expanded. */
+ private int mBubblesMaxSpace;
+ /** Amount of space between the bubbles when expanded. */
+ private float mSpaceBetweenBubbles;
+ /** Whether the expand / collapse animation is running. */
private boolean mAnimatingExpand = false;
/**
@@ -205,8 +209,17 @@ public class ExpandedAnimationController
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
- mBubbleSizePx = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
+ mBubbleSizePx = mPositioner.getBubbleSize();
mBubblesMaxRendered = res.getInteger(R.integer.bubbles_max_rendered);
+ mBubblesMaxSpace = res.getDimensionPixelSize(R.dimen.bubble_max_spacing);
+ final float availableSpace = mPositioner.isLandscape()
+ ? mPositioner.getAvailableRect().height()
+ : mPositioner.getAvailableRect().width();
+ final float spaceForMaxBubbles = (mExpandedViewPadding * 2)
+ + (mBubblesMaxRendered + 1) * mBubbleSizePx;
+ float spaceBetweenBubbles =
+ (availableSpace - spaceForMaxBubbles) / mBubblesMaxRendered;
+ mSpaceBetweenBubbles = Math.min(spaceBetweenBubbles, mBubblesMaxSpace);
}
/**
@@ -250,13 +263,15 @@ public class ExpandedAnimationController
final Path path = new Path();
path.moveTo(bubble.getTranslationX(), bubble.getTranslationY());
- final float expandedY = getExpandedY();
+ final float expandedY = mPositioner.showBubblesVertically()
+ ? getBubbleXOrYForOrientation(index)
+ : getExpandedY();
if (expanding) {
// If we're expanding, first draw a line from the bubble's current position to the
// top of the screen.
path.lineTo(bubble.getTranslationX(), expandedY);
// Then, draw a line across the screen to the bubble's resting position.
- if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) {
+ if (mPositioner.showBubblesVertically()) {
Rect availableRect = mPositioner.getAvailableRect();
boolean onLeft = mCollapsePoint != null
&& mCollapsePoint.x < (availableRect.width() / 2f);
@@ -422,6 +437,9 @@ public class ExpandedAnimationController
* bubbles to accommodate it if it was previously dragged out past the threshold.
*/
public void snapBubbleBack(View bubbleView, float velX, float velY) {
+ if (mLayout == null) {
+ return;
+ }
final int index = mLayout.indexOfChild(bubbleView);
animationForChildAtIndex(index)
@@ -580,7 +598,7 @@ public class ExpandedAnimationController
return;
}
- if (mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE) {
+ if (mPositioner.showBubblesVertically()) {
Rect availableRect = mPositioner.getAvailableRect();
boolean onLeft = mCollapsePoint != null
&& mCollapsePoint.x < (availableRect.width() / 2f);
@@ -613,23 +631,15 @@ public class ExpandedAnimationController
if (mLayout == null) {
return 0;
}
+ final float positionInBar = index * (mBubbleSizePx + mSpaceBetweenBubbles);
Rect availableRect = mPositioner.getAvailableRect();
- final boolean isLandscape =
- mPositioner.getOrientation() == Configuration.ORIENTATION_LANDSCAPE;
- final float availableSpace = isLandscape
- ? availableRect.height()
- : availableRect.width();
- final float spaceForMaxBubbles = (mExpandedViewPadding * 2)
- + (mBubblesMaxRendered + 1) * mBubbleSizePx;
- final float spaceBetweenBubbles =
- (availableSpace - spaceForMaxBubbles) / mBubblesMaxRendered;
+ final boolean isLandscape = mPositioner.showBubblesVertically();
final float expandedStackSize = (mLayout.getChildCount() * mBubbleSizePx)
- + ((mLayout.getChildCount() - 1) * spaceBetweenBubbles);
+ + ((mLayout.getChildCount() - 1) * mSpaceBetweenBubbles);
final float centerPosition = isLandscape
? availableRect.centerY()
: availableRect.centerX();
final float rowStart = centerPosition - (expandedStackSize / 2f);
- final float positionInBar = index * (mBubbleSizePx + spaceBetweenBubbles);
return rowStart + positionInBar;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/OneTimeEndListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OneTimeEndListener.java
index 4e0abc8009b4..37355c41810c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/OneTimeEndListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/OneTimeEndListener.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import androidx.dynamicanimation.animation.DynamicAnimation;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
index 0a596d5c69b6..0618d5d5f213 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -35,7 +35,7 @@ import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 43893f215d8a..24a8809d3f2b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import android.content.ContentResolver;
import android.content.res.Resources;
@@ -34,11 +34,11 @@ import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.systemui.R;
-import com.android.systemui.bubbles.BadgedImageView;
-import com.android.systemui.bubbles.BubblePositioner;
-import com.android.systemui.bubbles.BubbleStackView;
+import com.android.wm.shell.R;
import com.android.wm.shell.animation.PhysicsAnimator;
+import com.android.wm.shell.bubbles.BadgedImageView;
+import com.android.wm.shell.bubbles.BubblePositioner;
+import com.android.wm.shell.bubbles.BubbleStackView;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
@@ -133,12 +133,6 @@ public class StackAnimationController extends
/** Whether or not the stack's start position has been set. */
private boolean mStackMovedToStartPosition = false;
- /**
- * 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;
@@ -434,6 +428,9 @@ public class StackAnimationController extends
* Where the stack would be if it were snapped to the nearest horizontal edge (left or right).
*/
public PointF getStackPositionAlongNearestHorizontalEdge() {
+ if (mPositioner.showingInTaskbar()) {
+ return mPositioner.getRestingPosition();
+ }
final PointF stackPos = getStackPosition();
final boolean onLeft = mLayout.isFirstChildXLeftOfCenter(stackPos.x);
final RectF bounds = getAllowableStackPositionRegion();
@@ -447,7 +444,7 @@ public class StackAnimationController extends
pw.println("StackAnimationController state:");
pw.print(" isActive: "); pw.println(isActiveController());
pw.print(" restingStackPos: ");
- pw.println(mRestingStackPosition != null ? mRestingStackPosition.toString() : "null");
+ pw.println(mPositioner.getRestingPosition().toString());
pw.print(" currentStackPos: "); pw.println(mStackPosition.toString());
pw.print(" isMovingFromFlinging: "); pw.println(mIsMovingFromFlinging);
pw.print(" withinDismiss: "); pw.println(isStackStuckToTarget());
@@ -501,7 +498,7 @@ public class StackAnimationController extends
.addEndListener((animation, canceled, endValue, endVelocity) -> {
if (!canceled) {
- mRestingStackPosition.set(mStackPosition);
+ mPositioner.setRestingPosition(mStackPosition);
springFirstBubbleWithStackFollowing(property, spring, endVelocity,
finalPosition != null
@@ -679,7 +676,7 @@ public class StackAnimationController extends
// resting position - the touch location is not a valid resting
// position. We'll set this when the stack springs to the left or
// right side of the screen after the touch gesture ends.
- mRestingStackPosition.set(mStackPosition);
+ mPositioner.setRestingPosition(mStackPosition);
}
if (after != null) {
@@ -772,10 +769,9 @@ public class StackAnimationController extends
if (getBubbleCount() > 0) {
animationForChildAtIndex(0).translationX(mStackPosition.x).start();
} else {
+ // TODO: still needed with positioner?
// When all children are removed ensure stack position is sane
- setStackPosition(mRestingStackPosition == null
- ? getStartPosition()
- : mRestingStackPosition);
+ mPositioner.setRestingPosition(mPositioner.getRestingPosition());
// Remove the stack from the coordinator since we don't have any bubbles and aren't
// visible.
@@ -848,8 +844,8 @@ public class StackAnimationController extends
mSwapAnimationOffset = res.getDimensionPixelSize(R.dimen.bubble_swap_animation_offset);
mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
mElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
- mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
- mBubbleBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_bitmap_size);
+ mBubbleSize = mPositioner.getBubbleSize();
+ mBubbleBitmapSize = mPositioner.getBubbleBitmapSize();
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mBubbleOffscreen = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen);
}
@@ -873,9 +869,8 @@ public class StackAnimationController extends
// Post to ensure that the layout's width and height have been calculated.
mLayout.setVisibility(View.INVISIBLE);
mLayout.post(() -> {
- setStackPosition(mRestingStackPosition == null
- ? getStartPosition()
- : mRestingStackPosition);
+ setStackPosition(mPositioner.getRestingPosition());
+
mStackMovedToStartPosition = true;
mLayout.setVisibility(View.VISIBLE);
@@ -919,11 +914,7 @@ public class StackAnimationController extends
Log.d(TAG, String.format("Setting position to (%f, %f).", pos.x, pos.y));
mStackPosition.set(pos.x, pos.y);
- if (mRestingStackPosition == null) {
- mRestingStackPosition = new PointF();
- }
-
- mRestingStackPosition.set(mStackPosition);
+ mPositioner.setRestingPosition(mStackPosition);
// If we're not the active controller, we don't want to physically move the bubble views.
if (isActiveController()) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
index 24768cd84a76..aeba302bf487 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleEntity.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.annotation.DimenRes
import android.annotation.UserIdInt
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepository.kt
index ce0786d86460..66a75af7d64c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubblePersistentRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepository.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.content.Context
import android.util.AtomicFile
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
index e0a7c7879f43..7f0b165bdc25 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepository.kt
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.content.pm.LauncherApps
import android.os.UserHandle
import com.android.internal.annotations.VisibleForTesting
-import com.android.systemui.bubbles.ShortcutKey
+import com.android.wm.shell.bubbles.ShortcutKey
private const val CAPACITY = 16
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
index bf163a230aff..fe72bd301e04 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelper.kt
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
-import com.android.internal.util.FastXmlSerializer
-import org.xmlpull.v1.XmlSerializer
-import java.io.IOException
import android.util.Xml
+import com.android.internal.util.FastXmlSerializer
import com.android.internal.util.XmlUtils
import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlSerializer
+import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.nio.charset.StandardCharsets
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/AlphaOptimizedButton.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/AlphaOptimizedButton.java
new file mode 100644
index 000000000000..6f0a61b3187f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/AlphaOptimizedButton.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.wm.shell.common;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+/**
+ * A Button which doesn't have overlapping drawing commands
+ *
+ * This is the copy from SystemUI/statusbar.
+ */
+public class AlphaOptimizedButton extends Button {
+ public AlphaOptimizedButton(Context context) {
+ super(context);
+ }
+
+ public AlphaOptimizedButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AlphaOptimizedButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public AlphaOptimizedButton(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java
new file mode 100644
index 000000000000..87ddb181dcce
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/PipInputConsumer.java
@@ -0,0 +1,182 @@
+/*
+ * 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.wm.shell.common;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.BatchedInputEventReceiver;
+import android.view.Choreographer;
+import android.view.IWindowManager;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.WindowManagerGlobal;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the input consumer that allows the Shell to directly receive input.
+ */
+public class PipInputConsumer {
+
+ private static final String TAG = PipInputConsumer.class.getSimpleName();
+
+ /**
+ * Listener interface for callers to subscribe to input events.
+ */
+ public interface InputListener {
+ /** Handles any input event. */
+ boolean onInputEvent(InputEvent ev);
+ }
+
+ /**
+ * Listener interface for callers to learn when this class is registered or unregistered with
+ * window manager
+ */
+ public interface RegistrationListener {
+ void onRegistrationChanged(boolean isRegistered);
+ }
+
+ /**
+ * Input handler used for the input consumer. Input events are batched and consumed with the
+ * SurfaceFlinger vsync.
+ */
+ private final class InputEventReceiver extends BatchedInputEventReceiver {
+
+ InputEventReceiver(InputChannel inputChannel, Looper looper,
+ Choreographer choreographer) {
+ super(inputChannel, looper, choreographer);
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = true;
+ try {
+ if (mListener != null) {
+ handled = mListener.onInputEvent(event);
+ }
+ } finally {
+ finishInputEvent(event, handled);
+ }
+ }
+ }
+
+ private final IWindowManager mWindowManager;
+ private final IBinder mToken;
+ private final String mName;
+
+ private InputEventReceiver mInputEventReceiver;
+ private InputListener mListener;
+ private RegistrationListener mRegistrationListener;
+
+ /**
+ * @param name the name corresponding to the input consumer that is defined in the system.
+ */
+ public PipInputConsumer(IWindowManager windowManager, String name) {
+ mWindowManager = windowManager;
+ mToken = new Binder();
+ mName = name;
+ }
+
+ /**
+ * Sets the input listener.
+ */
+ public void setInputListener(InputListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Sets the registration listener.
+ */
+ public void setRegistrationListener(RegistrationListener listener) {
+ mRegistrationListener = listener;
+ if (mRegistrationListener != null) {
+ mRegistrationListener.onRegistrationChanged(mInputEventReceiver != null);
+ }
+ }
+
+ /**
+ * Check if the InputConsumer is currently registered with WindowManager
+ *
+ * @return {@code true} if registered, {@code false} if not.
+ */
+ public boolean isRegistered() {
+ return mInputEventReceiver != null;
+ }
+
+ /**
+ * Registers the input consumer.
+ */
+ public void registerInputConsumer() {
+ registerInputConsumer(false);
+ }
+
+ /**
+ * Registers the input consumer.
+ * @param withSfVsync the flag set using sf vsync signal or no
+ */
+ public void registerInputConsumer(boolean withSfVsync) {
+ if (mInputEventReceiver != null) {
+ return;
+ }
+ final InputChannel inputChannel = new InputChannel();
+ try {
+ // TODO(b/113087003): Support Picture-in-picture in multi-display.
+ mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+ mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to create input consumer", e);
+ }
+ mInputEventReceiver = new InputEventReceiver(inputChannel, Looper.myLooper(),
+ withSfVsync ? Choreographer.getSfInstance() : Choreographer.getInstance());
+ if (mRegistrationListener != null) {
+ mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
+ }
+ }
+
+ /**
+ * Unregisters the input consumer.
+ */
+ public void unregisterInputConsumer() {
+ if (mInputEventReceiver == null) {
+ return;
+ }
+ try {
+ // TODO(b/113087003): Support Picture-in-picture in multi-display.
+ mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to destroy input consumer", e);
+ }
+ mInputEventReceiver.dispose();
+ mInputEventReceiver = null;
+ if (mRegistrationListener != null) {
+ mRegistrationListener.onRegistrationChanged(false /* isRegistered */);
+ }
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + "registered=" + (mInputEventReceiver != null));
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
new file mode 100644
index 000000000000..0f6dd93f9c16
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerCallback.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ITaskStackListener;
+import android.app.TaskInfo;
+import android.content.ComponentName;
+import android.os.IBinder;
+
+import androidx.annotation.BinderThread;
+import androidx.annotation.MainThread;
+
+/**
+ * An interface to track task stack changes. Classes should implement this instead of
+ * {@link ITaskStackListener} to reduce IPC calls from system services.
+ */
+public interface TaskStackListenerCallback {
+
+ @MainThread
+ default void onRecentTaskListUpdated() { }
+
+ @MainThread
+ default void onRecentTaskListFrozenChanged(boolean frozen) { }
+
+ @BinderThread
+ default void onTaskStackChangedBackground() { }
+
+ @MainThread
+ default void onTaskStackChanged() { }
+
+ @MainThread
+ default void onTaskProfileLocked(int taskId, int userId) { }
+
+ @MainThread
+ default void onTaskDisplayChanged(int taskId, int newDisplayId) { }
+
+ @MainThread
+ default void onTaskCreated(int taskId, ComponentName componentName) { }
+
+ @MainThread
+ default void onTaskRemoved(int taskId) { }
+
+ @MainThread
+ default void onTaskMovedToFront(int taskId) { }
+
+ @MainThread
+ default void onTaskMovedToFront(RunningTaskInfo taskInfo) {
+ onTaskMovedToFront(taskInfo.taskId);
+ }
+
+ @MainThread
+ default void onTaskDescriptionChanged(RunningTaskInfo taskInfo) { }
+
+ @MainThread
+ default void onTaskSnapshotChanged(int taskId, ActivityManager.TaskSnapshot snapshot) { }
+
+ @MainThread
+ default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { }
+
+ @MainThread
+ default void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask, boolean wasVisible) { }
+
+ @MainThread
+ default void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
+
+ @MainThread
+ default void onActivityUnpinned() { }
+
+ @MainThread
+ default void onActivityForcedResizable(String packageName, int taskId, int reason) { }
+
+ @MainThread
+ default void onActivityDismissingDockedStack() { }
+
+ @MainThread
+ default void onActivityLaunchOnSecondaryDisplayFailed() { }
+
+ @MainThread
+ default void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo) {
+ onActivityLaunchOnSecondaryDisplayFailed();
+ }
+
+ @MainThread
+ default void onActivityLaunchOnSecondaryDisplayRerouted() { }
+
+ @MainThread
+ default void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo) {
+ onActivityLaunchOnSecondaryDisplayRerouted();
+ }
+
+ @MainThread
+ default void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }
+
+ @MainThread
+ default void onActivityRotation(int displayId) { }
+
+ @MainThread
+ default void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) { }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
new file mode 100644
index 000000000000..7efacc7b2c1f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TaskStackListenerImpl.java
@@ -0,0 +1,437 @@
+/*
+ * 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.wm.shell.common;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Trace;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.SomeArgs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of a {@link android.app.TaskStackListener}.
+ */
+public class TaskStackListenerImpl extends TaskStackListener implements Handler.Callback {
+ private static final String TAG = TaskStackListenerImpl.class.getSimpleName();
+
+ private static final int ON_TASK_STACK_CHANGED = 1;
+ private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
+ private static final int ON_ACTIVITY_PINNED = 3;
+ private static final int ON_ACTIVITY_RESTART_ATTEMPT = 4;
+ private static final int ON_ACTIVITY_FORCED_RESIZABLE = 5;
+ private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 6;
+ private static final int ON_TASK_PROFILE_LOCKED = 7;
+ private static final int ON_ACTIVITY_UNPINNED = 8;
+ private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED = 9;
+ private static final int ON_TASK_CREATED = 10;
+ private static final int ON_TASK_REMOVED = 11;
+ private static final int ON_TASK_MOVED_TO_FRONT = 12;
+ private static final int ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE = 13;
+ private static final int ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED = 14;
+ private static final int ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED = 15;
+ private static final int ON_BACK_PRESSED_ON_TASK_ROOT = 16;
+ private static final int ON_TASK_DISPLAY_CHANGED = 17;
+ private static final int ON_TASK_LIST_UPDATED = 18;
+ private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 19;
+ private static final int ON_TASK_DESCRIPTION_CHANGED = 20;
+ private static final int ON_ACTIVITY_ROTATION = 21;
+
+ /**
+ * List of {@link TaskStackListenerCallback} registered from {@link #addListener}.
+ */
+ private final List<TaskStackListenerCallback> mTaskStackListeners = new ArrayList<>();
+ private final List<TaskStackListenerCallback> mTmpListeners = new ArrayList<>();
+
+ private final IActivityTaskManager mActivityTaskManager;
+ // NOTE: In this case we do want to use a handler since we rely on the message system to
+ // efficiently dedupe sequential calls
+ private Handler mHandler;
+
+ public TaskStackListenerImpl(Handler handler) {
+ mActivityTaskManager = ActivityTaskManager.getService();
+ mHandler = new Handler(handler.getLooper(), this);
+ }
+
+ @VisibleForTesting
+ TaskStackListenerImpl(IActivityTaskManager activityTaskManager) {
+ mActivityTaskManager = activityTaskManager;
+ }
+
+ @VisibleForTesting
+ void setHandler(Handler handler) {
+ mHandler = handler;
+ }
+
+ public void addListener(TaskStackListenerCallback listener) {
+ final boolean wasEmpty;
+ synchronized (mTaskStackListeners) {
+ wasEmpty = mTaskStackListeners.isEmpty();
+ mTaskStackListeners.add(listener);
+ }
+ if (wasEmpty) {
+ // Register mTaskStackListener to IActivityManager only once if needed.
+ try {
+ mActivityTaskManager.registerTaskStackListener(this);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to call registerTaskStackListener", e);
+ }
+ }
+ }
+
+ public void removeListener(TaskStackListenerCallback listener) {
+ final boolean wasEmpty;
+ final boolean isEmpty;
+ synchronized (mTaskStackListeners) {
+ wasEmpty = mTaskStackListeners.isEmpty();
+ mTaskStackListeners.remove(listener);
+ isEmpty = mTaskStackListeners.isEmpty();
+ }
+ if (!wasEmpty && isEmpty) {
+ // Unregister mTaskStackListener once we have no more listeners
+ try {
+ mActivityTaskManager.unregisterTaskStackListener(this);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to call unregisterTaskStackListener", e);
+ }
+ }
+ }
+
+ @Override
+ public void onRecentTaskListUpdated() {
+ mHandler.obtainMessage(ON_TASK_LIST_UPDATED).sendToTarget();
+ }
+
+ @Override
+ public void onRecentTaskListFrozenChanged(boolean frozen) {
+ mHandler.obtainMessage(ON_TASK_LIST_FROZEN_UNFROZEN, frozen ? 1 : 0, 0 /* unused */)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onTaskStackChanged() {
+ // Call the task changed callback for the non-ui thread listeners first. Copy to a set
+ // of temp listeners so that we don't lock on mTaskStackListeners while calling all the
+ // callbacks. This call is always on the same binder thread, so we can just synchronize
+ // on the copying of the listener list.
+ synchronized (mTaskStackListeners) {
+ mTmpListeners.addAll(mTaskStackListeners);
+ }
+ for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
+ mTmpListeners.get(i).onTaskStackChangedBackground();
+ }
+ mTmpListeners.clear();
+
+ mHandler.removeMessages(ON_TASK_STACK_CHANGED);
+ mHandler.sendEmptyMessage(ON_TASK_STACK_CHANGED);
+ }
+
+ @Override
+ public void onTaskProfileLocked(int taskId, int userId) {
+ mHandler.obtainMessage(ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
+ }
+
+ @Override
+ public void onTaskDisplayChanged(int taskId, int newDisplayId) {
+ mHandler.obtainMessage(ON_TASK_DISPLAY_CHANGED, taskId, newDisplayId).sendToTarget();
+ }
+
+ @Override
+ public void onTaskCreated(int taskId, ComponentName componentName) {
+ mHandler.obtainMessage(ON_TASK_CREATED, taskId, 0, componentName).sendToTarget();
+ }
+
+ @Override
+ public void onTaskRemoved(int taskId) {
+ mHandler.obtainMessage(ON_TASK_REMOVED, taskId, 0).sendToTarget();
+ }
+
+ @Override
+ public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ mHandler.obtainMessage(ON_TASK_MOVED_TO_FRONT, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ mHandler.obtainMessage(ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onTaskSnapshotChanged(int taskId, ActivityManager.TaskSnapshot snapshot) {
+ mHandler.obtainMessage(ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
+ }
+
+ @Override
+ public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) {
+ mHandler.obtainMessage(ON_BACK_PRESSED_ON_TASK_ROOT, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = packageName;
+ args.argi1 = userId;
+ args.argi2 = taskId;
+ args.argi3 = stackId;
+ mHandler.removeMessages(ON_ACTIVITY_PINNED);
+ mHandler.obtainMessage(ON_ACTIVITY_PINNED, args).sendToTarget();
+ }
+
+ @Override
+ public void onActivityUnpinned() {
+ mHandler.removeMessages(ON_ACTIVITY_UNPINNED);
+ mHandler.sendEmptyMessage(ON_ACTIVITY_UNPINNED);
+ }
+
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask, boolean wasVisible) {
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = task;
+ args.argi1 = homeTaskVisible ? 1 : 0;
+ args.argi2 = clearedTask ? 1 : 0;
+ args.argi3 = wasVisible ? 1 : 0;
+ mHandler.removeMessages(ON_ACTIVITY_RESTART_ATTEMPT);
+ mHandler.obtainMessage(ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
+ }
+
+ @Override
+ public void onActivityForcedResizable(String packageName, int taskId, int reason) {
+ mHandler.obtainMessage(ON_ACTIVITY_FORCED_RESIZABLE, taskId, reason, packageName)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onActivityDismissingDockedStack() {
+ mHandler.sendEmptyMessage(ON_ACTIVITY_DISMISSING_DOCKED_STACK);
+ }
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayFailed(
+ ActivityManager.RunningTaskInfo taskInfo,
+ int requestedDisplayId) {
+ mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED,
+ requestedDisplayId,
+ 0 /* unused */,
+ taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayRerouted(
+ ActivityManager.RunningTaskInfo taskInfo,
+ int requestedDisplayId) {
+ mHandler.obtainMessage(ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED,
+ requestedDisplayId, 0 /* unused */, taskInfo).sendToTarget();
+ }
+
+ @Override
+ public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
+ mHandler.obtainMessage(ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE, taskId,
+ requestedOrientation).sendToTarget();
+ }
+
+ @Override
+ public void onActivityRotation(int displayId) {
+ mHandler.obtainMessage(ON_ACTIVITY_ROTATION, displayId, 0 /* unused */)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onSizeCompatModeActivityChanged(int displayId, IBinder activityToken) {
+ mHandler.obtainMessage(ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED, displayId,
+ 0 /* unused */,
+ activityToken).sendToTarget();
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ synchronized (mTaskStackListeners) {
+ switch (msg.what) {
+ case ON_TASK_STACK_CHANGED: {
+ Trace.beginSection("onTaskStackChanged");
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskStackChanged();
+ }
+ Trace.endSection();
+ break;
+ }
+ case ON_TASK_SNAPSHOT_CHANGED: {
+ Trace.beginSection("onTaskSnapshotChanged");
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
+ (ActivityManager.TaskSnapshot) msg.obj);
+ }
+ Trace.endSection();
+ break;
+ }
+ case ON_ACTIVITY_PINNED: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityPinned((String) args.arg1, args.argi1,
+ args.argi2, args.argi3);
+ }
+ break;
+ }
+ case ON_ACTIVITY_UNPINNED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityUnpinned();
+ }
+ break;
+ }
+ case ON_ACTIVITY_RESTART_ATTEMPT: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final ActivityManager.RunningTaskInfo
+ task = (ActivityManager.RunningTaskInfo) args.arg1;
+ final boolean homeTaskVisible = args.argi1 != 0;
+ final boolean clearedTask = args.argi2 != 0;
+ final boolean wasVisible = args.argi3 != 0;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityRestartAttempt(task,
+ homeTaskVisible, clearedTask, wasVisible);
+ }
+ break;
+ }
+ case ON_ACTIVITY_FORCED_RESIZABLE: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityForcedResizable(
+ (String) msg.obj, msg.arg1, msg.arg2);
+ }
+ break;
+ }
+ case ON_ACTIVITY_DISMISSING_DOCKED_STACK: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityDismissingDockedStack();
+ }
+ break;
+ }
+ case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED: {
+ final ActivityManager.RunningTaskInfo
+ info = (ActivityManager.RunningTaskInfo) msg.obj;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i)
+ .onActivityLaunchOnSecondaryDisplayFailed(info);
+ }
+ break;
+ }
+ case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_REROUTED: {
+ final ActivityManager.RunningTaskInfo
+ info = (ActivityManager.RunningTaskInfo) msg.obj;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i)
+ .onActivityLaunchOnSecondaryDisplayRerouted(info);
+ }
+ break;
+ }
+ case ON_TASK_PROFILE_LOCKED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
+ }
+ break;
+ }
+ case ON_TASK_CREATED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskCreated(msg.arg1,
+ (ComponentName) msg.obj);
+ }
+ break;
+ }
+ case ON_TASK_REMOVED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskRemoved(msg.arg1);
+ }
+ break;
+ }
+ case ON_TASK_MOVED_TO_FRONT: {
+ final ActivityManager.RunningTaskInfo
+ info = (ActivityManager.RunningTaskInfo) msg.obj;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskMovedToFront(info);
+ }
+ break;
+ }
+ case ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i)
+ .onActivityRequestedOrientationChanged(msg.arg1, msg.arg2);
+ }
+ break;
+ }
+ case ON_SIZE_COMPAT_MODE_ACTIVITY_CHANGED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onSizeCompatModeActivityChanged(
+ msg.arg1, (IBinder) msg.obj);
+ }
+ break;
+ }
+ case ON_BACK_PRESSED_ON_TASK_ROOT: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onBackPressedOnTaskRoot(
+ (ActivityManager.RunningTaskInfo) msg.obj);
+ }
+ break;
+ }
+ case ON_TASK_DISPLAY_CHANGED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskDisplayChanged(msg.arg1, msg.arg2);
+ }
+ break;
+ }
+ case ON_TASK_LIST_UPDATED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onRecentTaskListUpdated();
+ }
+ break;
+ }
+ case ON_TASK_LIST_FROZEN_UNFROZEN: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onRecentTaskListFrozenChanged(
+ msg.arg1 != 0);
+ }
+ break;
+ }
+ case ON_TASK_DESCRIPTION_CHANGED: {
+ final ActivityManager.RunningTaskInfo
+ info = (ActivityManager.RunningTaskInfo) msg.obj;
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskDescriptionChanged(info);
+ }
+ break;
+ }
+ case ON_ACTIVITY_ROTATION: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityRotation(msg.arg1);
+ }
+ break;
+ }
+ }
+ }
+ if (msg.obj instanceof SomeArgs) {
+ ((SomeArgs) msg.obj).recycle();
+ }
+ return true;
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TriangleShape.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TriangleShape.java
new file mode 100644
index 000000000000..707919033065
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TriangleShape.java
@@ -0,0 +1,77 @@
+/*
+ * 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.wm.shell.common;
+
+import android.graphics.Outline;
+import android.graphics.Path;
+import android.graphics.drawable.shapes.PathShape;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Wrapper around {@link PathShape}
+ * that creates a shape with a triangular path (pointing up or down).
+ *
+ * This is the copy from SystemUI/recents.
+ */
+public class TriangleShape extends PathShape {
+ private Path mTriangularPath;
+
+ public TriangleShape(Path path, float stdWidth, float stdHeight) {
+ super(path, stdWidth, stdHeight);
+ mTriangularPath = path;
+ }
+
+ public static TriangleShape create(float width, float height, boolean isPointingUp) {
+ Path triangularPath = new Path();
+ if (isPointingUp) {
+ triangularPath.moveTo(0, height);
+ triangularPath.lineTo(width, height);
+ triangularPath.lineTo(width / 2, 0);
+ triangularPath.close();
+ } else {
+ triangularPath.moveTo(0, 0);
+ triangularPath.lineTo(width / 2, height);
+ triangularPath.lineTo(width, 0);
+ triangularPath.close();
+ }
+ return new TriangleShape(triangularPath, width, height);
+ }
+
+ /** Create an arrow TriangleShape that points to the left or the right */
+ public static TriangleShape createHorizontal(
+ float width, float height, boolean isPointingLeft) {
+ Path triangularPath = new Path();
+ if (isPointingLeft) {
+ triangularPath.moveTo(0, height / 2);
+ triangularPath.lineTo(width, height);
+ triangularPath.lineTo(width, 0);
+ triangularPath.close();
+ } else {
+ triangularPath.moveTo(0, height);
+ triangularPath.lineTo(width, height / 2);
+ triangularPath.lineTo(0, 0);
+ triangularPath.close();
+ }
+ return new TriangleShape(triangularPath, width, height);
+ }
+
+ @Override
+ public void getOutline(@NonNull Outline outline) {
+ outline.setPath(mTriangularPath);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index bf5b1d8a4bcc..625c0a7b5d19 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -16,17 +16,9 @@
package com.android.wm.shell.draganddrop;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
-import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
-import static android.content.Intent.EXTRA_PACKAGE_NAME;
-import static android.content.Intent.EXTRA_SHORTCUT_ID;
-import static android.content.Intent.EXTRA_TASK_ID;
-import static android.content.Intent.EXTRA_USER;
import static android.view.DragEvent.ACTION_DRAG_ENDED;
import static android.view.DragEvent.ACTION_DRAG_ENTERED;
import static android.view.DragEvent.ACTION_DRAG_EXITED;
@@ -42,24 +34,10 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
-import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
-import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.LauncherApps;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.Slog;
import android.util.SparseArray;
import android.view.DragEvent;
@@ -76,6 +54,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreen;
+import java.util.Objects;
import java.util.Optional;
/**
@@ -91,8 +70,6 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
private SplitScreen mSplitScreen;
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
- private boolean mIsHandlingDrag;
- private DragLayout mDragLayout;
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
public DragAndDropController(Context context, DisplayController displayController) {
@@ -124,26 +101,31 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
layoutParams.setFitInsetsTypes(0);
layoutParams.setTitle("ShellDropTarget");
- FrameLayout dropTarget = (FrameLayout) LayoutInflater.from(context).inflate(
+ FrameLayout rootView = (FrameLayout) LayoutInflater.from(context).inflate(
R.layout.global_drop_target, null);
- dropTarget.setOnDragListener(this);
- dropTarget.setVisibility(View.INVISIBLE);
- wm.addView(dropTarget, layoutParams);
- mDisplayDropTargets.put(displayId, new PerDisplay(displayId, context, wm, dropTarget));
+ rootView.setOnDragListener(this);
+ rootView.setVisibility(View.INVISIBLE);
+ DragLayout dragLayout = new DragLayout(context, mSplitScreen);
+ rootView.addView(dragLayout,
+ new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ wm.addView(rootView, layoutParams);
+
+ mDisplayDropTargets.put(displayId,
+ new PerDisplay(displayId, context, wm, rootView, dragLayout));
}
@Override
public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display changed: %d", displayId);
final PerDisplay pd = mDisplayDropTargets.get(displayId);
- pd.dropTarget.requestApplyInsets();
+ pd.rootView.requestApplyInsets();
}
@Override
public void onDisplayRemoved(int displayId) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display removed: %d", displayId);
final PerDisplay pd = mDisplayDropTargets.get(displayId);
- pd.wm.removeViewImmediate(pd.dropTarget);
+ pd.wm.removeViewImmediate(pd.rootView);
mDisplayDropTargets.remove(displayId);
}
@@ -158,32 +140,37 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
final ClipDescription description = event.getClipDescription();
if (event.getAction() == ACTION_DRAG_STARTED) {
- final boolean hasValidClipData = description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
- || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
- || description.hasMimeType(MIMETYPE_APPLICATION_TASK);
- mIsHandlingDrag = hasValidClipData;
+ final boolean hasValidClipData = event.getClipData().getItemCount() > 0
+ && (description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
+ || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
+ || description.hasMimeType(MIMETYPE_APPLICATION_TASK));
+ pd.isHandlingDrag = hasValidClipData;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
- "Clip description: handlingDrag=%b mimeTypes=%s",
- mIsHandlingDrag, getMimeTypes(description));
+ "Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s",
+ pd.isHandlingDrag, event.getClipData().getItemCount(),
+ getMimeTypes(description));
}
- if (!mIsHandlingDrag) {
+ if (!pd.isHandlingDrag) {
return false;
}
switch (event.getAction()) {
case ACTION_DRAG_STARTED:
- mDragLayout = new DragLayout(pd.context,
- mDisplayController.getDisplayLayout(displayId), mSplitScreen);
- pd.dropTarget.addView(mDragLayout,
- new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ if (pd.activeDragCount != 0) {
+ Slog.w(TAG, "Unexpected drag start during an active drag");
+ return false;
+ }
+ pd.activeDragCount++;
+ pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
+ event.getClipData());
setDropTargetWindowVisibility(pd, View.VISIBLE);
break;
case ACTION_DRAG_ENTERED:
- mDragLayout.show(event);
+ pd.dragLayout.show();
break;
case ACTION_DRAG_LOCATION:
- mDragLayout.update(event);
+ pd.dragLayout.update(event);
break;
case ACTION_DROP: {
return handleDrop(event, pd);
@@ -191,20 +178,22 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
case ACTION_DRAG_EXITED: {
// Either one of DROP or EXITED will happen, and when EXITED we won't consume
// the drag surface
- mDragLayout.hide(event, null);
+ pd.dragLayout.hide(event, null);
break;
}
case ACTION_DRAG_ENDED:
// TODO(b/169894807): Ensure sure it's not possible to get ENDED without DROP
// or EXITED
- if (!mDragLayout.hasDropped()) {
- final View dragLayout = mDragLayout;
- mDragLayout.hide(event, () -> {
- setDropTargetWindowVisibility(pd, View.INVISIBLE);
- pd.dropTarget.removeView(dragLayout);
+ if (!pd.dragLayout.hasDropped()) {
+ pd.activeDragCount--;
+ pd.dragLayout.hide(event, () -> {
+ if (pd.activeDragCount == 0) {
+ // Hide the window if another drag hasn't been started while animating
+ // the drag-end
+ setDropTargetWindowVisibility(pd, View.INVISIBLE);
+ }
});
}
- mDragLayout = null;
break;
}
return true;
@@ -214,52 +203,14 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
* Handles dropping on the drop target.
*/
private boolean handleDrop(DragEvent event, PerDisplay pd) {
- final ClipData data = event.getClipData();
- final ClipDescription description = event.getClipDescription();
final SurfaceControl dragSurface = event.getDragSurface();
- final View dragLayout = mDragLayout;
- final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
- final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
- return mDragLayout.drop(event, dragSurface, (dropTargetBounds) -> {
- if (dropTargetBounds != null && data.getItemCount() > 0) {
- final Intent intent = data.getItemAt(0).getIntent();
- // TODO(b/169894807): Properly handle the drop, for now just launch it
- if (isTask) {
- int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
- try {
- ActivityTaskManager.getService().startActivityFromRecents(
- taskId, null);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to launch task", e);
- }
- } else if (isShortcut) {
- try {
- Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)
- ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)
- : null;
- LauncherApps launcherApps =
- mContext.getSystemService(LauncherApps.class);
- launcherApps.startShortcut(
- intent.getStringExtra(EXTRA_PACKAGE_NAME),
- intent.getStringExtra(EXTRA_SHORTCUT_ID),
- null /* sourceBounds */, opts,
- intent.getParcelableExtra(EXTRA_USER));
- } catch (ActivityNotFoundException e) {
- Slog.e(TAG, "Failed to launch shortcut", e);
- }
- } else {
- PendingIntent pi = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
- try {
- pi.send();
- } catch (PendingIntent.CanceledException e) {
- Slog.e(TAG, "Failed to launch activity", e);
- }
- }
+ pd.activeDragCount--;
+ return pd.dragLayout.drop(event, dragSurface, () -> {
+ if (pd.activeDragCount == 0) {
+ // Hide the window if another drag hasn't been started while animating the drop
+ setDropTargetWindowVisibility(pd, View.INVISIBLE);
}
- setDropTargetWindowVisibility(pd, View.INVISIBLE);
- pd.dropTarget.removeView(dragLayout);
-
// Clean up the drag surface
mTransaction.reparent(dragSurface, null);
mTransaction.apply();
@@ -270,9 +221,9 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
"Set drop target window visibility: displayId=%d visibility=%d",
pd.displayId, visibility);
- pd.dropTarget.setVisibility(visibility);
+ pd.rootView.setVisibility(visibility);
if (visibility == View.VISIBLE) {
- pd.dropTarget.requestApplyInsets();
+ pd.rootView.requestApplyInsets();
}
}
@@ -291,13 +242,20 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
final int displayId;
final Context context;
final WindowManager wm;
- final FrameLayout dropTarget;
+ final FrameLayout rootView;
+ final DragLayout dragLayout;
+
+ boolean isHandlingDrag;
+ // A count of the number of active drags in progress to ensure that we only hide the window
+ // when all the drag animations have completed
+ int activeDragCount;
- PerDisplay(int dispId, Context c, WindowManager w, FrameLayout l) {
+ PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayout dl) {
displayId = dispId;
context = c;
wm = w;
- dropTarget = l;
+ rootView = rv;
+ dragLayout = dl;
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
new file mode 100644
index 000000000000..8a547b4477fd
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -0,0 +1,432 @@
+/*
+ * 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.wm.shell.draganddrop;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
+import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
+import static android.content.Intent.EXTRA_SHORTCUT_ID;
+import static android.content.Intent.EXTRA_TASK_ID;
+import static android.content.Intent.EXTRA_USER;
+
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.PendingIntent;
+import android.app.WindowConfiguration;
+import android.content.ActivityNotFoundException;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.LauncherApps;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.splitscreen.SplitScreen;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * The policy for handling drag and drop operations to shell.
+ */
+public class DragAndDropPolicy {
+
+ private static final String TAG = DragAndDropPolicy.class.getSimpleName();
+
+ private final Context mContext;
+ private final IActivityTaskManager mIActivityTaskManager;
+ private final Starter mStarter;
+ private final SplitScreen mSplitScreen;
+ private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
+
+ private DragSession mSession;
+
+ public DragAndDropPolicy(Context context, SplitScreen splitScreen) {
+ this(context, ActivityTaskManager.getService(), splitScreen,
+ new DefaultStarter(context, splitScreen));
+ }
+
+ @VisibleForTesting
+ DragAndDropPolicy(Context context, IActivityTaskManager activityTaskManager,
+ SplitScreen splitScreen, Starter starter) {
+ mContext = context;
+ mIActivityTaskManager = activityTaskManager;
+ mSplitScreen = splitScreen;
+ mStarter = starter;
+ }
+
+ /**
+ * Starts a new drag session with the given initial drag data.
+ */
+ void start(DisplayLayout displayLayout, ClipData data) {
+ mSession = new DragSession(mContext, mIActivityTaskManager, displayLayout, data);
+ // TODO(b/169894807): Also update the session data with task stack changes
+ mSession.update();
+ }
+
+ /**
+ * Returns the target's regions based on the current state of the device and display.
+ */
+ @NonNull
+ ArrayList<Target> getTargets(Insets insets) {
+ mTargets.clear();
+ if (mSession == null) {
+ // Return early if this isn't an app drag
+ return mTargets;
+ }
+
+ final int w = mSession.displayLayout.width();
+ final int h = mSession.displayLayout.height();
+ final int iw = w - insets.left - insets.right;
+ final int ih = h - insets.top - insets.bottom;
+ final int l = insets.left;
+ final int t = insets.top;
+ final boolean isVerticalSplit = mSession.isPhone && !mSession.displayLayout.isLandscape();
+ if (mSession.dragItemSupportsSplitscreen
+ && mSession.runningTaskActType == ACTIVITY_TYPE_STANDARD
+ && mSession.runningTaskWinMode == WINDOWING_MODE_FULLSCREEN
+ && mSession.runningTaskIsResizeable) {
+ // Allow splitting when there is a fullscreen standard activity running
+ if (isVerticalSplit) {
+ // TODO(b/169894807): For now, only allow splitting to the right/bottom until we
+ // have split pairs
+ mTargets.add(new Target(TYPE_FULLSCREEN,
+ new Rect(l, t, l + iw, t + ih / 2),
+ new Rect(l, t, l + iw, t + ih),
+ new Rect(0, 0, w, h)));
+ mTargets.add(new Target(TYPE_SPLIT_BOTTOM,
+ new Rect(l, t + ih / 2, l + iw, t + ih),
+ new Rect(l, t + ih / 2, l + iw, t + ih),
+ new Rect(0, h / 2, w, h)));
+ } else {
+ mTargets.add(new Target(TYPE_FULLSCREEN,
+ new Rect(l, t, l + iw / 2, t + ih),
+ new Rect(l, t, l + iw, t + ih),
+ new Rect(0, 0, w, h)));
+ mTargets.add(new Target(TYPE_SPLIT_RIGHT,
+ new Rect(l + iw / 2, t, l + iw, t + ih),
+ new Rect(l + iw / 2, t, l + iw, t + ih),
+ new Rect(w / 2, 0, w, h)));
+ }
+ } else if (mSession.dragItemSupportsSplitscreen
+ && mSplitScreen != null
+ && mSplitScreen.isDividerVisible()) {
+ // Already split, allow replacing existing split task
+ // TODO(b/169894807): For now, only allow replacing the non-primary task until we have
+ // split pairs
+ final Rect secondarySplitRawBounds =
+ mSplitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds();
+ final Rect secondarySplitBounds = new Rect(secondarySplitRawBounds);
+ secondarySplitBounds.intersect(new Rect(l, t, l + iw, t + ih));
+ if (isVerticalSplit) {
+ mTargets.add(new Target(TYPE_FULLSCREEN,
+ new Rect(l, t, l + iw, secondarySplitRawBounds.top),
+ new Rect(l, t, l + iw, t + ih),
+ new Rect(0, 0, w, secondarySplitRawBounds.top)));
+ } else {
+ mTargets.add(new Target(TYPE_FULLSCREEN,
+ new Rect(l, t, secondarySplitRawBounds.left, t + ih),
+ new Rect(l, t, l + iw, t + ih),
+ new Rect(0, 0, w, h)));
+ }
+ mTargets.add(new Target(isVerticalSplit ? TYPE_SPLIT_BOTTOM : TYPE_SPLIT_RIGHT,
+ new Rect(secondarySplitBounds),
+ new Rect(secondarySplitBounds),
+ new Rect(secondarySplitBounds)));
+ } else {
+ // Otherwise only show the fullscreen target
+ mTargets.add(new Target(TYPE_FULLSCREEN,
+ new Rect(l, t, l + iw, t + ih),
+ new Rect(l, t, l + iw, t + ih),
+ new Rect(0, 0, w, h)));
+ }
+ return mTargets;
+ }
+
+ /**
+ * Returns the target at the given position based on the targets previously calculated.
+ */
+ @Nullable
+ Target getTargetAtLocation(int x, int y) {
+ for (int i = mTargets.size() - 1; i >= 0; i--) {
+ DragAndDropPolicy.Target t = mTargets.get(i);
+ if (t.hitRegion.contains(x, y)) {
+ return t;
+ }
+ }
+ return null;
+ }
+
+ @VisibleForTesting
+ void handleDrop(Target target, ClipData data) {
+ if (target == null || !mTargets.contains(target)) {
+ return;
+ }
+
+ final ClipDescription description = data.getDescription();
+ final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
+ final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
+ final Intent dragData = mSession.dragData;
+
+ boolean deferAppLaunchUntilSplit = false;
+ if (target.type == TYPE_FULLSCREEN) {
+ if (mSplitScreen != null && mSplitScreen.isDividerVisible()) {
+ // If in split, remove split and launch fullscreen
+ mStarter.exitSplitScreen(mSession.runningTaskId);
+ } else {
+ // Not in split, fall through to launch
+ }
+ } else {
+ if (mSplitScreen != null && mSplitScreen.isDividerVisible()) {
+ // Split is already visible, just replace the task
+ // TODO(b/169894807): Since we only allow replacing the non-primary target above
+ // just fall through and start the activity
+ } else {
+ // Not in split, enter split now
+ mStarter.enterSplitScreen(mSession.runningTaskId,
+ target.type == TYPE_SPLIT_LEFT || target.type == TYPE_SPLIT_TOP);
+ deferAppLaunchUntilSplit = true;
+ }
+ }
+
+ final Runnable startAppRunnable = () -> {
+ Bundle opts = dragData.hasExtra(EXTRA_ACTIVITY_OPTIONS)
+ ? dragData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)
+ : null;
+ if (isTask) {
+ mStarter.startTask(dragData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID), opts);
+ } else if (isShortcut) {
+ mStarter.startShortcut(dragData.getStringExtra(EXTRA_PACKAGE_NAME),
+ dragData.getStringExtra(EXTRA_SHORTCUT_ID),
+ opts, dragData.getParcelableExtra(EXTRA_USER));
+ } else {
+ mStarter.startIntent(dragData.getParcelableExtra(EXTRA_PENDING_INTENT), opts);
+ }
+ };
+ if (deferAppLaunchUntilSplit) {
+ // TODO(b/169894807): The enterSplitScreen() call above will trigger the current task
+ // into split, and we should wait for home and other tasks to be moved to
+ // split-secondary before trying to launch the new secondary task. This can be removed
+ // once we have app-pairs.
+ mSplitScreen.registerInSplitScreenListener(new Consumer<Boolean>() {
+ @Override
+ public void accept(Boolean inSplit) {
+ if (inSplit) {
+ startAppRunnable.run();
+ mSplitScreen.unregisterInSplitScreenListener(this);
+ }
+ }
+ });
+ } else {
+ startAppRunnable.run();
+ }
+ }
+
+ /**
+ * Per-drag session data.
+ */
+ private static class DragSession {
+ private final Context mContext;
+ private final IActivityTaskManager mIActivityTaskManager;
+ private final ClipData mInitialDragData;
+
+ final DisplayLayout displayLayout;
+ Intent dragData;
+ int runningTaskId;
+ @WindowConfiguration.WindowingMode
+ int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
+ @WindowConfiguration.ActivityType
+ int runningTaskActType = ACTIVITY_TYPE_STANDARD;
+ boolean runningTaskIsResizeable;
+ boolean dragItemSupportsSplitscreen;
+ boolean isPhone;
+
+ DragSession(Context context, IActivityTaskManager activityTaskManager,
+ DisplayLayout dispLayout, ClipData data) {
+ mContext = context;
+ mIActivityTaskManager = activityTaskManager;
+ mInitialDragData = data;
+ displayLayout = dispLayout;
+ }
+
+ /**
+ * Updates the session data based on the current state of the system.
+ */
+ void update() {
+
+ try {
+ List<ActivityManager.RunningTaskInfo> tasks =
+ mIActivityTaskManager.getFilteredTasks(1,
+ false /* filterOnlyVisibleRecents */);
+ if (!tasks.isEmpty()) {
+ final ActivityManager.RunningTaskInfo task = tasks.get(0);
+ runningTaskWinMode = task.getWindowingMode();
+ runningTaskActType = task.getActivityType();
+ runningTaskId = task.taskId;
+ runningTaskIsResizeable = task.isResizeable;
+ }
+ } catch (RemoteException e) {
+ // Fall through
+ }
+
+ final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
+ dragItemSupportsSplitscreen = info == null
+ || ActivityInfo.isResizeableMode(info.resizeMode);
+ isPhone = mContext.getResources().getConfiguration().smallestScreenWidthDp < 600;
+ dragData = mInitialDragData.getItemAt(0).getIntent();
+ }
+ }
+
+ /**
+ * Interface for actually committing the task launches.
+ */
+ @VisibleForTesting
+ interface Starter {
+ void startTask(int taskId, Bundle activityOptions);
+ void startShortcut(String packageName, String shortcutId, Bundle activityOptions,
+ UserHandle user);
+ void startIntent(PendingIntent intent, Bundle activityOptions);
+ void enterSplitScreen(int taskId, boolean leftOrTop);
+ void exitSplitScreen(int taskId);
+ }
+
+ /**
+ * Default implementation of the starter which calls through the system services to launch the
+ * tasks.
+ */
+ private static class DefaultStarter implements Starter {
+ private final Context mContext;
+ private final SplitScreen mSplitScreen;
+
+ public DefaultStarter(Context context, SplitScreen splitScreen) {
+ mContext = context;
+ mSplitScreen = splitScreen;
+ }
+
+ @Override
+ public void startTask(int taskId, Bundle activityOptions) {
+ try {
+ ActivityTaskManager.getService().startActivityFromRecents(taskId, null);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to launch task", e);
+ }
+ }
+
+ @Override
+ public void startShortcut(String packageName, String shortcutId, Bundle activityOptions,
+ UserHandle user) {
+ try {
+ LauncherApps launcherApps =
+ mContext.getSystemService(LauncherApps.class);
+ launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */,
+ activityOptions, user);
+ } catch (ActivityNotFoundException e) {
+ Slog.e(TAG, "Failed to launch shortcut", e);
+ }
+ }
+
+ @Override
+ public void startIntent(PendingIntent intent, Bundle activityOptions) {
+ try {
+ intent.send(null, 0, null, null, null, null, activityOptions);
+ } catch (PendingIntent.CanceledException e) {
+ Slog.e(TAG, "Failed to launch activity", e);
+ }
+ }
+
+ @Override
+ public void enterSplitScreen(int taskId, boolean leftOrTop) {
+ mSplitScreen.splitPrimaryTask();
+ }
+
+ @Override
+ public void exitSplitScreen(int taskId) {
+ mSplitScreen.dismissSplitToPrimaryTask();
+ }
+ }
+
+ /**
+ * Represents a drop target.
+ */
+ static class Target {
+ static final int TYPE_FULLSCREEN = 0;
+ static final int TYPE_SPLIT_LEFT = 1;
+ static final int TYPE_SPLIT_TOP = 2;
+ static final int TYPE_SPLIT_RIGHT = 3;
+ static final int TYPE_SPLIT_BOTTOM = 4;
+ @IntDef(value = {
+ TYPE_FULLSCREEN,
+ TYPE_SPLIT_LEFT,
+ TYPE_SPLIT_TOP,
+ TYPE_SPLIT_RIGHT,
+ TYPE_SPLIT_BOTTOM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Type{}
+
+ final @Type int type;
+
+ // The actual hit region for this region
+ final Rect hitRegion;
+ // The approximate visual region for where the task will start
+ final Rect drawRegion;
+ // The
+ final Rect dropTargetBounds;
+
+ public Target(@Type int t, Rect hit, Rect draw, Rect drop) {
+ type = t;
+ hitRegion = hit;
+ drawRegion = draw;
+ dropTargetBounds = drop;
+ }
+
+ @Override
+ public String toString() {
+ return "Target {hit=" + hitRegion + " drop=" + dropTargetBounds + "}";
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index b70036b1cce7..5b7531c09a7b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -24,6 +24,7 @@ import static com.android.wm.shell.animation.Interpolators.LINEAR_OUT_SLOW_IN;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.content.ClipData;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Insets;
@@ -52,20 +53,19 @@ import java.util.function.Consumer;
*/
public class DragLayout extends View {
- private final DisplayLayout mDisplayLayout;
- private final SplitScreen mSplitScreen;
+ private final DragAndDropPolicy mPolicy;
- private final ArrayList<Target> mTargets = new ArrayList<>();
- private Target mCurrentTarget = null;
+ private DragAndDropPolicy.Target mCurrentTarget = null;
private DropOutlineDrawable mDropOutline;
private int mDisplayMargin;
private Insets mInsets = Insets.NONE;
+
+ private boolean mIsShowing;
private boolean mHasDropped;
- public DragLayout(Context context, DisplayLayout displayLayout, SplitScreen splitscreen) {
+ public DragLayout(Context context, SplitScreen splitscreen) {
super(context);
- mDisplayLayout = displayLayout;
- mSplitScreen = splitscreen;
+ mPolicy = new DragAndDropPolicy(context, splitscreen);
mDisplayMargin = context.getResources().getDimensionPixelSize(
R.dimen.drop_layout_display_margin);
mDropOutline = new DropOutlineDrawable(context);
@@ -76,7 +76,7 @@ public class DragLayout extends View {
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mInsets = insets.getInsets(Type.systemBars() | Type.displayCutout());
- calculateDropTargets();
+ recomputeDropTargets();
return super.onApplyWindowInsets(insets);
}
@@ -100,82 +100,69 @@ public class DragLayout extends View {
return mHasDropped;
}
- public void show(DragEvent event) {
- calculateDropTargets();
+ public void prepare(DisplayLayout displayLayout, ClipData initialData) {
+ mPolicy.start(displayLayout, initialData);
mHasDropped = false;
+ mCurrentTarget = null;
}
- private void calculateDropTargets() {
- // Calculate all the regions based on split and landscape portrait
- // TODO: Filter based on clip data
- final float SIDE_MARGIN_PCT = 0.3f;
- final int w = mDisplayLayout.width();
- final int h = mDisplayLayout.height();
- final int iw = w - mInsets.left - mInsets.right;
- final int ih = h - mInsets.top - mInsets.bottom;
- final int l = mInsets.left;
- final int t = mInsets.top;
- final int r = mInsets.right;
- final int b = mInsets.bottom;
- mTargets.clear();
-
- // Left split
- addTarget(new Target(
- new Rect(0, 0,
- (int) (w * SIDE_MARGIN_PCT), h),
- new Rect(l + mDisplayMargin, t + mDisplayMargin,
- l + iw / 2 - mDisplayMargin, t + ih - mDisplayMargin),
- new Rect(0, 0, w / 2, h)));
-
- // Fullscreen
- addTarget(new Target(
- new Rect((int) (w * SIDE_MARGIN_PCT), 0,
- w - (int) (w * SIDE_MARGIN_PCT), h),
- new Rect(l + mDisplayMargin, t + mDisplayMargin,
- l + iw - mDisplayMargin, t + ih - mDisplayMargin),
- new Rect(0, 0, w, h)));
-
- // Right split
- addTarget(new Target(
- new Rect(w - (int) (w * SIDE_MARGIN_PCT), 0,
- w, h),
- new Rect(l + iw / 2 + mDisplayMargin, t + mDisplayMargin,
- l + iw - mDisplayMargin, t + ih - mDisplayMargin),
- new Rect(w / 2, 0, w, h)));
+ public void show() {
+ mIsShowing = true;
+ recomputeDropTargets();
}
- private void addTarget(Target t) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Add target: %s", t);
- mTargets.add(t);
+ /**
+ * Recalculates the drop targets based on the current policy.
+ */
+ private void recomputeDropTargets() {
+ if (!mIsShowing) {
+ return;
+ }
+ final ArrayList<DragAndDropPolicy.Target> targets = mPolicy.getTargets(mInsets);
+ for (int i = 0; i < targets.size(); i++) {
+ final DragAndDropPolicy.Target target = targets.get(i);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Add target: %s", target);
+ // Inset the draw region by a little bit
+ target.drawRegion.inset(mDisplayMargin, mDisplayMargin);
+ }
}
+ /**
+ * Updates the visible drop target as the user drags.
+ */
public void update(DragEvent event) {
// Find containing region, if the same as mCurrentRegion, then skip, otherwise, animate the
// visibility of the current region
- Target target = null;
- for (int i = mTargets.size() - 1; i >= 0; i--) {
- Target t = mTargets.get(i);
- if (t.hitRegion.contains((int) event.getX(), (int) event.getY())) {
- target = t;
- break;
- }
- }
- if (target != null && mCurrentTarget != target) {
+ DragAndDropPolicy.Target target = mPolicy.getTargetAtLocation(
+ (int) event.getX(), (int) event.getY());
+ if (mCurrentTarget != target) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
- Interpolator boundsInterpolator = FAST_OUT_SLOW_IN;
- if (mCurrentTarget == null) {
+ if (target == null) {
+ // Animating to no target
+ mDropOutline.startVisibilityAnimation(false, LINEAR);
+ Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
+ finalBounds.inset(mDisplayMargin, mDisplayMargin);
+ mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
+ } else if (mCurrentTarget == null) {
+ // Animating to first target
mDropOutline.startVisibilityAnimation(true, LINEAR);
Rect initialBounds = new Rect(target.drawRegion);
initialBounds.inset(mDisplayMargin, mDisplayMargin);
mDropOutline.setRegionBounds(initialBounds);
- boundsInterpolator = LINEAR_OUT_SLOW_IN;
+ mDropOutline.startBoundsAnimation(target.drawRegion, LINEAR_OUT_SLOW_IN);
+ } else {
+ // Bounds change
+ mDropOutline.startBoundsAnimation(target.drawRegion, FAST_OUT_SLOW_IN);
}
- mDropOutline.startBoundsAnimation(target.drawRegion, boundsInterpolator);
mCurrentTarget = target;
}
}
+ /**
+ * Hides the drag layout and animates out the visible drop targets.
+ */
public void hide(DragEvent event, Runnable hideCompleteCallback) {
+ mIsShowing = false;
ObjectAnimator alphaAnimator = mDropOutline.startVisibilityAnimation(false, LINEAR);
ObjectAnimator boundsAnimator = null;
if (mCurrentTarget != null) {
@@ -199,50 +186,19 @@ public class DragLayout extends View {
mCurrentTarget = null;
}
+ /**
+ * Handles the drop onto a target and animates out the visible drop targets.
+ */
public boolean drop(DragEvent event, SurfaceControl dragSurface,
- Consumer<Rect> dropCompleteCallback) {
+ Runnable dropCompleteCallback) {
+ final boolean handledDrop = mCurrentTarget != null;
mHasDropped = true;
- // TODO(b/169894807): Coordinate with dragSurface
- final Rect dropRegion = mCurrentTarget != null
- ? mCurrentTarget.dropTargetBounds
- : null;
-
- ObjectAnimator alphaAnimator = mDropOutline.startVisibilityAnimation(false, LINEAR);
- ObjectAnimator boundsAnimator = null;
- if (dropRegion != null) {
- Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
- finalBounds.inset(mDisplayMargin, mDisplayMargin);
- mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
- }
-
- if (dropCompleteCallback != null) {
- ObjectAnimator lastAnim = boundsAnimator != null
- ? boundsAnimator
- : alphaAnimator;
- lastAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- dropCompleteCallback.accept(dropRegion);
- }
- });
- }
- return dropRegion != null;
- }
- private static class Target {
- final Rect hitRegion;
- final Rect drawRegion;
- final Rect dropTargetBounds;
+ // Process the drop
+ mPolicy.handleDrop(mCurrentTarget, event.getClipData());
- public Target(Rect hit, Rect draw, Rect drop) {
- hitRegion = hit;
- drawRegion = draw;
- dropTargetBounds = drop;
- }
-
- @Override
- public String toString() {
- return "Target {hit=" + hitRegion + " drop=" + dropTargetBounds + "}";
- }
+ // TODO(b/169894807): Coordinate with dragSurface
+ hide(event, dropCompleteCallback);
+ return handledDrop;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
index 08edc2fb35ac..64f7be5be813 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
@@ -40,7 +40,7 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.R;
/**
- * Drawable to draw the region of the
+ * Drawable to draw the region that the target will have once it is dropped.
*/
public class DropOutlineDrawable extends Drawable {
diff --git a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMComponent.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java
index c6a7fd2f822d..38e0519b7a90 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMComponent.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java
@@ -14,26 +14,26 @@
* limitations under the License.
*/
-package com.android.systemui.wmshell;
+package com.android.wm.shell.hidedisplaycutout;
-import com.android.systemui.dagger.WMComponent;
-import com.android.systemui.dagger.WMSingleton;
+import android.content.res.Configuration;
-import dagger.Subcomponent;
+import androidx.annotation.NonNull;
+import java.io.PrintWriter;
/**
- * Dagger Subcomponent for WindowManager.
+ * Interface to engage hide display cutout feature.
*/
-@WMSingleton
-@Subcomponent(modules = {CarWMShellModule.class})
-public interface CarWMComponent extends WMComponent {
+public interface HideDisplayCutout {
+ /**
+ * Notifies {@link Configuration} changed.
+ * @param newConfig
+ */
+ void onConfigurationChanged(Configuration newConfig);
/**
- * Builder for a SysUIComponent.
+ * Dumps hide display cutout status.
*/
- @Subcomponent.Builder
- interface Builder extends WMComponent.Builder {
- CarWMComponent build();
- }
+ void dump(@NonNull PrintWriter pw);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java
new file mode 100644
index 000000000000..e4e254633395
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java
@@ -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.
+ */
+
+package com.android.wm.shell.hidedisplaycutout;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.SystemProperties;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.wm.shell.common.DisplayController;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the hide display cutout status.
+ */
+public class HideDisplayCutoutController implements HideDisplayCutout {
+ private static final String TAG = "HideDisplayCutoutController";
+
+ private final Context mContext;
+ private final HideDisplayCutoutOrganizer mOrganizer;
+ @VisibleForTesting
+ boolean mEnabled;
+
+ HideDisplayCutoutController(Context context, HideDisplayCutoutOrganizer organizer) {
+ mContext = context;
+ mOrganizer = organizer;
+ updateStatus();
+ }
+
+ /**
+ * Creates {@link HideDisplayCutoutController}, returns {@code null} if the feature is not
+ * supported.
+ */
+ @Nullable
+ public static HideDisplayCutoutController create(
+ Context context, DisplayController displayController) {
+ // The SystemProperty is set for devices that support this feature and is used to control
+ // whether to create the HideDisplayCutout instance.
+ // It's defined in the device.mk (e.g. device/google/crosshatch/device.mk).
+ if (!SystemProperties.getBoolean("ro.support_hide_display_cutout", false)) {
+ return null;
+ }
+
+ HideDisplayCutoutOrganizer organizer =
+ new HideDisplayCutoutOrganizer(context, displayController);
+ return new HideDisplayCutoutController(context, organizer);
+ }
+
+ @VisibleForTesting
+ void updateStatus() {
+ // The config value is used for controlling enabling/disabling status of the feature and is
+ // defined in the config.xml in a "Hide Display Cutout" overlay package (e.g. device/google/
+ // crosshatch/crosshatch/overlay/packages/apps/overlays/NoCutoutOverlay).
+ final boolean enabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_hideDisplayCutoutWithDisplayArea);
+ if (enabled == mEnabled) {
+ return;
+ }
+
+ mEnabled = enabled;
+ if (enabled) {
+ mOrganizer.enableHideDisplayCutout();
+ } else {
+ mOrganizer.disableHideDisplayCutout();
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ updateStatus();
+ }
+
+ @Override
+ public void dump(@NonNull PrintWriter pw) {
+ final String prefix = " ";
+ pw.print(TAG);
+ pw.println(" states: ");
+ pw.print(prefix);
+ pw.print("mEnabled=");
+ pw.println(mEnabled);
+ mOrganizer.dump(pw);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
new file mode 100644
index 000000000000..090d2270817b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java
@@ -0,0 +1,330 @@
+/*
+ * 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.wm.shell.hidedisplaycutout;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.content.Context;
+import android.graphics.Insets;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.RotationUtils;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.window.DisplayAreaAppearedInfo;
+import android.window.DisplayAreaInfo;
+import android.window.DisplayAreaOrganizer;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.internal.R;
+import com.android.wm.shell.common.DisplayChangeController;
+import com.android.wm.shell.common.DisplayController;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Manages the display areas of hide display cutout feature.
+ */
+class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer {
+ private static final String TAG = "HideDisplayCutoutOrganizer";
+
+ private final Context mContext;
+ private final DisplayController mDisplayController;
+
+ @VisibleForTesting
+ @GuardedBy("this")
+ ArrayMap<WindowContainerToken, SurfaceControl> mDisplayAreaMap = new ArrayMap();
+ // The default display bound in natural orientation.
+ private final Rect mDefaultDisplayBounds = new Rect();
+ @VisibleForTesting
+ final Rect mCurrentDisplayBounds = new Rect();
+ // The default display cutout in natural orientation.
+ private Insets mDefaultCutoutInsets;
+ private Insets mCurrentCutoutInsets;
+ private boolean mIsDefaultPortrait;
+ private int mStatusBarHeight;
+ @VisibleForTesting
+ int mOffsetX;
+ @VisibleForTesting
+ int mOffsetY;
+ @VisibleForTesting
+ int mRotation;
+
+ /**
+ * Handles rotation based on OnDisplayChangingListener callback.
+ */
+ private final DisplayChangeController.OnDisplayChangingListener mRotationController =
+ (display, fromRotation, toRotation, wct) -> {
+ mRotation = toRotation;
+ updateBoundsAndOffsets(true /* enable */);
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ applyAllBoundsAndOffsets(wct, t);
+ // Only apply t here since the server will do the wct.apply when the method
+ // finishes.
+ t.apply();
+ };
+
+ HideDisplayCutoutOrganizer(Context context, DisplayController displayController) {
+ mContext = context;
+ mDisplayController = displayController;
+ }
+
+ @Override
+ public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
+ @NonNull SurfaceControl leash) {
+ if (!addDisplayAreaInfoAndLeashToMap(displayAreaInfo, leash)) {
+ return;
+ }
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ applyBoundsAndOffsets(displayAreaInfo.token, leash, wct, tx);
+ applyTransaction(wct, tx);
+ }
+
+ @Override
+ public void onDisplayAreaVanished(@NonNull DisplayAreaInfo displayAreaInfo) {
+ synchronized (this) {
+ if (!mDisplayAreaMap.containsKey(displayAreaInfo.token)) {
+ Log.w(TAG, "Unrecognized token: " + displayAreaInfo.token);
+ return;
+ }
+
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ applyBoundsAndOffsets(
+ displayAreaInfo.token, mDisplayAreaMap.get(displayAreaInfo.token), wct, t);
+ applyTransaction(wct, t);
+ mDisplayAreaMap.remove(displayAreaInfo.token);
+ }
+ }
+
+ private void updateDisplayAreaMap(List<DisplayAreaAppearedInfo> displayAreaInfos) {
+ for (int i = 0; i < displayAreaInfos.size(); i++) {
+ final DisplayAreaInfo info = displayAreaInfos.get(i).getDisplayAreaInfo();
+ final SurfaceControl leash = displayAreaInfos.get(i).getLeash();
+ addDisplayAreaInfoAndLeashToMap(info, leash);
+ }
+ }
+
+ @VisibleForTesting
+ boolean addDisplayAreaInfoAndLeashToMap(@NonNull DisplayAreaInfo displayAreaInfo,
+ @NonNull SurfaceControl leash) {
+ synchronized (this) {
+ if (displayAreaInfo.displayId != DEFAULT_DISPLAY) {
+ return false;
+ }
+ if (mDisplayAreaMap.containsKey(displayAreaInfo.token)) {
+ Log.w(TAG, "Already appeared token: " + displayAreaInfo.token);
+ return false;
+ }
+ mDisplayAreaMap.put(displayAreaInfo.token, leash);
+ return true;
+ }
+ }
+
+ /**
+ * Enables hide display cutout.
+ */
+ void enableHideDisplayCutout() {
+ mDisplayController.addDisplayChangingController(mRotationController);
+ final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY);
+ if (display != null) {
+ mRotation = display.getRotation();
+ }
+ final List<DisplayAreaAppearedInfo> displayAreaInfos =
+ registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
+ updateDisplayAreaMap(displayAreaInfos);
+ updateBoundsAndOffsets(true /* enabled */);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ applyAllBoundsAndOffsets(wct, t);
+ applyTransaction(wct, t);
+ }
+
+ /**
+ * Disables hide display cutout.
+ */
+ void disableHideDisplayCutout() {
+ updateBoundsAndOffsets(false /* enabled */);
+ mDisplayController.removeDisplayChangingController(mRotationController);
+ unregisterOrganizer();
+ }
+
+ @VisibleForTesting
+ Insets getDisplayCutoutInsetsOfNaturalOrientation() {
+ final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY);
+ if (display == null) {
+ return Insets.NONE;
+ }
+ DisplayCutout cutout = display.getCutout();
+ Insets insets = cutout != null ? Insets.of(cutout.getSafeInsets()) : Insets.NONE;
+ return mRotation != Surface.ROTATION_0
+ ? RotationUtils.rotateInsets(insets, 4 /* total number of rotation */ - mRotation)
+ : insets;
+ }
+
+ @VisibleForTesting
+ Rect getDisplayBoundsOfNaturalOrientation() {
+ Point realSize = new Point(0, 0);
+ final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY);
+ if (display != null) {
+ display.getRealSize(realSize);
+ }
+ final boolean isDisplaySizeFlipped = isDisplaySizeFlipped();
+ return new Rect(
+ 0,
+ 0,
+ isDisplaySizeFlipped ? realSize.y : realSize.x,
+ isDisplaySizeFlipped ? realSize.x : realSize.y);
+ }
+
+ private boolean isDisplaySizeFlipped() {
+ return mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270;
+ }
+
+ /**
+ * Updates bounds and offsets according to current state.
+ *
+ * @param enabled whether the hide display cutout feature is enabled.
+ */
+ @VisibleForTesting
+ void updateBoundsAndOffsets(boolean enabled) {
+ if (!enabled) {
+ resetBoundsAndOffsets();
+ } else {
+ initDefaultValuesIfNeeded();
+
+ // Reset to default values.
+ mCurrentDisplayBounds.set(mDefaultDisplayBounds);
+ mOffsetX = 0;
+ mOffsetY = 0;
+
+ // Update bounds and insets according to the rotation.
+ mCurrentCutoutInsets = RotationUtils.rotateInsets(mDefaultCutoutInsets, mRotation);
+ if (isDisplaySizeFlipped()) {
+ mCurrentDisplayBounds.set(
+ mCurrentDisplayBounds.top,
+ mCurrentDisplayBounds.left,
+ mCurrentDisplayBounds.bottom,
+ mCurrentDisplayBounds.right);
+ }
+ mCurrentDisplayBounds.inset(mCurrentCutoutInsets);
+
+ // Replace the top bound with the max(status bar height, cutout height) if there is
+ // cutout on the top side.
+ mStatusBarHeight = getStatusBarHeight();
+ if (mCurrentCutoutInsets.top != 0) {
+ mCurrentDisplayBounds.top = Math.max(mStatusBarHeight, mCurrentCutoutInsets.top);
+ }
+ mOffsetX = mCurrentDisplayBounds.left;
+ mOffsetY = mCurrentDisplayBounds.top;
+ }
+ }
+
+ private void resetBoundsAndOffsets() {
+ mCurrentDisplayBounds.setEmpty();
+ mOffsetX = 0;
+ mOffsetY = 0;
+ }
+
+ private void initDefaultValuesIfNeeded() {
+ if (!mDefaultDisplayBounds.isEmpty()) {
+ return;
+ }
+ mDefaultDisplayBounds.set(getDisplayBoundsOfNaturalOrientation());
+ mDefaultCutoutInsets = getDisplayCutoutInsetsOfNaturalOrientation();
+ mIsDefaultPortrait = mDefaultDisplayBounds.width() < mDefaultDisplayBounds.height();
+ }
+
+ private void applyAllBoundsAndOffsets(
+ WindowContainerTransaction wct, SurfaceControl.Transaction t) {
+ synchronized (this) {
+ mDisplayAreaMap.forEach((token, leash) -> {
+ applyBoundsAndOffsets(token, leash, wct, t);
+ });
+ }
+ }
+
+ @VisibleForTesting
+ void applyBoundsAndOffsets(WindowContainerToken token, SurfaceControl leash,
+ WindowContainerTransaction wct, SurfaceControl.Transaction t) {
+ wct.setBounds(token, mCurrentDisplayBounds.isEmpty() ? null : mCurrentDisplayBounds);
+ t.setPosition(leash, mOffsetX, mOffsetY);
+ }
+
+ @VisibleForTesting
+ void applyTransaction(WindowContainerTransaction wct, SurfaceControl.Transaction t) {
+ applyTransaction(wct);
+ t.apply();
+ }
+
+ private int getStatusBarHeight() {
+ final boolean isLandscape =
+ mIsDefaultPortrait ? isDisplaySizeFlipped() : !isDisplaySizeFlipped();
+ return mContext.getResources().getDimensionPixelSize(
+ isLandscape ? R.dimen.status_bar_height_landscape
+ : R.dimen.status_bar_height_portrait);
+ }
+
+ void dump(@NonNull PrintWriter pw) {
+ final String prefix = " ";
+ pw.print(TAG);
+ pw.println(" states: ");
+ synchronized (this) {
+ pw.print(prefix);
+ pw.print("mDisplayAreaMap=");
+ pw.println(mDisplayAreaMap);
+ }
+ pw.print(prefix);
+ pw.print("getDisplayBoundsOfNaturalOrientation()=");
+ pw.println(getDisplayBoundsOfNaturalOrientation());
+ pw.print(prefix);
+ pw.print("mDefaultDisplayBounds=");
+ pw.println(mDefaultDisplayBounds);
+ pw.print(prefix);
+ pw.print("mCurrentDisplayBounds=");
+ pw.println(mCurrentDisplayBounds);
+ pw.print(prefix);
+ pw.print("mDefaultCutoutInsets=");
+ pw.println(mDefaultCutoutInsets);
+ pw.print(prefix);
+ pw.print("mCurrentCutoutInsets=");
+ pw.println(mCurrentCutoutInsets);
+ pw.print(prefix);
+ pw.print("mRotation=");
+ pw.println(mRotation);
+ pw.print(prefix);
+ pw.print("mStatusBarHeight=");
+ pw.println(mStatusBarHeight);
+ pw.print(prefix);
+ pw.print("mOffsetX=");
+ pw.println(mOffsetX);
+ pw.print(prefix);
+ pw.print("mOffsetY=");
+ pw.println(mOffsetY);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 7d039d4d92f6..f84936e5f386 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -19,6 +19,7 @@ package com.android.wm.shell.onehanded;
import static android.os.UserHandle.USER_CURRENT;
import static android.view.Display.DEFAULT_DISPLAY;
+import android.content.ComponentName;
import android.content.Context;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
@@ -38,6 +39,8 @@ import androidx.annotation.VisibleForTesting;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
import java.io.PrintWriter;
@@ -164,7 +167,8 @@ public class OneHandedController implements OneHanded {
*/
@Nullable
public static OneHandedController create(
- Context context, DisplayController displayController) {
+ Context context, DisplayController displayController,
+ TaskStackListenerImpl taskStackListener) {
if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
Slog.w(TAG, "Device doesn't support OneHanded feature");
return null;
@@ -181,7 +185,7 @@ public class OneHandedController implements OneHanded {
IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
ServiceManager.getService(Context.OVERLAY_SERVICE));
return new OneHandedController(context, displayController, organizer, touchHandler,
- tutorialHandler, gestureHandler, overlayManager);
+ tutorialHandler, gestureHandler, overlayManager, taskStackListener);
}
@VisibleForTesting
@@ -191,7 +195,8 @@ public class OneHandedController implements OneHanded {
OneHandedTouchHandler touchHandler,
OneHandedTutorialHandler tutorialHandler,
OneHandedGestureHandler gestureHandler,
- IOverlayManager overlayManager) {
+ IOverlayManager overlayManager,
+ TaskStackListenerImpl taskStackListener) {
mContext = context;
mDisplayAreaOrganizer = displayAreaOrganizer;
mDisplayController = displayController;
@@ -216,6 +221,19 @@ public class OneHandedController implements OneHanded {
setupTimeoutListener();
setupGesturalOverlay();
updateSettings();
+
+ taskStackListener.addListener(
+ new TaskStackListenerCallback() {
+ @Override
+ public void onTaskCreated(int taskId, ComponentName componentName) {
+ stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
+ }
+
+ @Override
+ public void onTaskMovedToFront(int taskId) {
+ stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
+ }
+ });
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index 8d5da1a5ffcb..9fa222ad4fdd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -81,30 +81,6 @@ public interface Pip {
}
/**
- * Called whenever an Activity is moved to the pinned stack from another stack.
- */
- default void onActivityPinned(String packageName) {
- }
-
- /**
- * Called whenever an Activity is moved from the pinned stack to another stack
- */
- default void onActivityUnpinned(ComponentName topActivity) {
- }
-
- /**
- * Called whenever IActivityManager.startActivity is called on an activity that is already
- * running, but the task is either brought to the front or a new Intent is delivered to it.
- *
- * @param task information about the task the activity was relaunched into
- * @param clearedTask whether or not the launch activity also cleared the task as a part of
- * starting
- */
- default void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean clearedTask) {
- }
-
- /**
* Called when display size or font size of settings changed
*/
default void onDensityOrFontScaleChanged() {
@@ -132,12 +108,6 @@ public interface Pip {
}
/**
- * Called when task stack changed.
- */
- default void onTaskStackChanged() {
- }
-
- /**
* Resize the Pip to the appropriate size for the input state.
*
* @param state In Pip state also used to determine the new size for the Pip.
@@ -214,4 +184,11 @@ public interface Pip {
default void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
return;
}
+
+ /**
+ * Called by NavigationBar in order to listen in for PiP bounds change. This is mostly used
+ * for times where the PiP bounds could conflict with SystemUI elements, such as a stashed
+ * PiP and the Back-from-Edge gesture.
+ */
+ default void setPipExclusionBoundsChangeListener(Consumer<Rect> listener) { }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
new file mode 100644
index 000000000000..df6683ebb80b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -0,0 +1,318 @@
+/*
+ * 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.wm.shell.pip;
+
+import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.DisplayMetrics;
+import android.util.Size;
+import android.util.TypedValue;
+import android.view.DisplayInfo;
+import android.view.Gravity;
+
+import java.io.PrintWriter;
+
+/**
+ * Calculates the default, normal, entry, inset and movement bounds of the PIP.
+ */
+public class PipBoundsAlgorithm {
+
+ private static final String TAG = PipBoundsAlgorithm.class.getSimpleName();
+ private static final float INVALID_SNAP_FRACTION = -1f;
+
+ private final @NonNull PipBoundsState mPipBoundsState;
+ private final PipSnapAlgorithm mSnapAlgorithm;
+
+ private float mDefaultAspectRatio;
+ private float mMinAspectRatio;
+ private float mMaxAspectRatio;
+ private int mDefaultStackGravity;
+ private int mDefaultMinSize;
+ private Point mScreenEdgeInsets;
+
+ public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState) {
+ mPipBoundsState = pipBoundsState;
+ mSnapAlgorithm = new PipSnapAlgorithm(context);
+ reloadResources(context);
+ // Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
+ // resources as it would clobber mAspectRatio when entering PiP from fullscreen which
+ // triggers a configuration change and the resources to be reloaded.
+ mPipBoundsState.setAspectRatio(mDefaultAspectRatio);
+ mPipBoundsState.setMinEdgeSize(mDefaultMinSize);
+ }
+
+ /**
+ * TODO: move the resources to SysUI package.
+ */
+ private void reloadResources(Context context) {
+ final Resources res = context.getResources();
+ mDefaultAspectRatio = res.getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
+ mDefaultStackGravity = res.getInteger(
+ com.android.internal.R.integer.config_defaultPictureInPictureGravity);
+ mDefaultMinSize = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
+ final String screenEdgeInsetsDpString = res.getString(
+ com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
+ final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
+ ? Size.parseSize(screenEdgeInsetsDpString)
+ : null;
+ mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
+ : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), res.getDisplayMetrics()),
+ dpToPx(screenEdgeInsetsDp.getHeight(), res.getDisplayMetrics()));
+ mMinAspectRatio = res.getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
+ mMaxAspectRatio = res.getFloat(
+ com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
+ }
+
+ /**
+ * The {@link PipSnapAlgorithm} is couple on display bounds
+ * @return {@link PipSnapAlgorithm}.
+ */
+ public PipSnapAlgorithm getSnapAlgorithm() {
+ return mSnapAlgorithm;
+ }
+
+ /**
+ * Responds to IPinnedStackListener on configuration change.
+ */
+ public void onConfigurationChanged(Context context) {
+ reloadResources(context);
+ }
+
+ /** Returns the normal bounds (i.e. the default entry bounds). */
+ public Rect getNormalBounds() {
+ // The normal bounds are the default bounds adjusted to the current aspect ratio.
+ return transformBoundsToAspectRatioIfValid(getDefaultBounds(),
+ mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */,
+ false /* useCurrentSize */);
+ }
+
+ /** Returns the default bounds. */
+ public Rect getDefaultBounds() {
+ return getDefaultBounds(INVALID_SNAP_FRACTION, null /* size */);
+ }
+
+ /** Returns the destination bounds to place the PIP window on entry. */
+ public Rect getEntryDestinationBounds() {
+ final PipBoundsState.PipReentryState reentryState = mPipBoundsState.getReentryState();
+ final boolean shouldRestoreReentryBounds = reentryState != null;
+
+ final Rect destinationBounds = shouldRestoreReentryBounds
+ ? getDefaultBounds(reentryState.getSnapFraction(), reentryState.getSize())
+ : getDefaultBounds();
+
+ return transformBoundsToAspectRatioIfValid(destinationBounds,
+ mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */,
+ shouldRestoreReentryBounds);
+ }
+
+ /** Returns the current bounds adjusted to the new aspect ratio, if valid. */
+ public Rect getAdjustedDestinationBounds(Rect currentBounds, float newAspectRatio) {
+ return transformBoundsToAspectRatioIfValid(currentBounds, newAspectRatio,
+ true /* useCurrentMinEdgeSize */, false /* useCurrentSize */);
+ }
+
+ public float getDefaultAspectRatio() {
+ return mDefaultAspectRatio;
+ }
+
+ /**
+ * @return whether the given {@param aspectRatio} is valid.
+ */
+ private boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
+ return Float.compare(mMinAspectRatio, aspectRatio) <= 0
+ && Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
+ }
+
+ private Rect transformBoundsToAspectRatioIfValid(Rect bounds, float aspectRatio,
+ boolean useCurrentMinEdgeSize, boolean useCurrentSize) {
+ final Rect destinationBounds = new Rect(bounds);
+ if (isValidPictureInPictureAspectRatio(aspectRatio)) {
+ transformBoundsToAspectRatio(destinationBounds, aspectRatio,
+ useCurrentMinEdgeSize, useCurrentSize);
+ }
+ return destinationBounds;
+ }
+
+ /**
+ * Set the current bounds (or the default bounds if there are no current bounds) with the
+ * specified aspect ratio.
+ */
+ public void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
+ boolean useCurrentMinEdgeSize, boolean useCurrentSize) {
+ // Save the snap fraction and adjust the size based on the new aspect ratio.
+ final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
+ getMovementBounds(stackBounds), mPipBoundsState.getStashedState());
+
+ final Size overrideMinSize = mPipBoundsState.getOverrideMinSize();
+ final Size size;
+ if (useCurrentMinEdgeSize || useCurrentSize) {
+ // The default minimum edge size, or the override min edge size if set.
+ final int defaultMinEdgeSize = overrideMinSize == null ? mDefaultMinSize
+ : mPipBoundsState.getOverrideMinEdgeSize();
+ final int minEdgeSize = useCurrentMinEdgeSize ? mPipBoundsState.getMinEdgeSize()
+ : defaultMinEdgeSize;
+ // Use the existing size but adjusted to the aspect ratio and min edge size.
+ size = mSnapAlgorithm.getSizeForAspectRatio(
+ new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize);
+ } else {
+ if (overrideMinSize != null) {
+ // The override minimal size is set, use that as the default size making sure it's
+ // adjusted to the aspect ratio.
+ size = adjustSizeToAspectRatio(overrideMinSize, aspectRatio);
+ } else {
+ // Calculate the default size using the display size and default min edge size.
+ final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
+ size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, mDefaultMinSize,
+ displayInfo.logicalWidth, displayInfo.logicalHeight);
+ }
+ }
+
+ final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
+ final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f);
+ stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight());
+ mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
+ }
+
+ /** Adjusts the given size to conform to the given aspect ratio. */
+ private Size adjustSizeToAspectRatio(@NonNull Size size, float aspectRatio) {
+ final float sizeAspectRatio = size.getWidth() / (float) size.getHeight();
+ if (sizeAspectRatio > aspectRatio) {
+ // Size is wider, fix the width and increase the height
+ return new Size(size.getWidth(), (int) (size.getWidth() / aspectRatio));
+ } else {
+ // Size is taller, fix the height and adjust the width.
+ return new Size((int) (size.getHeight() * aspectRatio), size.getHeight());
+ }
+ }
+
+ /**
+ * @return the default bounds to show the PIP, if a {@param snapFraction} and {@param size} are
+ * provided, then it will apply the default bounds to the provided snap fraction and size.
+ */
+ private Rect getDefaultBounds(float snapFraction, Size size) {
+ final Rect defaultBounds = new Rect();
+ if (snapFraction != INVALID_SNAP_FRACTION && size != null) {
+ defaultBounds.set(0, 0, size.getWidth(), size.getHeight());
+ final Rect movementBounds = getMovementBounds(defaultBounds);
+ mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
+ } else {
+ final Rect insetBounds = new Rect();
+ getInsetBounds(insetBounds);
+ final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
+ final Size defaultSize;
+ final Size overrideMinSize = mPipBoundsState.getOverrideMinSize();
+ if (overrideMinSize != null) {
+ // The override minimal size is set, use that as the default size making sure it's
+ // adjusted to the aspect ratio.
+ defaultSize = adjustSizeToAspectRatio(overrideMinSize, mDefaultAspectRatio);
+ } else {
+ // Calculate the default size using the display size and default min edge size.
+ defaultSize = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
+ mDefaultMinSize, displayInfo.logicalWidth, displayInfo.logicalHeight);
+ }
+ Gravity.apply(mDefaultStackGravity, defaultSize.getWidth(), defaultSize.getHeight(),
+ insetBounds, 0, Math.max(
+ mPipBoundsState.isImeShowing() ? mPipBoundsState.getImeHeight() : 0,
+ mPipBoundsState.isShelfShowing()
+ ? mPipBoundsState.getShelfHeight() : 0), defaultBounds);
+ }
+ return defaultBounds;
+ }
+
+ /**
+ * Populates the bounds on the screen that the PIP can be visible in.
+ */
+ public void getInsetBounds(Rect outRect) {
+ final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
+ Rect insets = mPipBoundsState.getDisplayLayout().stableInsets();
+ outRect.set(insets.left + mScreenEdgeInsets.x,
+ insets.top + mScreenEdgeInsets.y,
+ displayInfo.logicalWidth - insets.right - mScreenEdgeInsets.x,
+ displayInfo.logicalHeight - insets.bottom - mScreenEdgeInsets.y);
+ }
+
+ /**
+ * @return the movement bounds for the given stackBounds and the current state of the
+ * controller.
+ */
+ public Rect getMovementBounds(Rect stackBounds) {
+ return getMovementBounds(stackBounds, true /* adjustForIme */);
+ }
+
+ /**
+ * @return the movement bounds for the given stackBounds and the current state of the
+ * controller.
+ */
+ public Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
+ final Rect movementBounds = new Rect();
+ getInsetBounds(movementBounds);
+
+ // Apply the movement bounds adjustments based on the current state.
+ mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
+ (adjustForIme && mPipBoundsState.isImeShowing())
+ ? mPipBoundsState.getImeHeight() : 0);
+ return movementBounds;
+ }
+
+ /**
+ * @return the default snap fraction to apply instead of the default gravity when calculating
+ * the default stack bounds when first entering PiP.
+ */
+ public float getSnapFraction(Rect stackBounds) {
+ return mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds));
+ }
+
+ /**
+ * Applies the given snap fraction to the given stack bounds.
+ */
+ public void applySnapFraction(Rect stackBounds, float snapFraction) {
+ final Rect movementBounds = getMovementBounds(stackBounds);
+ mSnapAlgorithm.applySnapFraction(stackBounds, movementBounds, snapFraction);
+ }
+
+ public int getDefaultMinSize() {
+ return mDefaultMinSize;
+ }
+
+ /**
+ * @return the pixels for a given dp value.
+ */
+ private int dpToPx(float dpValue, DisplayMetrics dm) {
+ return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, dm);
+ }
+
+ /**
+ * Dumps internal states.
+ */
+ public void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + "mDefaultAspectRatio=" + mDefaultAspectRatio);
+ pw.println(innerPrefix + "mMinAspectRatio=" + mMinAspectRatio);
+ pw.println(innerPrefix + "mMaxAspectRatio=" + mMaxAspectRatio);
+ pw.println(innerPrefix + "mDefaultStackGravity=" + mDefaultStackGravity);
+ pw.println(innerPrefix + "mSnapAlgorithm" + mSnapAlgorithm);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java
deleted file mode 100644
index 4a9e28e8d9ff..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsHandler.java
+++ /dev/null
@@ -1,467 +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.wm.shell.pip;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
-
-import android.annotation.NonNull;
-import android.app.ActivityTaskManager;
-import android.app.ActivityTaskManager.RootTaskInfo;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.RemoteException;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.Size;
-import android.util.TypedValue;
-import android.view.DisplayInfo;
-import android.view.Gravity;
-import android.window.WindowContainerTransaction;
-
-import java.io.PrintWriter;
-
-/**
- * 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.
- */
-public class PipBoundsHandler {
-
- private static final String TAG = PipBoundsHandler.class.getSimpleName();
- private static final float INVALID_SNAP_FRACTION = -1f;
-
- private final @NonNull PipBoundsState mPipBoundsState;
- private final PipSnapAlgorithm mSnapAlgorithm;
-
- private float mDefaultAspectRatio;
- private float mMinAspectRatio;
- private float mMaxAspectRatio;
- private int mDefaultStackGravity;
- private int mDefaultMinSize;
- private Point mScreenEdgeInsets;
- private int mCurrentMinSize;
- private Size mOverrideMinimalSize;
-
- private boolean mIsImeShowing;
- private int mImeHeight;
- private boolean mIsShelfShowing;
- private int mShelfHeight;
-
- public PipBoundsHandler(Context context, @NonNull PipBoundsState pipBoundsState) {
- mPipBoundsState = pipBoundsState;
- mSnapAlgorithm = new PipSnapAlgorithm(context);
- reloadResources(context);
- // Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
- // resources as it would clobber mAspectRatio when entering PiP from fullscreen which
- // triggers a configuration change and the resources to be reloaded.
- mPipBoundsState.setAspectRatio(mDefaultAspectRatio);
- }
-
- /**
- * TODO: move the resources to SysUI package.
- */
- private void reloadResources(Context context) {
- final Resources res = context.getResources();
- mDefaultAspectRatio = res.getFloat(
- com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
- mDefaultStackGravity = res.getInteger(
- com.android.internal.R.integer.config_defaultPictureInPictureGravity);
- mDefaultMinSize = res.getDimensionPixelSize(
- com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
- mCurrentMinSize = mDefaultMinSize;
- final String screenEdgeInsetsDpString = res.getString(
- com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
- final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
- ? Size.parseSize(screenEdgeInsetsDpString)
- : null;
- mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
- : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), res.getDisplayMetrics()),
- dpToPx(screenEdgeInsetsDp.getHeight(), res.getDisplayMetrics()));
- mMinAspectRatio = res.getFloat(
- com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
- mMaxAspectRatio = res.getFloat(
- com.android.internal.R.dimen.config_pictureInPictureMaxAspectRatio);
- }
-
- /**
- * Update the Min edge size for {@link PipSnapAlgorithm} to calculate corresponding bounds
- * @param minEdgeSize
- */
- public void setMinEdgeSize(int minEdgeSize) {
- mCurrentMinSize = minEdgeSize;
- }
-
- /**
- * Sets both shelf visibility and its height if applicable.
- * @return {@code true} if the internal shelf state is changed, {@code false} otherwise.
- */
- public boolean setShelfHeight(boolean shelfVisible, int shelfHeight) {
- final boolean shelfShowing = shelfVisible && shelfHeight > 0;
- if (shelfShowing == mIsShelfShowing && shelfHeight == mShelfHeight) {
- return false;
- }
-
- mIsShelfShowing = shelfVisible;
- mShelfHeight = shelfHeight;
- return true;
- }
-
- /**
- * Responds to IPinnedStackListener on IME visibility change.
- */
- public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
- mIsImeShowing = imeVisible;
- mImeHeight = imeHeight;
- }
-
- /**
- * Responds to IPinnedStackListener on movement bounds change.
- * Note that both inset and normal bounds will be calculated here rather than in the caller.
- */
- public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
- Rect animatingBounds) {
- getInsetBounds(insetBounds);
- final Rect defaultBounds = getDefaultBounds(INVALID_SNAP_FRACTION, null);
- normalBounds.set(defaultBounds);
- if (animatingBounds.isEmpty()) {
- animatingBounds.set(defaultBounds);
- }
- if (isValidPictureInPictureAspectRatio(mPipBoundsState.getAspectRatio())) {
- transformBoundsToAspectRatio(normalBounds, mPipBoundsState.getAspectRatio(),
- false /* useCurrentMinEdgeSize */, false /* useCurrentSize */);
- }
- }
-
- /**
- * The {@link PipSnapAlgorithm} is couple on display bounds
- * @return {@link PipSnapAlgorithm}.
- */
- public PipSnapAlgorithm getSnapAlgorithm() {
- return mSnapAlgorithm;
- }
-
- /**
- * Responds to IPinnedStackListener on configuration change.
- */
- public void onConfigurationChanged(Context context) {
- reloadResources(context);
- }
-
- /**
- * See {@link #getDestinationBounds(Rect, Size, boolean)}
- */
- public Rect getDestinationBounds(Rect bounds, Size minimalSize) {
- return getDestinationBounds(bounds, minimalSize, false /* useCurrentMinEdgeSize */);
- }
-
- /**
- * @return {@link Rect} of the destination PiP window bounds.
- */
- public Rect getDestinationBounds(Rect bounds, Size minimalSize, boolean useCurrentMinEdgeSize) {
- boolean isReentryBounds = false;
- final Rect destinationBounds;
- if (bounds == null) {
- // Calculating initial entry bounds
- final PipBoundsState.PipReentryState state = mPipBoundsState.getReentryState();
-
- final Rect defaultBounds;
- if (state != null) {
- // Restore to reentry bounds.
- defaultBounds = getDefaultBounds(state.getSnapFraction(), state.getSize());
- isReentryBounds = true;
- } else {
- // Get actual default bounds.
- defaultBounds = getDefaultBounds(INVALID_SNAP_FRACTION, null /* size */);
- mOverrideMinimalSize = minimalSize;
- }
-
- destinationBounds = new Rect(defaultBounds);
- } else {
- // Just adjusting bounds (e.g. on aspect ratio changed).
- destinationBounds = new Rect(bounds);
- }
- if (isValidPictureInPictureAspectRatio(mPipBoundsState.getAspectRatio())) {
- transformBoundsToAspectRatio(destinationBounds, mPipBoundsState.getAspectRatio(),
- useCurrentMinEdgeSize, isReentryBounds);
- }
- return destinationBounds;
- }
-
- public float getDefaultAspectRatio() {
- return mDefaultAspectRatio;
- }
-
- /**
- * Updatest the display info and display layout on rotation change. This is needed even when we
- * aren't in PIP because the rotation layout is used to calculate the proper insets for the
- * next enter animation into PIP.
- */
- public void onDisplayRotationChangedNotInPip(Context context, int toRotation) {
- // Update the display layout, note that we have to do this on every rotation even if we
- // aren't in PIP since we need to update the display layout to get the right resources
- mPipBoundsState.getDisplayLayout().rotateTo(context.getResources(), toRotation);
-
- // Populate the new {@link #mDisplayInfo}.
- // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
- // therefore, the width/height may require a swap first.
- // Moving forward, we should get the new dimensions after rotation from DisplayLayout.
- mPipBoundsState.setDisplayRotation(toRotation);
- updateDisplayInfoIfNeeded();
- }
-
- /**
- * Updates the display info, calculating and returning the new stack and movement bounds in the
- * new orientation of the device if necessary.
- *
- * @return {@code true} if internal {@link DisplayInfo} is rotated, {@code false} otherwise.
- */
- public boolean onDisplayRotationChanged(Context context, Rect outBounds, Rect oldBounds,
- Rect outInsetBounds,
- int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) {
- // Bail early if the event is not sent to current {@link #mDisplayInfo}
- if ((displayId != mPipBoundsState.getDisplayInfo().displayId)
- || (fromRotation == toRotation)) {
- return false;
- }
-
- // Bail early if the pinned task is staled.
- final RootTaskInfo pinnedTaskInfo;
- try {
- pinnedTaskInfo = ActivityTaskManager.getService()
- .getRootTaskInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
- if (pinnedTaskInfo == null) return false;
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get RootTaskInfo for pinned task", e);
- return false;
- }
-
- // Calculate the snap fraction of the current stack along the old movement bounds
- final Rect postChangeStackBounds = new Rect(oldBounds);
- final float snapFraction = getSnapFraction(postChangeStackBounds);
-
- // Update the display layout
- mPipBoundsState.getDisplayLayout().rotateTo(context.getResources(), toRotation);
-
- // Populate the new {@link #mDisplayInfo}.
- // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
- // therefore, the width/height may require a swap first.
- // Moving forward, we should get the new dimensions after rotation from DisplayLayout.
- mPipBoundsState.getDisplayInfo().rotation = toRotation;
- updateDisplayInfoIfNeeded();
-
- // Calculate the stack bounds in the new orientation based on same fraction along the
- // rotated movement bounds.
- final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
- false /* adjustForIme */);
- mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
- snapFraction);
-
- getInsetBounds(outInsetBounds);
- outBounds.set(postChangeStackBounds);
- t.setBounds(pinnedTaskInfo.token, outBounds);
- return true;
- }
-
- private void updateDisplayInfoIfNeeded() {
- final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
- final boolean updateNeeded;
- if ((displayInfo.rotation == ROTATION_0) || (displayInfo.rotation == ROTATION_180)) {
- updateNeeded = (displayInfo.logicalWidth > displayInfo.logicalHeight);
- } else {
- updateNeeded = (displayInfo.logicalWidth < displayInfo.logicalHeight);
- }
- if (updateNeeded) {
- final int newLogicalHeight = displayInfo.logicalWidth;
- displayInfo.logicalWidth = displayInfo.logicalHeight;
- displayInfo.logicalHeight = newLogicalHeight;
- }
- }
-
- /**
- * @return whether the given {@param aspectRatio} is valid.
- */
- private boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
- return Float.compare(mMinAspectRatio, aspectRatio) <= 0
- && Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
- }
-
- /**
- * Sets the current bound with the currently store aspect ratio.
- * @param stackBounds
- */
- public void transformBoundsToAspectRatio(Rect stackBounds) {
- transformBoundsToAspectRatio(stackBounds, mPipBoundsState.getAspectRatio(),
- true /* useCurrentMinEdgeSize */, true /* useCurrentSize */);
- }
-
- /**
- * Set the current bounds (or the default bounds if there are no current bounds) with the
- * specified aspect ratio.
- */
- private void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
- boolean useCurrentMinEdgeSize, boolean useCurrentSize) {
- // Save the snap fraction and adjust the size based on the new aspect ratio.
- final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
- getMovementBounds(stackBounds));
- final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize;
- final Size size;
- if (useCurrentMinEdgeSize || useCurrentSize) {
- size = mSnapAlgorithm.getSizeForAspectRatio(
- new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize);
- } else {
- final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
- size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize,
- displayInfo.logicalWidth, displayInfo.logicalHeight);
- }
-
- final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
- final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f);
- stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight());
- // apply the override minimal size if applicable, this minimal size is specified by app
- if (mOverrideMinimalSize != null) {
- transformBoundsToMinimalSize(stackBounds, aspectRatio, mOverrideMinimalSize);
- }
- mSnapAlgorithm.applySnapFraction(stackBounds, getMovementBounds(stackBounds), snapFraction);
- }
-
- /**
- * Transforms a given bounds to meet the minimal size constraints.
- * This function assumes the given {@param stackBounds} qualifies {@param aspectRatio}.
- */
- private void transformBoundsToMinimalSize(Rect stackBounds, float aspectRatio,
- Size minimalSize) {
- if (minimalSize == null) return;
- final Size adjustedMinimalSize;
- final float minimalSizeAspectRatio =
- minimalSize.getWidth() / (float) minimalSize.getHeight();
- if (minimalSizeAspectRatio > aspectRatio) {
- // minimal size is wider, fixed the width and increase the height
- adjustedMinimalSize = new Size(
- minimalSize.getWidth(), (int) (minimalSize.getWidth() / aspectRatio));
- } else {
- adjustedMinimalSize = new Size(
- (int) (minimalSize.getHeight() * aspectRatio), minimalSize.getHeight());
- }
- final Rect containerBounds = new Rect(stackBounds);
- Gravity.apply(mDefaultStackGravity,
- adjustedMinimalSize.getWidth(), adjustedMinimalSize.getHeight(),
- containerBounds, stackBounds);
- }
-
- /**
- * @return the default bounds to show the PIP, if a {@param snapFraction} and {@param size} are
- * provided, then it will apply the default bounds to the provided snap fraction and size.
- */
- private Rect getDefaultBounds(float snapFraction, Size size) {
- final Rect defaultBounds = new Rect();
- if (snapFraction != INVALID_SNAP_FRACTION && size != null) {
- defaultBounds.set(0, 0, size.getWidth(), size.getHeight());
- final Rect movementBounds = getMovementBounds(defaultBounds);
- mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
- } else {
- final Rect insetBounds = new Rect();
- getInsetBounds(insetBounds);
- final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
- size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
- mDefaultMinSize, displayInfo.logicalWidth, displayInfo.logicalHeight);
- Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
- 0, Math.max(mIsImeShowing ? mImeHeight : 0,
- mIsShelfShowing ? mShelfHeight : 0),
- defaultBounds);
- }
- return defaultBounds;
- }
-
- /**
- * Populates the bounds on the screen that the PIP can be visible in.
- */
- protected void getInsetBounds(Rect outRect) {
- final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
- Rect insets = mPipBoundsState.getDisplayLayout().stableInsets();
- outRect.set(insets.left + mScreenEdgeInsets.x,
- insets.top + mScreenEdgeInsets.y,
- displayInfo.logicalWidth - insets.right - mScreenEdgeInsets.x,
- displayInfo.logicalHeight - insets.bottom - mScreenEdgeInsets.y);
- }
-
- /**
- * @return the movement bounds for the given {@param stackBounds} and the current state of the
- * controller.
- */
- private Rect getMovementBounds(Rect stackBounds) {
- return getMovementBounds(stackBounds, true /* adjustForIme */);
- }
-
- /**
- * @return the movement bounds for the given {@param stackBounds} and the current state of the
- * controller.
- */
- private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
- final Rect movementBounds = new Rect();
- getInsetBounds(movementBounds);
-
- // Apply the movement bounds adjustments based on the current state.
- mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
- (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
- return movementBounds;
- }
-
- /**
- * @return the default snap fraction to apply instead of the default gravity when calculating
- * the default stack bounds when first entering PiP.
- */
- public float getSnapFraction(Rect stackBounds) {
- return mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds));
- }
-
- /**
- * Applies the given snap fraction to the given stack bounds.
- */
- public void applySnapFraction(Rect stackBounds, float snapFraction) {
- final Rect movementBounds = getMovementBounds(stackBounds);
- mSnapAlgorithm.applySnapFraction(stackBounds, movementBounds, snapFraction);
- }
-
- /**
- * @return the pixels for a given dp value.
- */
- private int dpToPx(float dpValue, DisplayMetrics dm) {
- return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, dm);
- }
-
- /**
- * Dumps internal states.
- */
- public void dump(PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- pw.println(prefix + TAG);
- pw.println(innerPrefix + "mDefaultAspectRatio=" + mDefaultAspectRatio);
- pw.println(innerPrefix + "mMinAspectRatio=" + mMinAspectRatio);
- pw.println(innerPrefix + "mMaxAspectRatio=" + mMaxAspectRatio);
- pw.println(innerPrefix + "mDefaultStackGravity=" + mDefaultStackGravity);
- pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
- pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
- pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
- pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
- pw.println(innerPrefix + "mSnapAlgorithm" + mSnapAlgorithm);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index fc523aef9d16..ce1139b4264d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -16,36 +16,88 @@
package com.android.wm.shell.pip;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
+import android.content.Context;
import android.graphics.Rect;
import android.util.Size;
import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
+import java.util.function.BiConsumer;
/**
* Singleton source of truth for the current state of PIP bounds.
*/
public final class PipBoundsState {
+ public static final int STASH_TYPE_NONE = 0;
+ public static final int STASH_TYPE_LEFT = 1;
+ public static final int STASH_TYPE_RIGHT = 2;
+
+ @IntDef(prefix = { "STASH_TYPE_" }, value = {
+ STASH_TYPE_NONE,
+ STASH_TYPE_LEFT,
+ STASH_TYPE_RIGHT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface StashType {}
+
private static final String TAG = PipBoundsState.class.getSimpleName();
private final @NonNull Rect mBounds = new Rect();
+ private final @NonNull Rect mMovementBounds = new Rect();
+ private final @NonNull Rect mNormalBounds = new Rect();
+ private final @NonNull Rect mExpandedBounds = new Rect();
+ private final @NonNull Rect mNormalMovementBounds = new Rect();
+ private final @NonNull Rect mExpandedMovementBounds = new Rect();
+ private final Context mContext;
private float mAspectRatio;
- private boolean mIsStashed;
+ private int mStashedState = STASH_TYPE_NONE;
+ private int mStashOffset;
private PipReentryState mPipReentryState;
private ComponentName mLastPipComponentName;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
private final DisplayLayout mDisplayLayout = new DisplayLayout();
+ /** The current minimum edge size of PIP. */
+ private int mMinEdgeSize;
+ /** The preferred minimum (and default) size specified by apps. */
+ private Size mOverrideMinSize;
+ private final @NonNull AnimatingBoundsState mAnimatingBoundsState = new AnimatingBoundsState();
+ private boolean mIsImeShowing;
+ private int mImeHeight;
+ private boolean mIsShelfShowing;
+ private int mShelfHeight;
+
+ private Runnable mOnMinimalSizeChangeCallback;
+ private BiConsumer<Boolean, Integer> mOnShelfVisibilityChangeCallback;
+
+ public PipBoundsState(Context context) {
+ mContext = context;
+ reloadResources();
+ }
/**
- * Set the current PIP bounds.
+ * Reloads the resources.
*/
+ public void onConfigurationChanged() {
+ reloadResources();
+ }
+
+ private void reloadResources() {
+ mStashOffset = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.pip_stash_offset);
+ }
+
+ /** Set the current PIP bounds. */
public void setBounds(@NonNull Rect bounds) {
mBounds.set(bounds);
}
@@ -55,18 +107,80 @@ public final class PipBoundsState {
return new Rect(mBounds);
}
+ /** Returns the current movement bounds. */
+ public Rect getMovementBounds() {
+ return mMovementBounds;
+ }
+
+ /** Set the current normal PIP bounds. */
+ public void setNormalBounds(@NonNull Rect bounds) {
+ mNormalBounds.set(bounds);
+ }
+
+ /** Get the current normal PIP bounds. */
+ @NonNull
+ public Rect getNormalBounds() {
+ return mNormalBounds;
+ }
+
+ /** Set the expanded bounds of PIP. */
+ public void setExpandedBounds(@NonNull Rect bounds) {
+ mExpandedBounds.set(bounds);
+ }
+
+ /** Get the PIP expanded bounds. */
+ @NonNull
+ public Rect getExpandedBounds() {
+ return mExpandedBounds;
+ }
+
+ /** Set the normal movement bounds. */
+ public void setNormalMovementBounds(Rect bounds) {
+ mNormalMovementBounds.set(bounds);
+ }
+
+ /** Returns the normal movement bounds. */
+ public Rect getNormalMovementBounds() {
+ return mNormalMovementBounds;
+ }
+
+ /** Set the expanded movement bounds. */
+ public void setExpandedMovementBounds(Rect bounds) {
+ mExpandedMovementBounds.set(bounds);
+ }
+
+ /** Returns the expanded movement bounds. */
+ public Rect getExpandedMovementBounds() {
+ return mExpandedMovementBounds;
+ }
+
+ /**
+ * Dictate where PiP currently should be stashed, if at all.
+ */
+ public void setStashed(@StashType int stashedState) {
+ mStashedState = stashedState;
+ }
+
/**
- * Dictate where PiP currently should be stashed or not.
+ * Return where the PiP is stashed, if at all.
+ * @return {@code STASH_NONE}, {@code STASH_LEFT} or {@code STASH_RIGHT}.
*/
- public void setStashed(boolean isStashed) {
- mIsStashed = isStashed;
+ public @StashType int getStashedState() {
+ return mStashedState;
}
/**
* Whether PiP is stashed or not.
*/
public boolean isStashed() {
- return mIsStashed;
+ return mStashedState != STASH_TYPE_NONE;
+ }
+
+ /**
+ * Returns the offset from the edge of the screen for PiP stash.
+ */
+ public int getStashOffset() {
+ return mStashOffset;
}
public void setAspectRatio(float aspectRatio) {
@@ -151,6 +265,145 @@ public final class PipBoundsState {
mPipReentryState = null;
}
+ /** Set the PIP minimum edge size. */
+ public void setMinEdgeSize(int minEdgeSize) {
+ mMinEdgeSize = minEdgeSize;
+ }
+
+ /** Returns the PIP's current minimum edge size. */
+ public int getMinEdgeSize() {
+ return mMinEdgeSize;
+ }
+
+ /**
+ * Sets the preferred size of PIP as specified by the activity in PIP mode.
+ */
+ public void setOverrideMinSize(Size overrideMinSize) {
+ final boolean changed = !Objects.equals(overrideMinSize, mOverrideMinSize);
+ mOverrideMinSize = overrideMinSize;
+ if (changed && mOnMinimalSizeChangeCallback != null) {
+ mOnMinimalSizeChangeCallback.run();
+ }
+ }
+
+ /** Returns the preferred minimal size specified by the activity in PIP. */
+ public Size getOverrideMinSize() {
+ return mOverrideMinSize;
+ }
+
+ /** Returns the minimum edge size of the override minimum size, or 0 if not set. */
+ public int getOverrideMinEdgeSize() {
+ if (mOverrideMinSize == null) return 0;
+ return Math.min(mOverrideMinSize.getWidth(), mOverrideMinSize.getHeight());
+ }
+
+ public AnimatingBoundsState getAnimatingBoundsState() {
+ return mAnimatingBoundsState;
+ }
+
+ /** Set whether the IME is currently showing and its height. */
+ public void setImeVisibility(boolean imeShowing, int imeHeight) {
+ mIsImeShowing = imeShowing;
+ mImeHeight = imeHeight;
+ }
+
+ /** Returns whether the IME is currently showing. */
+ public boolean isImeShowing() {
+ return mIsImeShowing;
+ }
+
+ /** Returns the IME height. */
+ public int getImeHeight() {
+ return mImeHeight;
+ }
+
+ /** Set whether the shelf is showing and its height. */
+ public void setShelfVisibility(boolean showing, int height) {
+ final boolean shelfShowing = showing && height > 0;
+ if (shelfShowing == mIsShelfShowing && height == mShelfHeight) {
+ return;
+ }
+
+ mIsShelfShowing = showing;
+ mShelfHeight = height;
+ if (mOnShelfVisibilityChangeCallback != null) {
+ mOnShelfVisibilityChangeCallback.accept(mIsShelfShowing, mShelfHeight);
+ }
+ }
+
+ /** Returns whether the shelf is currently showing. */
+ public boolean isShelfShowing() {
+ return mIsShelfShowing;
+ }
+
+ /** Returns the shelf height. */
+ public int getShelfHeight() {
+ return mShelfHeight;
+ }
+
+ /**
+ * Registers a callback when the minimal size of PIP that is set by the app changes.
+ */
+ public void setOnMinimalSizeChangeCallback(Runnable onMinimalSizeChangeCallback) {
+ mOnMinimalSizeChangeCallback = onMinimalSizeChangeCallback;
+ }
+
+ /** Set a callback to be notified when the shelf visibility changes. */
+ public void setOnShelfVisibilityChangeCallback(
+ BiConsumer<Boolean, Integer> onShelfVisibilityChangeCallback) {
+ mOnShelfVisibilityChangeCallback = onShelfVisibilityChangeCallback;
+ }
+
+ /** Source of truth for the current animation bounds of PIP. */
+ public static class AnimatingBoundsState {
+ /** The bounds used when PIP is being dragged or animated. */
+ private final Rect mTemporaryBounds = new Rect();
+ /** The destination bounds to which PIP is animating. */
+ private final Rect mAnimatingToBounds = new Rect();
+
+ /** Whether PIP is being dragged or animated (e.g. resizing, in fling, etc). */
+ public boolean isAnimating() {
+ return !mTemporaryBounds.isEmpty();
+ }
+
+ /** Set the temporary bounds used to represent the drag or animation bounds of PIP. */
+ public void setTemporaryBounds(Rect bounds) {
+ mTemporaryBounds.set(bounds);
+ }
+
+ /** Set the bounds to which PIP is animating. */
+ public void setAnimatingToBounds(Rect bounds) {
+ mAnimatingToBounds.set(bounds);
+ }
+
+ /** Called when all ongoing dragging and animation operations have ended. */
+ public void onAllAnimationsEnded() {
+ mTemporaryBounds.setEmpty();
+ }
+
+ /** Called when an ongoing physics animation has ended. */
+ public void onPhysicsAnimationEnded() {
+ mAnimatingToBounds.setEmpty();
+ }
+
+ /** Returns the temporary animation bounds. */
+ public Rect getTemporaryBounds() {
+ return mTemporaryBounds;
+ }
+
+ /** Returns the destination bounds to which PIP is currently animating. */
+ public Rect getAnimatingToBounds() {
+ return mAnimatingToBounds;
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + AnimatingBoundsState.class.getSimpleName());
+ pw.println(innerPrefix + "mTemporaryBounds=" + mTemporaryBounds);
+ pw.println(innerPrefix + "mAnimatingToBounds=" + mAnimatingToBounds);
+ }
+ }
+
static final class PipReentryState {
private static final String TAG = PipReentryState.class.getSimpleName();
@@ -186,14 +439,28 @@ public final class PipBoundsState {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
pw.println(innerPrefix + "mBounds=" + mBounds);
+ pw.println(innerPrefix + "mNormalBounds=" + mNormalBounds);
+ pw.println(innerPrefix + "mExpandedBounds=" + mExpandedBounds);
+ pw.println(innerPrefix + "mMovementBounds=" + mMovementBounds);
+ pw.println(innerPrefix + "mNormalMovementBounds=" + mNormalMovementBounds);
+ pw.println(innerPrefix + "mExpandedMovementBounds=" + mExpandedMovementBounds);
pw.println(innerPrefix + "mLastPipComponentName=" + mLastPipComponentName);
pw.println(innerPrefix + "mAspectRatio=" + mAspectRatio);
pw.println(innerPrefix + "mDisplayInfo=" + mDisplayInfo);
pw.println(innerPrefix + "mDisplayLayout=" + mDisplayLayout);
+ pw.println(innerPrefix + "mStashedState=" + mStashedState);
+ pw.println(innerPrefix + "mStashOffset=" + mStashOffset);
+ pw.println(innerPrefix + "mMinEdgeSize=" + mMinEdgeSize);
+ pw.println(innerPrefix + "mOverrideMinSize=" + mOverrideMinSize);
+ pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
+ pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
+ pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
+ pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
if (mPipReentryState == null) {
pw.println(innerPrefix + "mPipReentryState=null");
} else {
mPipReentryState.dump(pw, innerPrefix);
}
+ mAnimatingBoundsState.dump(pw, innerPrefix);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java
index 820930c463f2..71060752df09 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSnapAlgorithm.java
@@ -16,6 +16,10 @@
package com.android.wm.shell.pip;
+import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_LEFT;
+import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_NONE;
+import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT;
+
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
@@ -42,9 +46,20 @@ public class PipSnapAlgorithm {
}
/**
+ * Returns a fraction that describes where the PiP bounds is.
+ * See {@link #getSnapFraction(Rect, Rect, int)}.
+ */
+ public float getSnapFraction(Rect stackBounds, Rect movementBounds) {
+ return getSnapFraction(stackBounds, movementBounds, STASH_TYPE_NONE);
+ }
+
+ /**
* @return returns a fraction that describes where along the {@param movementBounds} the
* {@param stackBounds} are. If the {@param stackBounds} are not currently on the
* {@param movementBounds} exactly, then they will be snapped to the movement bounds.
+ * stashType dictates whether the PiP is stashed (off-screen) or not. If
+ * that's the case, we will have to do some math to calculate the snap fraction
+ * correctly.
*
* The fraction is defined in a clockwise fashion against the {@param movementBounds}:
*
@@ -54,9 +69,10 @@ public class PipSnapAlgorithm {
* 3 +---+ 2
* 3 2
*/
- public float getSnapFraction(Rect stackBounds, Rect movementBounds) {
+ public float getSnapFraction(Rect stackBounds, Rect movementBounds,
+ @PipBoundsState.StashType int stashType) {
final Rect tmpBounds = new Rect();
- snapRectToClosestEdge(stackBounds, movementBounds, tmpBounds);
+ snapRectToClosestEdge(stackBounds, movementBounds, tmpBounds, stashType);
final float widthFraction = (float) (tmpBounds.left - movementBounds.left) /
movementBounds.width();
final float heightFraction = (float) (tmpBounds.top - movementBounds.top) /
@@ -104,6 +120,22 @@ public class PipSnapAlgorithm {
}
/**
+ * Same as {@link #applySnapFraction(Rect, Rect, float)}, but take stash state into
+ * consideration.
+ */
+ public void applySnapFraction(Rect stackBounds, Rect movementBounds, float snapFraction,
+ @PipBoundsState.StashType int stashType, int stashOffset, Rect displayBounds) {
+ applySnapFraction(stackBounds, movementBounds, snapFraction);
+
+ if (stashType != STASH_TYPE_NONE) {
+ stackBounds.offsetTo(stashType == STASH_TYPE_LEFT
+ ? stashOffset - stackBounds.width()
+ : displayBounds.right - stashOffset,
+ stackBounds.top);
+ }
+ }
+
+ /**
* Adjusts {@param movementBoundsOut} so that it is the movement bounds for the given
* {@param stackBounds}.
*/
@@ -178,17 +210,24 @@ public class PipSnapAlgorithm {
* Snaps the {@param stackBounds} to the closest edge of the {@param movementBounds} and writes
* the new bounds out to {@param boundsOut}.
*/
- public void snapRectToClosestEdge(Rect stackBounds, Rect movementBounds, Rect boundsOut) {
+ public void snapRectToClosestEdge(Rect stackBounds, Rect movementBounds, Rect boundsOut,
+ @PipBoundsState.StashType int stashType) {
+ int leftEdge = stackBounds.left;
+ if (stashType == STASH_TYPE_LEFT) {
+ leftEdge = movementBounds.left;
+ } else if (stashType == STASH_TYPE_RIGHT) {
+ leftEdge = movementBounds.right;
+ }
final int boundedLeft = Math.max(movementBounds.left, Math.min(movementBounds.right,
- stackBounds.left));
+ leftEdge));
final int boundedTop = Math.max(movementBounds.top, Math.min(movementBounds.bottom,
stackBounds.top));
boundsOut.set(stackBounds);
// Otherwise, just find the closest edge
- final int fromLeft = Math.abs(stackBounds.left - movementBounds.left);
+ final int fromLeft = Math.abs(leftEdge - movementBounds.left);
final int fromTop = Math.abs(stackBounds.top - movementBounds.top);
- final int fromRight = Math.abs(movementBounds.right - stackBounds.left);
+ final int fromRight = Math.abs(movementBounds.right - leftEdge);
final int fromBottom = Math.abs(movementBounds.bottom - stackBounds.top);
final int shortest = Math.min(Math.min(fromLeft, fromRight), Math.min(fromTop, fromBottom));
if (shortest == fromLeft) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 833924c8ee28..7cc2a419354e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -134,7 +134,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private final Handler mMainHandler;
private final Handler mUpdateHandler;
private final PipBoundsState mPipBoundsState;
- private final PipBoundsHandler mPipBoundsHandler;
+ private final PipBoundsAlgorithm mPipBoundsAlgorithm;
+ // TODO(b/172286265): Remove dependency on .pip.PHONE.PipMenuActivityController
private final PipMenuActivityController mMenuActivityController;
private final PipAnimationController mPipAnimationController;
private final PipUiEventLogger mPipUiEventLoggerLogger;
@@ -262,7 +263,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private boolean mShouldIgnoreEnteringPipTransition;
public PipTaskOrganizer(Context context, @NonNull PipBoundsState pipBoundsState,
- @NonNull PipBoundsHandler boundsHandler,
+ @NonNull PipBoundsAlgorithm boundsHandler,
PipMenuActivityController menuActivityController,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional,
@@ -272,7 +273,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mMainHandler = new Handler(Looper.getMainLooper());
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
mPipBoundsState = pipBoundsState;
- mPipBoundsHandler = boundsHandler;
+ mPipBoundsAlgorithm = boundsHandler;
mMenuActivityController = menuActivityController;
mEnterExitAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
@@ -338,10 +339,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
PictureInPictureParams pictureInPictureParams) {
mShouldIgnoreEnteringPipTransition = true;
sendOnPipTransitionStarted(componentName, TRANSITION_DIRECTION_TO_PIP);
- mPipBoundsState.setLastPipComponentName(componentName);
- mPipBoundsState.setAspectRatio(getAspectRatioOrDefault(pictureInPictureParams));
- return mPipBoundsHandler.getDestinationBounds(null /* bounds */,
- getMinimalSize(activityInfo));
+ setBoundsStateForEntry(componentName, pictureInPictureParams, activityInfo);
+ return mPipBoundsAlgorithm.getEntryDestinationBounds();
}
/**
@@ -355,6 +354,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
}
+ private void setBoundsStateForEntry(ComponentName componentName, PictureInPictureParams params,
+ ActivityInfo activityInfo) {
+ mPipBoundsState.setLastPipComponentName(componentName);
+ mPipBoundsState.setAspectRatio(getAspectRatioOrDefault(params));
+ mPipBoundsState.setOverrideMinSize(getMinimalSize(activityInfo));
+ }
+
/**
* Expands PiP to the previous bounds, this is done in two phases using
* {@link WindowContainerTransaction}
@@ -482,7 +488,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mLeash = leash;
mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration));
mPictureInPictureParams = mTaskInfo.pictureInPictureParams;
- mPipBoundsState.setLastPipComponentName(mTaskInfo.topActivity);
+ setBoundsStateForEntry(mTaskInfo.topActivity, mPictureInPictureParams,
+ mTaskInfo.topActivityInfo);
mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER);
@@ -494,6 +501,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mOnDisplayIdChangeCallback.accept(info.displayId);
}
+ if (mMenuActivityController != null) {
+ mMenuActivityController.onTaskAppeared();
+ }
+
if (mShouldIgnoreEnteringPipTransition) {
final Rect destinationBounds = mPipBoundsState.getBounds();
// animation is finished in the Launcher and here we directly apply the final touch.
@@ -517,9 +528,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return;
}
- mPipBoundsState.setAspectRatio(getAspectRatioOrDefault(mPictureInPictureParams));
- final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(null /* bounds */,
- getMinimalSize(mTaskInfo.topActivityInfo));
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
@@ -665,21 +674,24 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mPictureInPictureParams = null;
mState = State.UNDEFINED;
mPipUiEventLoggerLogger.setTaskInfo(null);
+ if (mMenuActivityController != null) {
+ mMenuActivityController.onTaskVanished();
+ }
}
@Override
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken");
mPipBoundsState.setLastPipComponentName(info.topActivity);
+ mPipBoundsState.setOverrideMinSize(getMinimalSize(info.topActivityInfo));
final PictureInPictureParams newParams = info.pictureInPictureParams;
if (newParams == null || !applyPictureInPictureParams(newParams)) {
Log.d(TAG, "Ignored onTaskInfoChanged with PiP param: " + newParams);
return;
}
- // Aspect ratio changed, re-calculate destination bounds.
- final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
- mPipBoundsState.getBounds(), getMinimalSize(info.topActivityInfo),
- true /* userCurrentMinEdgeSize */);
+ // Aspect ratio changed, re-calculate bounds if valid.
+ final Rect destinationBounds = mPipBoundsAlgorithm.getAdjustedDestinationBounds(
+ mPipBoundsState.getBounds(), mPipBoundsState.getAspectRatio());
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
scheduleAnimateResizePip(destinationBounds, mEnterExitAnimationDuration,
null /* updateBoundsCallback */);
@@ -693,8 +705,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@Override
public void onFixedRotationFinished(int displayId) {
if (mShouldDeferEnteringPip && mState.isInPip()) {
- final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
- null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo));
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
// schedule a regular animation to ensure all the callbacks are still being sent
enterPipWithAlphaAnimation(destinationBounds, 0 /* durationMs */);
}
@@ -769,8 +780,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return;
}
- final Rect newDestinationBounds = mPipBoundsHandler.getDestinationBounds(null /* bounds */,
- getMinimalSize(mTaskInfo.topActivityInfo));
+ final Rect newDestinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
if (newDestinationBounds.equals(currentDestinationBounds)) return;
if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) {
animator.updateEndValue(newDestinationBounds);
@@ -946,10 +956,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mSurfaceTransactionHelper
.crop(tx, mLeash, destinationBounds)
.round(tx, mLeash, mState.isInPip());
- if (mMenuActivityController.isMenuVisible()) {
- runOnMainHandler(() -> {
- mMenuActivityController.resizePipMenu(mLeash, tx, destinationBounds);
- });
+ if (mMenuActivityController != null && mMenuActivityController.isMenuVisible()) {
+ runOnMainHandler(() ->
+ mMenuActivityController.resizePipMenu(mLeash, tx, destinationBounds));
} else {
tx.apply();
}
@@ -973,10 +982,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper.scale(tx, mLeash, startBounds, destinationBounds);
- if (mMenuActivityController.isMenuVisible()) {
- runOnMainHandler(() -> {
- mMenuActivityController.movePipMenu(mLeash, tx, destinationBounds);
- });
+ if (mMenuActivityController != null && mMenuActivityController.isMenuVisible()) {
+ runOnMainHandler(() ->
+ mMenuActivityController.movePipMenu(mLeash, tx, destinationBounds));
} else {
tx.apply();
}
@@ -993,7 +1001,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
removePipImmediately();
return;
- } else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
+ } else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA
+ && mMenuActivityController != null) {
// TODO: Synchronize this correctly in #applyEnterPipSyncTransaction
finishResizeForMenu(destinationBounds);
return;
@@ -1097,7 +1106,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) {
return params == null || !params.hasSetAspectRatio()
- ? mPipBoundsHandler.getDefaultAspectRatio()
+ ? mPipBoundsAlgorithm.getDefaultAspectRatio()
: params.getAspectRatio();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 37a5919b1c9e..598b5d9b5d30 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -16,12 +16,17 @@
package com.android.wm.shell.pip.phone;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
import android.app.PictureInPictureParams;
import android.app.RemoteAction;
import android.content.ComponentName;
@@ -32,9 +37,12 @@ import android.graphics.Rect;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.IPinnedStackController;
+import android.view.WindowManagerGlobal;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -44,13 +52,18 @@ import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.PipInputConsumer;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
+import com.android.wm.shell.pip.PipUtils;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -63,22 +76,21 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
private Context mContext;
private ShellExecutor mMainExecutor;
-
- private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
- private final Rect mTmpInsetBounds = new Rect();
- private final Rect mTmpNormalBounds = new Rect();
- protected final Rect mReentryBounds = new Rect();
-
private DisplayController mDisplayController;
+ private PipInputConsumer mPipInputConsumer;
+ private WindowManagerShellWrapper mWindowManagerShellWrapper;
private PipAppOpsListener mAppOpsListener;
- private PipBoundsHandler mPipBoundsHandler;
- private @NonNull PipBoundsState mPipBoundsState;
private PipMediaController mMediaController;
+ private PipBoundsAlgorithm mPipBoundsAlgorithm;
+ private PipBoundsState mPipBoundsState;
private PipTouchHandler mTouchHandler;
- private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
- private WindowManagerShellWrapper mWindowManagerShellWrapper;
+
+ private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
+ private final Rect mTmpInsetBounds = new Rect();
+ protected final Rect mReentryBounds = new Rect();
private boolean mIsInFixedRotation;
+ private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
protected PipMenuActivityController mMenuController;
protected PipTaskOrganizer mPipTaskOrganizer;
@@ -93,20 +105,20 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
if (!mPipTaskOrganizer.isInPip() || mPipTaskOrganizer.isDeferringEnterPipAnimation()) {
// Skip if we aren't in PIP or haven't actually entered PIP yet. We still need to update
// the display layout in the bounds handler in this case.
- mPipBoundsHandler.onDisplayRotationChangedNotInPip(mContext, toRotation);
+ onDisplayRotationChangedNotInPip(mContext, toRotation);
return;
}
// If there is an animation running (ie. from a shelf offset), then ensure that we calculate
// the bounds for the next orientation using the destination bounds of the animation
// TODO: Technically this should account for movement animation bounds as well
Rect currentBounds = mPipTaskOrganizer.getCurrentOrAnimatingBounds();
- final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mContext,
- mTmpNormalBounds, currentBounds, mTmpInsetBounds, displayId, fromRotation,
- toRotation, t);
+ final boolean changed = onDisplayRotationChanged(mContext,
+ mPipBoundsState.getNormalBounds(), currentBounds, mTmpInsetBounds, displayId,
+ fromRotation, toRotation, t);
if (changed) {
// If the pip was in the offset zone earlier, adjust the new bounds to the bottom of the
// movement bounds
- mTouchHandler.adjustBoundsForRotation(mTmpNormalBounds,
+ mTouchHandler.adjustBoundsForRotation(mPipBoundsState.getNormalBounds(),
mPipBoundsState.getBounds(), mTmpInsetBounds);
// The bounds are being applied to a specific snap fraction, so reset any known offsets
@@ -115,13 +127,13 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
// not during the fixed rotation. In fixed rotation case, app is about to enter PiP
// and we need the offsets preserved to calculate the destination bounds.
if (!mIsInFixedRotation) {
- mPipBoundsHandler.setShelfHeight(false, 0);
- mPipBoundsHandler.onImeVisibilityChanged(false, 0);
+ mPipBoundsState.setShelfVisibility(false /* showing */, 0 /* height */);
+ mPipBoundsState.setImeVisibility(false /* showing */, 0 /* height */);
mTouchHandler.onShelfVisibilityChanged(false, 0);
mTouchHandler.onImeVisibilityChanged(false, 0);
}
- updateMovementBounds(mTmpNormalBounds, true /* fromRotation */,
+ updateMovementBounds(mPipBoundsState.getNormalBounds(), true /* fromRotation */,
false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t);
}
};
@@ -158,7 +170,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mMainExecutor.execute(() -> {
- mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight);
+ mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
mTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight);
});
}
@@ -194,8 +206,9 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
@Override
public void onConfigurationChanged() {
mMainExecutor.execute(() -> {
- mPipBoundsHandler.onConfigurationChanged(mContext);
+ mPipBoundsAlgorithm.onConfigurationChanged(mContext);
mTouchHandler.onConfigurationChanged();
+ mPipBoundsState.onConfigurationChanged();
});
}
@@ -213,13 +226,14 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
protected PipController(Context context,
DisplayController displayController,
PipAppOpsListener pipAppOpsListener,
- PipBoundsHandler pipBoundsHandler,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
@NonNull PipBoundsState pipBoundsState,
PipMediaController pipMediaController,
PipMenuActivityController pipMenuActivityController,
PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler,
WindowManagerShellWrapper windowManagerShellWrapper,
+ TaskStackListenerImpl taskStackListener,
ShellExecutor mainExecutor
) {
// Ensure that we are the primary user's SystemUI.
@@ -231,23 +245,43 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
mContext = context;
mWindowManagerShellWrapper = windowManagerShellWrapper;
mDisplayController = displayController;
- mPipBoundsHandler = pipBoundsHandler;
+ mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipBoundsState = pipBoundsState;
mPipTaskOrganizer = pipTaskOrganizer;
mMainExecutor = mainExecutor;
+ mMediaController = pipMediaController;
+ mMenuController = pipMenuActivityController;
+ mTouchHandler = pipTouchHandler;
+ mAppOpsListener = pipAppOpsListener;
+ mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(),
+ INPUT_CONSUMER_PIP);
mPipTaskOrganizer.registerPipTransitionCallback(this);
mPipTaskOrganizer.registerOnDisplayIdChangeCallback((int displayId) -> {
final DisplayInfo newDisplayInfo = new DisplayInfo();
displayController.getDisplay(displayId).getDisplayInfo(newDisplayInfo);
mPipBoundsState.setDisplayInfo(newDisplayInfo);
updateMovementBounds(null /* toBounds */, false /* fromRotation */,
- false /* fromImeAdjustment */, false /* fromShelfAdustment */,
+ false /* fromImeAdjustment */, false /* fromShelfAdjustment */,
null /* wct */);
});
- mMediaController = pipMediaController;
- mMenuController = pipMenuActivityController;
- mTouchHandler = pipTouchHandler;
- mAppOpsListener = pipAppOpsListener;
+ mPipBoundsState.setOnMinimalSizeChangeCallback(
+ () -> {
+ // The minimal size drives the normal bounds, so they need to be recalculated.
+ updateMovementBounds(null /* toBounds */, false /* fromRotation */,
+ false /* fromImeAdjustment */, false /* fromShelfAdjustment */,
+ null /* wct */);
+ });
+ mPipBoundsState.setOnShelfVisibilityChangeCallback((isShowing, height) -> {
+ mTouchHandler.onShelfVisibilityChanged(isShowing, height);
+ updateMovementBounds(mPipBoundsState.getBounds(),
+ false /* fromRotation */, false /* fromImeAdjustment */,
+ true /* fromShelfAdjustment */, null /* windowContainerTransaction */);
+ });
+ if (mTouchHandler != null) {
+ // Register the listener for input consumer touch events. Only for Phone
+ mPipInputConsumer.setInputListener(mTouchHandler::handleTouchEvent);
+ mPipInputConsumer.setRegistrationListener(mTouchHandler::onRegistrationChanged);
+ }
displayController.addDisplayChangingController(mRotationController);
displayController.addDisplayWindowListener(mFixedRotationListener);
@@ -262,45 +296,66 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
} catch (RemoteException e) {
Slog.e(TAG, "Failed to register pinned stack listener", e);
}
- }
- @Override
- public void onDensityOrFontScaleChanged() {
- mMainExecutor.execute(() -> {
- mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext);
- });
- }
+ try {
+ ActivityTaskManager.RootTaskInfo taskInfo = ActivityTaskManager.getService()
+ .getRootTaskInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+ if (taskInfo != null) {
+ // If SystemUI restart, and it already existed a pinned stack,
+ // register the pip input consumer to ensure touch can send to it.
+ mPipInputConsumer.registerInputConsumer(true /* withSfVsync */);
+ }
+ } catch (RemoteException | UnsupportedOperationException e) {
+ Log.e(TAG, "Failed to register pinned stack listener", e);
+ e.printStackTrace();
+ }
- @Override
- public void onActivityPinned(String packageName) {
- mMainExecutor.execute(() -> {
- mTouchHandler.onActivityPinned();
- mMediaController.onActivityPinned();
- mMenuController.onActivityPinned();
- mAppOpsListener.onActivityPinned(packageName);
- });
+ // Handle for system task stack changes.
+ taskStackListener.addListener(
+ new TaskStackListenerCallback() {
+ @Override
+ public void onActivityPinned(String packageName, int userId, int taskId,
+ int stackId) {
+ mMainExecutor.execute(() -> {
+ mTouchHandler.onActivityPinned();
+ mMediaController.onActivityPinned();
+ mAppOpsListener.onActivityPinned(packageName);
+ });
+ mPipInputConsumer.registerInputConsumer(true /* withSfVsync */);
+ }
+
+ @Override
+ public void onActivityUnpinned() {
+ final Pair<ComponentName, Integer> topPipActivityInfo =
+ PipUtils.getTopPipActivity(mContext);
+ final ComponentName topActivity = topPipActivityInfo.first;
+ mMainExecutor.execute(() -> {
+ mTouchHandler.onActivityUnpinned(topActivity);
+ mAppOpsListener.onActivityUnpinned();
+ });
+ mPipInputConsumer.unregisterInputConsumer();
+ }
+
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ if (task.getWindowingMode() != WINDOWING_MODE_PINNED) {
+ return;
+ }
+ mTouchHandler.getMotionHelper().expandLeavePip(
+ clearedTask /* skipAnimation */);
+ }
+ });
}
@Override
- public void onActivityUnpinned(ComponentName topActivity) {
+ public void onDensityOrFontScaleChanged() {
mMainExecutor.execute(() -> {
- mMenuController.onActivityUnpinned();
- mTouchHandler.onActivityUnpinned(topActivity);
- mAppOpsListener.onActivityUnpinned();
+ mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext);
});
}
@Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean clearedTask) {
- if (task.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_PINNED) {
- return;
- }
- mTouchHandler.getMotionHelper().expandLeavePip(clearedTask /* skipAnimation */);
- }
-
- @Override
public void onOverlayChanged() {
mMainExecutor.execute(() -> {
mPipBoundsState.setDisplayLayout(new DisplayLayout(mContext, mContext.getDisplay()));
@@ -366,13 +421,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
private void setShelfHeightLocked(boolean visible, int height) {
final int shelfHeight = visible ? height : 0;
- final boolean changed = mPipBoundsHandler.setShelfHeight(visible, shelfHeight);
- if (changed) {
- mTouchHandler.onShelfVisibilityChanged(visible, shelfHeight);
- updateMovementBounds(mPipBoundsState.getBounds(),
- false /* fromRotation */, false /* fromImeAdjustment */,
- true /* fromShelfAdjustment */, null /* windowContainerTransaction */);
- }
+ mPipBoundsState.setShelfVisibility(visible, shelfHeight);
}
@Override
@@ -390,7 +439,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
PictureInPictureParams pictureInPictureParams,
int launcherRotation, int shelfHeight) {
setShelfHeightLocked(shelfHeight > 0 /* visible */, shelfHeight);
- mPipBoundsHandler.onDisplayRotationChangedNotInPip(mContext, launcherRotation);
+ onDisplayRotationChangedNotInPip(mContext, launcherRotation);
return mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
pictureInPictureParams);
}
@@ -405,7 +454,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
if (isOutPipDirection(direction)) {
// Exiting PIP, save the reentry bounds to restore to when re-entering.
updateReentryBounds(pipBounds);
- final float snapFraction = mPipBoundsHandler.getSnapFraction(mReentryBounds);
+ final float snapFraction = mPipBoundsAlgorithm.getSnapFraction(mReentryBounds);
mPipBoundsState.saveReentryState(mReentryBounds, snapFraction);
}
// Disable touches while the animation is running
@@ -420,11 +469,21 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
*/
public void updateReentryBounds(Rect bounds) {
final Rect reentryBounds = mTouchHandler.getUserResizeBounds();
- float snapFraction = mPipBoundsHandler.getSnapFraction(bounds);
- mPipBoundsHandler.applySnapFraction(reentryBounds, snapFraction);
+ float snapFraction = mPipBoundsAlgorithm.getSnapFraction(bounds);
+ mPipBoundsAlgorithm.applySnapFraction(reentryBounds, snapFraction);
mReentryBounds.set(reentryBounds);
}
+ /**
+ * Set a listener to watch out for PiP bounds. This is mostly used by SystemUI's
+ * Back-gesture handler, to avoid conflicting with PiP when it's stashed.
+ */
+ @Override
+ public void setPipExclusionBoundsChangeListener(
+ Consumer<Rect> pipExclusionBoundsChangeListener) {
+ mTouchHandler.setPipExclusionBoundsChangeListener(pipExclusionBoundsChangeListener);
+ }
+
@Override
public void onPipTransitionFinished(ComponentName activity, int direction) {
onPipTransitionFinishedOrCanceled(direction);
@@ -449,25 +508,121 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
// passing to mTouchHandler/mPipTaskOrganizer
final Rect outBounds = new Rect(toBounds);
mTmpDisplayInfo.copyFrom(mPipBoundsState.getDisplayInfo());
- mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
- outBounds);
+
+ mPipBoundsAlgorithm.getInsetBounds(mTmpInsetBounds);
+ mPipBoundsState.setNormalBounds(mPipBoundsAlgorithm.getNormalBounds());
+ if (outBounds.isEmpty()) {
+ outBounds.set(mPipBoundsAlgorithm.getDefaultBounds());
+ }
+
// mTouchHandler would rely on the bounds populated from mPipTaskOrganizer
mPipTaskOrganizer.onMovementBoundsChanged(outBounds, fromRotation, fromImeAdjustment,
fromShelfAdjustment, wct);
- mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
+ mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mPipBoundsState.getNormalBounds(),
outBounds, fromImeAdjustment, fromShelfAdjustment,
mTmpDisplayInfo.rotation);
}
+ /**
+ * Updates the display info and display layout on rotation change. This is needed even when we
+ * aren't in PIP because the rotation layout is used to calculate the proper insets for the
+ * next enter animation into PIP.
+ */
+ private void onDisplayRotationChangedNotInPip(Context context, int toRotation) {
+ // Update the display layout, note that we have to do this on every rotation even if we
+ // aren't in PIP since we need to update the display layout to get the right resources
+ mPipBoundsState.getDisplayLayout().rotateTo(context.getResources(), toRotation);
+
+ // Populate the new {@link #mDisplayInfo}.
+ // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
+ // therefore, the width/height may require a swap first.
+ // Moving forward, we should get the new dimensions after rotation from DisplayLayout.
+ mPipBoundsState.setDisplayRotation(toRotation);
+ updateDisplayInfoIfNeeded();
+ }
+
+ /**
+ * Updates the display info, calculating and returning the new stack and movement bounds in the
+ * new orientation of the device if necessary.
+ *
+ * @return {@code true} if internal {@link DisplayInfo} is rotated, {@code false} otherwise.
+ */
+ public boolean onDisplayRotationChanged(Context context, Rect outBounds, Rect oldBounds,
+ Rect outInsetBounds,
+ int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) {
+ // Bail early if the event is not sent to current {@link #mDisplayInfo}
+ if ((displayId != mPipBoundsState.getDisplayInfo().displayId)
+ || (fromRotation == toRotation)) {
+ return false;
+ }
+
+ // Bail early if the pinned task is staled.
+ final ActivityTaskManager.RootTaskInfo pinnedTaskInfo;
+ try {
+ pinnedTaskInfo = ActivityTaskManager.getService()
+ .getRootTaskInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+ if (pinnedTaskInfo == null) return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get RootTaskInfo for pinned task", e);
+ return false;
+ }
+ final PipSnapAlgorithm pipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
+
+ // Calculate the snap fraction of the current stack along the old movement bounds
+ final Rect postChangeStackBounds = new Rect(oldBounds);
+ final float snapFraction = pipSnapAlgorithm.getSnapFraction(postChangeStackBounds,
+ mPipBoundsAlgorithm.getMovementBounds(postChangeStackBounds),
+ mPipBoundsState.getStashedState());
+
+ // Update the display layout
+ mPipBoundsState.getDisplayLayout().rotateTo(context.getResources(), toRotation);
+
+ // Populate the new {@link #mDisplayInfo}.
+ // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
+ // therefore, the width/height may require a swap first.
+ // Moving forward, we should get the new dimensions after rotation from DisplayLayout.
+ mPipBoundsState.getDisplayInfo().rotation = toRotation;
+ updateDisplayInfoIfNeeded();
+
+ // Calculate the stack bounds in the new orientation based on same fraction along the
+ // rotated movement bounds.
+ final Rect postChangeMovementBounds = mPipBoundsAlgorithm.getMovementBounds(
+ postChangeStackBounds, false /* adjustForIme */);
+ pipSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
+ snapFraction, mPipBoundsState.getStashedState(), mPipBoundsState.getStashOffset(),
+ mPipBoundsState.getDisplayBounds());
+
+ mPipBoundsAlgorithm.getInsetBounds(outInsetBounds);
+ outBounds.set(postChangeStackBounds);
+ t.setBounds(pinnedTaskInfo.token, outBounds);
+ return true;
+ }
+
+ private void updateDisplayInfoIfNeeded() {
+ final DisplayInfo displayInfo = mPipBoundsState.getDisplayInfo();
+ final boolean updateNeeded;
+ if ((displayInfo.rotation == ROTATION_0) || (displayInfo.rotation == ROTATION_180)) {
+ updateNeeded = (displayInfo.logicalWidth > displayInfo.logicalHeight);
+ } else {
+ updateNeeded = (displayInfo.logicalWidth < displayInfo.logicalHeight);
+ }
+ if (updateNeeded) {
+ final int newLogicalHeight = displayInfo.logicalWidth;
+ displayInfo.logicalWidth = displayInfo.logicalHeight;
+ displayInfo.logicalHeight = newLogicalHeight;
+ }
+ }
+
@Override
public void dump(PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG);
mMenuController.dump(pw, innerPrefix);
mTouchHandler.dump(pw, innerPrefix);
- mPipBoundsHandler.dump(pw, innerPrefix);
+ mPipBoundsAlgorithm.dump(pw, innerPrefix);
mPipTaskOrganizer.dump(pw, innerPrefix);
mPipBoundsState.dump(pw, innerPrefix);
+ mPipInputConsumer.dump(pw, innerPrefix);
}
/**
@@ -475,19 +630,18 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
*/
@Nullable
public static PipController create(Context context, DisplayController displayController,
- PipAppOpsListener pipAppOpsListener, PipBoundsHandler pipBoundsHandler,
+ PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
- PipMenuActivityController pipMenuActivityController,
- PipTaskOrganizer pipTaskOrganizer, PipTouchHandler pipTouchHandler,
- WindowManagerShellWrapper windowManagerShellWrapper,
- ShellExecutor mainExecutor) {
+ PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
+ PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
+ TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
Slog.w(TAG, "Device doesn't support Pip feature");
return null;
}
- return new PipController(context, displayController, pipAppOpsListener, pipBoundsHandler,
- pipBoundsState, pipMediaController, pipMenuActivityController,
- pipTaskOrganizer, pipTouchHandler, windowManagerShellWrapper, mainExecutor);
+ return new PipController(context, displayController, pipAppOpsListener, pipBoundsAlgorithm,
+ pipBoundsState, pipMediaController, pipMenuActivityController, pipTaskOrganizer,
+ pipTouchHandler, windowManagerShellWrapper, taskStackListener, mainExecutor);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
index 24144b21e6d0..1d5430008501 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
@@ -22,6 +22,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
@@ -134,15 +135,22 @@ public class PipMenuActivityController {
return mPipMenuView != null && mMenuState != MENU_STATE_NONE;
}
- public void onActivityPinned() {
+ /**
+ * Attach the menu when the PiP task first appears.
+ */
+ public void onTaskAppeared() {
attachPipMenuView();
}
- public void onActivityUnpinned() {
+ /**
+ * Detach the menu when the PiP task is gone.
+ */
+ public void onTaskVanished() {
hideMenu();
detachPipMenuView();
}
+
public void onPinnedStackAnimationEnded() {
if (isMenuVisible()) {
mPipMenuView.onPipAnimationEnded();
@@ -150,10 +158,11 @@ public class PipMenuActivityController {
}
private void attachPipMenuView() {
- if (mPipMenuView == null) {
- mPipMenuView = new PipMenuView(mContext, this);
+ // In case detach was not called (e.g. PIP unexpectedly closed)
+ if (mPipMenuView != null) {
+ detachPipMenuView();
}
-
+ mPipMenuView = new PipMenuView(mContext, this);
mSystemWindows.addView(mPipMenuView, getPipMenuLayoutParams(0, 0), 0, SHELL_ROOT_LAYER_PIP);
}
@@ -419,7 +428,7 @@ public class PipMenuActivityController {
TYPE_APPLICATION_OVERLAY,
FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY | FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT);
-
+ lp.privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY;
lp.setTitle(MENU_WINDOW_TITLE);
return lp;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
index 985cd0f1fa19..6d12752d9218 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuIconsAlgorithm.java
@@ -60,6 +60,7 @@ public class PipMenuIconsAlgorithm {
if (mViewRoot == null || mTopEndContainer == null || mDragHandle == null
|| mSettingsButton == null || mDismissButton == null) {
Log.e(TAG, "One if the required views is null.");
+ return;
}
//We only need to calculate the layout once since it does not change.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index 9247c683a082..e4e1211f9fa9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -16,6 +16,9 @@
package com.android.wm.shell.pip.phone;
+import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_LEFT;
+import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
@@ -33,7 +36,6 @@ import androidx.dynamicanimation.animation.AnimationHandler;
import androidx.dynamicanimation.animation.AnimationHandler.FrameCallbackScheduler;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.wm.shell.R;
import com.android.wm.shell.animation.FloatProperties;
import com.android.wm.shell.animation.PhysicsAnimator;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -42,7 +44,6 @@ import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
-import java.io.PrintWriter;
import java.util.function.Consumer;
import kotlin.Unit;
@@ -74,28 +75,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
- /** The bounds within which PIP's top-left coordinate is allowed to move. */
- private final Rect mMovementBounds = new Rect();
-
/** The region that all of PIP must stay within. */
private final Rect mFloatingAllowedArea = new Rect();
- /**
- * Temporary bounds used when PIP is being dragged or animated. These bounds are applied to PIP
- * using {@link PipTaskOrganizer#scheduleUserResizePip}, so that we can animate shrinking into
- * and expanding out of the magnetic dismiss target.
- *
- * Once PIP is done being dragged or animated, we set {@link #mBounds} equal to these temporary
- * bounds, and call {@link PipTaskOrganizer#scheduleFinishResizePip} to 'officially' move PIP to
- * its new bounds.
- */
- private final Rect mTemporaryBounds = new Rect();
-
- /** The destination bounds to which PIP is animating. */
- private final Rect mAnimatingToBounds = new Rect();
-
- private int mStashOffset = 0;
-
/** Coordinator instance for resolving conflicts with other floating content. */
private FloatingContentCoordinator mFloatingContentCoordinator;
@@ -108,15 +90,15 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
});
/**
- * PhysicsAnimator instance for animating {@link #mTemporaryBounds} using physics animations.
+ * PhysicsAnimator instance for animating {@link PipBoundsState#getAnimatingBoundsState()}
+ * using physics animations.
*/
- private PhysicsAnimator<Rect> mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
- mTemporaryBounds);
+ private final PhysicsAnimator<Rect> mTemporaryBoundsPhysicsAnimator;
private MagnetizedObject<Rect> mMagnetizedPip;
/**
- * Update listener that resizes the PIP to {@link #mTemporaryBounds}.
+ * Update listener that resizes the PIP to {@link PipBoundsState#getAnimatingBoundsState()}.
*/
private final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener;
@@ -189,27 +171,24 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
mSnapAlgorithm = snapAlgorithm;
mFloatingContentCoordinator = floatingContentCoordinator;
mPipTaskOrganizer.registerPipTransitionCallback(mPipTransitionCallback);
+ mTemporaryBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
+ mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds());
mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler(
mSfAnimationHandlerThreadLocal.get());
- reloadResources();
mResizePipUpdateListener = (target, values) -> {
- if (!mTemporaryBounds.isEmpty()) {
- mPipTaskOrganizer.scheduleUserResizePip(
- getBounds(), mTemporaryBounds, null);
+ if (mPipBoundsState.getAnimatingBoundsState().isAnimating()) {
+ mPipTaskOrganizer.scheduleUserResizePip(getBounds(),
+ mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds(), null);
}
};
}
- void reloadResources() {
- mStashOffset = mContext.getResources()
- .getDimensionPixelSize(R.dimen.pip_stash_offset);
- }
-
@NonNull
@Override
public Rect getFloatingBoundsOnScreen() {
- return !mAnimatingToBounds.isEmpty() ? mAnimatingToBounds : getBounds();
+ return !mPipBoundsState.getAnimatingBoundsState().getAnimatingToBounds().isEmpty()
+ ? mPipBoundsState.getAnimatingBoundsState().getAnimatingToBounds() : getBounds();
}
@NonNull
@@ -227,18 +206,14 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
* Synchronizes the current bounds with the pinned stack, cancelling any ongoing animations.
*/
void synchronizePinnedStackBounds() {
- cancelAnimations();
- mTemporaryBounds.setEmpty();
+ cancelPhysicsAnimation();
+ mPipBoundsState.getAnimatingBoundsState().onAllAnimationsEnded();
if (mPipTaskOrganizer.isInPip()) {
mFloatingContentCoordinator.onContentMoved(this);
}
}
- boolean isAnimating() {
- return mTemporaryBoundsPhysicsAnimator.isRunning();
- }
-
/**
* Tries to move the pinned stack to the given {@param bounds}.
*/
@@ -261,14 +236,14 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
if (!mSpringingToTouch) {
// If we are moving PIP directly to the touch event locations, cancel any animations and
// move PIP to the given bounds.
- cancelAnimations();
+ cancelPhysicsAnimation();
if (!isDragging) {
resizePipUnchecked(toBounds);
mPipBoundsState.setBounds(toBounds);
} else {
- mTemporaryBounds.set(toBounds);
- mPipTaskOrganizer.scheduleUserResizePip(getBounds(), mTemporaryBounds,
+ mPipBoundsState.getAnimatingBoundsState().setTemporaryBounds(toBounds);
+ mPipTaskOrganizer.scheduleUserResizePip(getBounds(), toBounds,
(Rect newBounds) -> {
mMainHandler.post(() -> {
mMenuController.updateMenuLayout(newBounds);
@@ -284,8 +259,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
.spring(FloatProperties.RECT_X, toBounds.left, mSpringConfig)
.spring(FloatProperties.RECT_Y, toBounds.top, mSpringConfig);
- startBoundsAnimator(toBounds.left /* toX */, toBounds.top /* toY */,
- false /* dismiss */);
+ startBoundsAnimator(toBounds.left /* toX */, toBounds.top /* toY */);
}
}
@@ -303,9 +277,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
final float destinationY = targetCenter.y - (desiredHeight / 2f);
// If we're already in the dismiss target area, then there won't be a move to set the
- // temporary bounds, so just initialize it to the current bounds
- if (mTemporaryBounds.isEmpty()) {
- mTemporaryBounds.set(getBounds());
+ // temporary bounds, so just initialize it to the current bounds.
+ if (!mPipBoundsState.getAnimatingBoundsState().isAnimating()) {
+ mPipBoundsState.getAnimatingBoundsState().setTemporaryBounds(getBounds());
}
mTemporaryBoundsPhysicsAnimator
.spring(FloatProperties.RECT_X, destinationX, velX, mSpringConfig)
@@ -314,7 +288,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
.spring(FloatProperties.RECT_HEIGHT, desiredHeight, mSpringConfig)
.withEndActions(after);
- startBoundsAnimator(destinationX, destinationY, false);
+ startBoundsAnimator(destinationX, destinationY);
}
/** Set whether we're springing-to-touch to catch up after being stuck in the dismiss target. */
@@ -339,7 +313,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
Log.d(TAG, "exitPip: skipAnimation=" + skipAnimation
+ " callers=\n" + Debug.getCallers(5, " "));
}
- cancelAnimations();
+ cancelPhysicsAnimation();
mMenuController.hideMenuWithoutResize();
mPipTaskOrganizer.getUpdateHandler().post(() -> {
mPipTaskOrganizer.exitPip(skipAnimation
@@ -356,19 +330,18 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
if (DEBUG) {
Log.d(TAG, "removePip: callers=\n" + Debug.getCallers(5, " "));
}
- cancelAnimations();
+ cancelPhysicsAnimation();
mMenuController.hideMenuWithoutResize();
mPipTaskOrganizer.removePip();
}
/** Sets the movement bounds to use to constrain PIP position animations. */
- void setCurrentMovementBounds(Rect movementBounds) {
- mMovementBounds.set(movementBounds);
+ void onMovementBoundsChanged() {
rebuildFlingConfigs();
// The movement bounds represent the area within which we can move PIP's top-left position.
// The allowed area for all of PIP is those bounds plus PIP's width and height.
- mFloatingAllowedArea.set(mMovementBounds);
+ mFloatingAllowedArea.set(mPipBoundsState.getMovementBounds());
mFloatingAllowedArea.right += getBounds().width();
mFloatingAllowedArea.bottom += getBounds().height();
}
@@ -383,31 +356,26 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
}
/**
- * Returns the PIP bounds if we're not animating, or the current, temporary animating bounds
- * otherwise.
- */
- Rect getPossiblyAnimatingBounds() {
- return mTemporaryBounds.isEmpty() ? getBounds() : mTemporaryBounds;
- }
-
- /**
* Flings the PiP to the closest snap target.
*/
void flingToSnapTarget(
- float velocityX, float velocityY, @Nullable Runnable endAction) {
- movetoTarget(velocityX, velocityY, endAction, false /* isStash */);
+ float velocityX, float velocityY, @Nullable Runnable postBoundsUpdateCallback) {
+ movetoTarget(velocityX, velocityY, postBoundsUpdateCallback, false /* isStash */);
}
/**
- * Stash PiP to the closest edge.
+ * Stash PiP to the closest edge. We set velocityY to 0 to limit pure horizontal motion.
*/
- void stashToEdge(
- float velocityX, float velocityY, @Nullable Runnable endAction) {
- movetoTarget(velocityX, velocityY, endAction, true /* isStash */);
+ void stashToEdge(float velocityX, @Nullable Runnable postBoundsUpdateCallback) {
+ mPipBoundsState.setStashed(velocityX < 0 ? STASH_TYPE_LEFT : STASH_TYPE_RIGHT);
+ movetoTarget(velocityX, 0 /* velocityY */, postBoundsUpdateCallback, true /* isStash */);
}
private void movetoTarget(
- float velocityX, float velocityY, @Nullable Runnable endAction, boolean isStash) {
+ float velocityX,
+ float velocityY,
+ @Nullable Runnable postBoundsUpdateCallback,
+ boolean isStash) {
// If we're flinging to a snap target now, we're not springing to catch up to the touch
// location now.
mSpringingToTouch = false;
@@ -419,21 +387,23 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
FloatProperties.RECT_X, velocityX, isStash ? mStashConfigX : mFlingConfigX,
mSpringConfig, true /* flingMustReachMinOrMax */)
.flingThenSpring(
- FloatProperties.RECT_Y, velocityY, mFlingConfigY, mSpringConfig)
- .withEndActions(endAction);
+ FloatProperties.RECT_Y, velocityY, mFlingConfigY, mSpringConfig);
- final float leftEdge = isStash ? mStashOffset - mPipBoundsState.getBounds().width()
- : mMovementBounds.left;
- final float rightEdge = isStash ? mPipBoundsState.getDisplayBounds().right - mStashOffset
- : mMovementBounds.right;
+ final float leftEdge = isStash
+ ? mPipBoundsState.getStashOffset() - mPipBoundsState.getBounds().width()
+ : mPipBoundsState.getMovementBounds().left;
+ final float rightEdge = isStash
+ ? mPipBoundsState.getDisplayBounds().right - mPipBoundsState.getStashOffset()
+ : mPipBoundsState.getMovementBounds().right;
final float xEndValue = velocityX < 0 ? leftEdge : rightEdge;
+
+ final int startValueY = mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds().top;
final float estimatedFlingYEndValue =
- PhysicsAnimator.estimateFlingEndValue(
- mTemporaryBounds.top, velocityY, mFlingConfigY);
+ PhysicsAnimator.estimateFlingEndValue(startValueY, velocityY, mFlingConfigY);
startBoundsAnimator(xEndValue /* toX */, estimatedFlingYEndValue /* toY */,
- false /* dismiss */);
+ postBoundsUpdateCallback);
}
/**
@@ -443,14 +413,13 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
void animateToBounds(Rect bounds, PhysicsAnimator.SpringConfig springConfig) {
if (!mTemporaryBoundsPhysicsAnimator.isRunning()) {
// Animate from the current bounds if we're not already animating.
- mTemporaryBounds.set(getBounds());
+ mPipBoundsState.getAnimatingBoundsState().setTemporaryBounds(getBounds());
}
mTemporaryBoundsPhysicsAnimator
.spring(FloatProperties.RECT_X, bounds.left, springConfig)
.spring(FloatProperties.RECT_Y, bounds.top, springConfig);
- startBoundsAnimator(bounds.left /* toX */, bounds.top /* toY */,
- false /* dismiss */);
+ startBoundsAnimator(bounds.left /* toX */, bounds.top /* toY */);
}
/**
@@ -460,14 +429,13 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
// Animate off the bottom of the screen, then dismiss PIP.
mTemporaryBoundsPhysicsAnimator
.spring(FloatProperties.RECT_Y,
- mMovementBounds.bottom + getBounds().height() * 2,
+ mPipBoundsState.getMovementBounds().bottom + getBounds().height() * 2,
0,
mSpringConfig)
.withEndActions(this::dismissPip);
startBoundsAnimator(
- getBounds().left /* toX */, getBounds().bottom + getBounds().height() /* toY */,
- true /* dismiss */);
+ getBounds().left /* toX */, getBounds().bottom + getBounds().height() /* toY */);
mDismissalPending = false;
}
@@ -493,9 +461,12 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
if (savedSnapFraction < 0f) {
// If there are no saved snap fractions, then just use the current bounds
savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(getBounds()),
- currentMovementBounds);
+ currentMovementBounds, mPipBoundsState.getStashedState());
}
- mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction);
+
+ mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction,
+ mPipBoundsState.getStashedState(), mPipBoundsState.getStashOffset(),
+ mPipBoundsState.getDisplayBounds());
if (immediate) {
movePip(normalBounds);
@@ -513,7 +484,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
Log.d(TAG, "animateToOffset: originalBounds=" + originalBounds + " offset=" + offset
+ " callers=\n" + Debug.getCallers(5, " "));
}
- cancelAnimations();
+ cancelPhysicsAnimation();
mPipTaskOrganizer.scheduleOffsetPip(originalBounds, offset, SHIFT_DURATION,
mUpdateBoundsCallback);
}
@@ -521,21 +492,28 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
/**
* Cancels all existing animations.
*/
- private void cancelAnimations() {
+ private void cancelPhysicsAnimation() {
mTemporaryBoundsPhysicsAnimator.cancel();
- mAnimatingToBounds.setEmpty();
+ mPipBoundsState.getAnimatingBoundsState().onPhysicsAnimationEnded();
mSpringingToTouch = false;
}
/** Set new fling configs whose min/max values respect the given movement bounds. */
private void rebuildFlingConfigs() {
- mFlingConfigX = new PhysicsAnimator.FlingConfig(
- DEFAULT_FRICTION, mMovementBounds.left, mMovementBounds.right);
- mFlingConfigY = new PhysicsAnimator.FlingConfig(
- DEFAULT_FRICTION, mMovementBounds.top, mMovementBounds.bottom);
+ mFlingConfigX = new PhysicsAnimator.FlingConfig(DEFAULT_FRICTION,
+ mPipBoundsState.getMovementBounds().left,
+ mPipBoundsState.getMovementBounds().right);
+ mFlingConfigY = new PhysicsAnimator.FlingConfig(DEFAULT_FRICTION,
+ mPipBoundsState.getMovementBounds().top,
+ mPipBoundsState.getMovementBounds().bottom);
mStashConfigX = new PhysicsAnimator.FlingConfig(
- DEFAULT_FRICTION, mStashOffset - mPipBoundsState.getBounds().width(),
- mPipBoundsState.getDisplayBounds().right - mStashOffset);
+ DEFAULT_FRICTION,
+ mPipBoundsState.getStashOffset() - mPipBoundsState.getBounds().width(),
+ mPipBoundsState.getDisplayBounds().right - mPipBoundsState.getStashOffset());
+ }
+
+ private void startBoundsAnimator(float toX, float toY) {
+ startBoundsAnimator(toX, toY, null /* postBoundsUpdateCallback */);
}
/**
@@ -544,25 +522,32 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
*
* 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.
+ *
+ * If one wishes to supply a callback after all the 'real' bounds update has happened,
+ * pass @param postBoundsUpdateCallback.
*/
- private void startBoundsAnimator(float toX, float toY, boolean dismiss) {
+ private void startBoundsAnimator(float toX, float toY, Runnable postBoundsUpdateCallback) {
if (!mSpringingToTouch) {
- cancelAnimations();
+ cancelPhysicsAnimation();
}
- // Set animatingToBounds directly to avoid allocating a new Rect, but then call
- // setAnimatingToBounds to run the normal logic for changing animatingToBounds.
- mAnimatingToBounds.set(
+ setAnimatingToBounds(new Rect(
(int) toX,
(int) toY,
(int) toX + getBounds().width(),
- (int) toY + getBounds().height());
- setAnimatingToBounds(mAnimatingToBounds);
+ (int) toY + getBounds().height()));
if (!mTemporaryBoundsPhysicsAnimator.isRunning()) {
- mTemporaryBoundsPhysicsAnimator
- .addUpdateListener(mResizePipUpdateListener)
- .withEndActions(this::onBoundsAnimationEnd);
+ if (postBoundsUpdateCallback != null) {
+ mTemporaryBoundsPhysicsAnimator
+ .addUpdateListener(mResizePipUpdateListener)
+ .withEndActions(this::onBoundsPhysicsAnimationEnd,
+ postBoundsUpdateCallback);
+ } else {
+ mTemporaryBoundsPhysicsAnimator
+ .addUpdateListener(mResizePipUpdateListener)
+ .withEndActions(this::onBoundsPhysicsAnimationEnd);
+ }
}
mTemporaryBoundsPhysicsAnimator.start();
@@ -576,31 +561,34 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
mDismissalPending = true;
}
- private void onBoundsAnimationEnd() {
+ private void onBoundsPhysicsAnimationEnd() {
+ // The physics animation ended, though we may not necessarily be done animating, such as
+ // when we're still dragging after moving out of the magnetic target.
if (!mDismissalPending
&& !mSpringingToTouch
&& !mMagnetizedPip.getObjectStuckToTarget()) {
- mPipBoundsState.setBounds(mTemporaryBounds);
+ // All animations (including dragging) have actually finished.
+ mPipBoundsState.setBounds(
+ mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds());
+ mPipBoundsState.getAnimatingBoundsState().onAllAnimationsEnded();
if (!mDismissalPending) {
// do not schedule resize if PiP is dismissing, which may cause app re-open to
// mBounds instead of it's normal bounds.
mPipTaskOrganizer.scheduleFinishResizePip(getBounds());
}
- mTemporaryBounds.setEmpty();
}
-
- mAnimatingToBounds.setEmpty();
+ mPipBoundsState.getAnimatingBoundsState().onPhysicsAnimationEnded();
mSpringingToTouch = false;
mDismissalPending = false;
}
/**
- * Notifies the floating coordinator that we're moving, and sets {@link #mAnimatingToBounds} so
+ * Notifies the floating coordinator that we're moving, and sets the animating to bounds so
* we return these bounds from
* {@link FloatingContentCoordinator.FloatingContent#getFloatingBoundsOnScreen()}.
*/
private void setAnimatingToBounds(Rect bounds) {
- mAnimatingToBounds.set(bounds);
+ mPipBoundsState.getAnimatingBoundsState().setAnimatingToBounds(bounds);
mFloatingContentCoordinator.onContentMoved(this);
}
@@ -639,7 +627,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
MagnetizedObject<Rect> getMagnetizedPip() {
if (mMagnetizedPip == null) {
mMagnetizedPip = new MagnetizedObject<Rect>(
- mContext, mTemporaryBounds, FloatProperties.RECT_X, FloatProperties.RECT_Y) {
+ mContext, mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds(),
+ FloatProperties.RECT_X, FloatProperties.RECT_Y) {
@Override
public float getWidth(@NonNull Rect animatedPipBounds) {
return animatedPipBounds.width();
@@ -661,10 +650,4 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
return mMagnetizedPip;
}
-
- public void dump(PrintWriter pw, String prefix) {
- final String innerPrefix = prefix + " ";
- pw.println(prefix + TAG);
- pw.println(innerPrefix + "mBounds=" + getBounds());
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index f3d8c7b0f598..4849e0ddb6f7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -46,7 +46,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.policy.TaskResizingAlgorithm;
import com.android.wm.shell.R;
-import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipUiEventLogger;
@@ -66,7 +66,7 @@ public class PipResizeGestureHandler {
private static final float STARTING_SCALE_FACTOR = 1.0f;
private final Context mContext;
- private final PipBoundsHandler mPipBoundsHandler;
+ private final PipBoundsAlgorithm mPipBoundsAlgorithm;
private final PipMotionHelper mMotionHelper;
private final PipBoundsState mPipBoundsState;
private final int mDisplayId;
@@ -108,7 +108,7 @@ public class PipResizeGestureHandler {
private int mCtrlType;
- public PipResizeGestureHandler(Context context, PipBoundsHandler pipBoundsHandler,
+ public PipResizeGestureHandler(Context context, PipBoundsAlgorithm pipBoundsAlgorithm,
PipBoundsState pipBoundsState, PipMotionHelper motionHelper,
PipTaskOrganizer pipTaskOrganizer, Function<Rect, Rect> movementBoundsSupplier,
Runnable updateMovementBoundsRunnable, PipUiEventLogger pipUiEventLogger,
@@ -116,7 +116,7 @@ public class PipResizeGestureHandler {
mContext = context;
mDisplayId = context.getDisplayId();
mMainExecutor = context.getMainExecutor();
- mPipBoundsHandler = pipBoundsHandler;
+ mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipBoundsState = pipBoundsState;
mMotionHelper = motionHelper;
mPipTaskOrganizer = pipTaskOrganizer;
@@ -451,7 +451,9 @@ public class PipResizeGestureHandler {
mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
mMinSize.y, mMaxSize, true,
mLastDownBounds.width() > mLastDownBounds.height()));
- mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds);
+ mPipBoundsAlgorithm.transformBoundsToAspectRatio(mLastResizeBounds,
+ mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */,
+ true /* useCurrentSize */);
mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, mLastResizeBounds,
null);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index d820e772d490..609fa3509e67 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -48,12 +48,14 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.R;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.pip.PipAnimationController;
-import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipUiEventLogger;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.function.Consumer;
/**
* Manages all the touch handling for PIP on the Phone, including moving, dismissing and expanding
@@ -62,44 +64,32 @@ import java.io.PrintWriter;
public class PipTouchHandler {
private static final String TAG = "PipTouchHandler";
- /** Duration of the dismiss scrim fading in/out. */
- private static final int DISMISS_TRANSITION_DURATION_MS = 200;
-
- /* The multiplier to apply scale the target size by when applying the magnetic field radius */
- private static final float MAGNETIC_FIELD_RADIUS_MULTIPLIER = 1.25f;
+ private static final float STASH_MINIMUM_VELOCITY_X = 3000.f;
// Allow PIP to resize to a slightly bigger state upon touch
private final boolean mEnableResize;
private final Context mContext;
- private final PipBoundsHandler mPipBoundsHandler;
+ private final PipBoundsAlgorithm mPipBoundsAlgorithm;
private final @NonNull PipBoundsState mPipBoundsState;
private final PipUiEventLogger mPipUiEventLogger;
private final PipDismissTargetHandler mPipDismissTargetHandler;
private PipResizeGestureHandler mPipResizeGestureHandler;
private IPinnedStackController mPinnedStackController;
+ private WeakReference<Consumer<Rect>> mPipExclusionBoundsChangeListener;
private final PipMenuActivityController mMenuController;
private final AccessibilityManager mAccessibilityManager;
private boolean mShowPipMenuOnAnimationEnd = false;
/**
- * Whether PIP stash is enabled or not. When enabled, if at the time of fling-release the
- * PIP bounds is outside the left/right edge of the screen, it will be shown in "stashed" mode,
- * where PIP will only show partially.
+ * Whether PIP stash is enabled or not. When enabled, if the user flings toward the edge of the
+ * screen, it will be shown in "stashed" mode, where PIP will only show partially.
*/
- private boolean mEnableStash = false;
-
- // The current movement bounds
- private Rect mMovementBounds = new Rect();
+ private boolean mEnableStash = true;
// The reference inset bounds, used to determine the dismiss fraction
private Rect mInsetBounds = new Rect();
- // The reference bounds used to calculate the normal/expanded target bounds
- private Rect mNormalBounds = new Rect();
- @VisibleForTesting public Rect mNormalMovementBounds = new Rect();
- private Rect mExpandedBounds = new Rect();
- @VisibleForTesting public Rect mExpandedMovementBounds = new Rect();
private int mExpandedShortestEdgeSize;
// Used to workaround an issue where the WM rotation happens before we are notified, allowing
@@ -163,7 +153,7 @@ public class PipTouchHandler {
@SuppressLint("InflateParams")
public PipTouchHandler(Context context,
PipMenuActivityController menuController,
- PipBoundsHandler pipBoundsHandler,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
@NonNull PipBoundsState pipBoundsState,
PipTaskOrganizer pipTaskOrganizer,
FloatingContentCoordinator floatingContentCoordinator,
@@ -171,15 +161,16 @@ public class PipTouchHandler {
// Initialize the Pip input consumer
mContext = context;
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
- mPipBoundsHandler = pipBoundsHandler;
+ mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipBoundsState = pipBoundsState;
mMenuController = menuController;
mMenuController.addListener(new PipMenuListener());
mGesture = new DefaultPipTouchGesture();
mMotionHelper = new PipMotionHelper(mContext, pipBoundsState, pipTaskOrganizer,
- mMenuController, mPipBoundsHandler.getSnapAlgorithm(), floatingContentCoordinator);
+ mMenuController, mPipBoundsAlgorithm.getSnapAlgorithm(),
+ floatingContentCoordinator);
mPipResizeGestureHandler =
- new PipResizeGestureHandler(context, pipBoundsHandler, pipBoundsState,
+ new PipResizeGestureHandler(context, pipBoundsAlgorithm, pipBoundsState,
mMotionHelper, pipTaskOrganizer, this::getMovementBounds,
this::updateMovementBounds, pipUiEventLogger, menuController);
mPipDismissTargetHandler = new PipDismissTargetHandler(context, pipUiEventLogger,
@@ -195,7 +186,7 @@ public class PipTouchHandler {
mFloatingContentCoordinator = floatingContentCoordinator;
mConnection = new PipAccessibilityInteractionConnection(mContext, pipBoundsState,
- mMotionHelper, pipTaskOrganizer, mPipBoundsHandler.getSnapAlgorithm(),
+ mMotionHelper, pipTaskOrganizer, mPipBoundsAlgorithm.getSnapAlgorithm(),
this::onAccessibilityShowMenu, this::updateMovementBounds, mHandler);
mPipUiEventLogger = pipUiEventLogger;
@@ -203,13 +194,13 @@ public class PipTouchHandler {
mEnableStash = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_SYSTEMUI,
PIP_STASHING,
- /* defaultValue = */ false);
+ /* defaultValue = */ true);
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
context.getMainExecutor(),
properties -> {
if (properties.getKeyset().contains(PIP_STASHING)) {
mEnableStash = properties.getBoolean(
- PIP_STASHING, /* defaultValue = */ false);
+ PIP_STASHING, /* defaultValue = */ true);
}
});
}
@@ -221,7 +212,6 @@ public class PipTouchHandler {
R.dimen.pip_expanded_shortest_edge_size);
mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset);
mPipDismissTargetHandler.updateMagneticTargetSize();
- mMotionHelper.reloadResources();
}
private boolean shouldShowResizeHandle() {
@@ -260,6 +250,11 @@ public class PipTouchHandler {
mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
}
+ // Reset exclusion to none.
+ if (mPipExclusionBoundsChangeListener != null
+ && mPipExclusionBoundsChangeListener.get() != null) {
+ mPipExclusionBoundsChangeListener.get().accept(new Rect());
+ }
mPipResizeGestureHandler.onActivityUnpinned();
}
@@ -311,9 +306,10 @@ public class PipTouchHandler {
public void adjustBoundsForRotation(Rect outBounds, Rect curBounds, Rect insetBounds) {
final Rect toMovementBounds = new Rect();
- mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(outBounds, insetBounds,
+ mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(outBounds, insetBounds,
toMovementBounds, 0);
- final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets;
+ final int prevBottom = mPipBoundsState.getMovementBounds().bottom
+ - mMovementBoundsExtraOffsets;
if ((prevBottom - mBottomOffsetBufferPx) <= curBounds.top) {
outBounds.offsetTo(outBounds.left, toMovementBounds.bottom);
}
@@ -341,31 +337,33 @@ public class PipTouchHandler {
}
// Re-calculate the expanded bounds
- mNormalBounds.set(normalBounds);
Rect normalMovementBounds = new Rect();
- mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(mNormalBounds, insetBounds,
+ mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(normalBounds, insetBounds,
normalMovementBounds, bottomOffset);
- if (mMovementBounds.isEmpty()) {
+ if (mPipBoundsState.getMovementBounds().isEmpty()) {
// mMovementBounds is not initialized yet and a clean movement bounds without
// bottom offset shall be used later in this function.
- mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(curBounds, insetBounds,
- mMovementBounds, 0 /* bottomOffset */);
+ mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(curBounds, insetBounds,
+ mPipBoundsState.getMovementBounds(), 0 /* bottomOffset */);
}
// Calculate the expanded size
float aspectRatio = (float) normalBounds.width() / normalBounds.height();
Point displaySize = new Point();
mContext.getDisplay().getRealSize(displaySize);
- Size expandedSize = mPipBoundsHandler.getSnapAlgorithm().getSizeForAspectRatio(aspectRatio,
- mExpandedShortestEdgeSize, displaySize.x, displaySize.y);
- mExpandedBounds.set(0, 0, expandedSize.getWidth(), expandedSize.getHeight());
+ Size expandedSize = mPipBoundsAlgorithm.getSnapAlgorithm().getSizeForAspectRatio(
+ aspectRatio, mExpandedShortestEdgeSize, displaySize.x, displaySize.y);
+ mPipBoundsState.setExpandedBounds(
+ new Rect(0, 0, expandedSize.getWidth(), expandedSize.getHeight()));
Rect expandedMovementBounds = new Rect();
- mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(mExpandedBounds, insetBounds,
- expandedMovementBounds, bottomOffset);
+ mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(
+ mPipBoundsState.getExpandedBounds(), insetBounds, expandedMovementBounds,
+ bottomOffset);
- mPipResizeGestureHandler.updateMinSize(mNormalBounds.width(), mNormalBounds.height());
- mPipResizeGestureHandler.updateMaxSize(mExpandedBounds.width(), mExpandedBounds.height());
+ mPipResizeGestureHandler.updateMinSize(normalBounds.width(), normalBounds.height());
+ mPipResizeGestureHandler.updateMaxSize(mPipBoundsState.getExpandedBounds().width(),
+ mPipBoundsState.getExpandedBounds().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
@@ -382,9 +380,10 @@ public class PipTouchHandler {
} else {
final boolean isExpanded = mMenuState == MENU_STATE_FULL && willResizeMenu();
final Rect toMovementBounds = new Rect();
- mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(curBounds, insetBounds,
+ mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(curBounds, insetBounds,
toMovementBounds, mIsImeShowing ? mImeHeight : 0);
- final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets;
+ final int prevBottom = mPipBoundsState.getMovementBounds().bottom
+ - mMovementBoundsExtraOffsets;
// This is to handle landscape fullscreen IMEs, don't apply the extra offset in this
// case
final int toBottom = toMovementBounds.bottom < toMovementBounds.top
@@ -392,8 +391,8 @@ public class PipTouchHandler {
: toMovementBounds.bottom - extraOffset;
if (isExpanded) {
- curBounds.set(mExpandedBounds);
- mPipBoundsHandler.getSnapAlgorithm().applySnapFraction(curBounds,
+ curBounds.set(mPipBoundsState.getExpandedBounds());
+ mPipBoundsAlgorithm.getSnapAlgorithm().applySnapFraction(curBounds,
toMovementBounds, mSavedSnapFraction);
}
@@ -413,19 +412,21 @@ public class PipTouchHandler {
// Update the movement bounds after doing the calculations based on the old movement bounds
// above
- mNormalMovementBounds.set(normalMovementBounds);
- mExpandedMovementBounds.set(expandedMovementBounds);
+ mPipBoundsState.setNormalMovementBounds(normalMovementBounds);
+ mPipBoundsState.setExpandedMovementBounds(expandedMovementBounds);
mDisplayRotation = displayRotation;
mInsetBounds.set(insetBounds);
updateMovementBounds();
mMovementBoundsExtraOffsets = extraOffset;
- mConnection.onMovementBoundsChanged(mNormalBounds, mExpandedBounds, mNormalMovementBounds,
- mExpandedMovementBounds);
+ mConnection.onMovementBoundsChanged(normalBounds, mPipBoundsState.getExpandedBounds(),
+ mPipBoundsState.getNormalMovementBounds(),
+ mPipBoundsState.getExpandedMovementBounds());
// If we have a deferred resize, apply it now
if (mDeferResizeToNormalBoundsUntilRotation == displayRotation) {
mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
- mNormalMovementBounds, mMovementBounds, true /* immediate */);
+ mPipBoundsState.getNormalMovementBounds(), mPipBoundsState.getMovementBounds(),
+ true /* immediate */);
mSavedSnapFraction = -1f;
mDeferResizeToNormalBoundsUntilRotation = -1;
}
@@ -649,17 +650,18 @@ public class PipTouchHandler {
}
private void animateToExpandedState(Runnable callback) {
- Rect expandedBounds = new Rect(mExpandedBounds);
+ Rect expandedBounds = new Rect(mPipBoundsState.getExpandedBounds());
mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
- mMovementBounds, mExpandedMovementBounds, callback);
+ mPipBoundsState.getMovementBounds(), mPipBoundsState.getExpandedMovementBounds(),
+ callback);
}
private void animateToUnexpandedState(Rect restoreBounds) {
Rect restoredMovementBounds = new Rect();
- mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(restoreBounds,
+ mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(restoreBounds,
mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
mMotionHelper.animateToUnexpandedState(restoreBounds, mSavedSnapFraction,
- restoredMovementBounds, mMovementBounds, false /* immediate */);
+ restoredMovementBounds, mPipBoundsState.getMovementBounds(), false /* immediate */);
mSavedSnapFraction = -1f;
}
@@ -685,13 +687,6 @@ public class PipTouchHandler {
mMotionHelper = pipMotionHelper;
}
- /**
- * @return the unexpanded bounds.
- */
- public Rect getNormalBounds() {
- return mNormalBounds;
- }
-
Rect getUserResizeBounds() {
return mPipResizeGestureHandler.getUserResizeBounds();
}
@@ -703,6 +698,7 @@ public class PipTouchHandler {
private final Point mStartPosition = new Point();
private final PointF mDelta = new PointF();
private boolean mShouldHideMenuAfterFling;
+ private float mDownSavedFraction = -1f;
@Override
public void onDown(PipTouchState touchState) {
@@ -710,11 +706,13 @@ public class PipTouchHandler {
return;
}
- Rect bounds = mMotionHelper.getPossiblyAnimatingBounds();
+ Rect bounds = getPossiblyAnimatingBounds();
mDelta.set(0f, 0f);
mStartPosition.set(bounds.left, bounds.top);
- mMovementWithinDismiss = touchState.getDownTouchPosition().y >= mMovementBounds.bottom;
+ mMovementWithinDismiss = touchState.getDownTouchPosition().y
+ >= mPipBoundsState.getMovementBounds().bottom;
mMotionHelper.setSpringingToTouch(false);
+ mDownSavedFraction = mPipBoundsAlgorithm.getSnapFraction(mPipBoundsState.getBounds());
// If the menu is still visible then just poke the menu
// so that it will timeout after the user stops touching it
@@ -730,7 +728,7 @@ public class PipTouchHandler {
}
if (touchState.startedDragging()) {
- mPipBoundsState.setStashed(false);
+ mPipBoundsState.setStashed(PipBoundsState.STASH_TYPE_NONE);
mSavedSnapFraction = -1f;
mPipDismissTargetHandler.showDismissTargetMaybe();
}
@@ -747,14 +745,14 @@ public class PipTouchHandler {
mDelta.x += left - lastX;
mDelta.y += top - lastY;
- mTmpBounds.set(mMotionHelper.getPossiblyAnimatingBounds());
+ mTmpBounds.set(getPossiblyAnimatingBounds());
mTmpBounds.offsetTo((int) left, (int) top);
mMotionHelper.movePip(mTmpBounds, true /* isDragging */);
final PointF curPos = touchState.getLastTouchPosition();
if (mMovementWithinDismiss) {
// Track if movement remains near the bottom edge to identify swipe to dismiss
- mMovementWithinDismiss = curPos.y >= mMovementBounds.bottom;
+ mMovementWithinDismiss = curPos.y >= mPipBoundsState.getMovementBounds().bottom;
}
return true;
}
@@ -783,14 +781,15 @@ public class PipTouchHandler {
// Reset the touch state on up before the fling settles
mTouchState.reset();
- final Rect animatingBounds = mMotionHelper.getPossiblyAnimatingBounds();
- // If User releases the PIP window while it's out of the display bounds, put
- // PIP into stashed mode.
- if (mEnableStash
- && (animatingBounds.right > mPipBoundsState.getDisplayBounds().right
- || animatingBounds.left < mPipBoundsState.getDisplayBounds().left)) {
- mPipBoundsState.setStashed(true);
- mMotionHelper.stashToEdge(vel.x, vel.y, this::flingEndAction /* endAction */);
+ // If user flings the PIP window above the minimum velocity, stash PIP.
+ // Only allow stashing to the edge if the user starts dragging the PIP from that
+ // edge.
+ if (mEnableStash && !mPipBoundsState.isStashed()
+ && ((vel.x > STASH_MINIMUM_VELOCITY_X
+ && mDownSavedFraction > 1f && mDownSavedFraction < 2f)
+ || (vel.x < -STASH_MINIMUM_VELOCITY_X
+ && mDownSavedFraction > 3f && mDownSavedFraction < 4f))) {
+ mMotionHelper.stashToEdge(vel.x, this::stashEndAction /* endAction */);
} else {
mMotionHelper.flingToSnapTarget(vel.x, vel.y,
this::flingEndAction /* endAction */);
@@ -798,15 +797,17 @@ public class PipTouchHandler {
} else if (mTouchState.isDoubleTap() && !mPipBoundsState.isStashed()) {
// If using pinch to zoom, double-tap functions as resizing between max/min size
if (mPipResizeGestureHandler.isUsingPinchToZoom()) {
- final boolean toExpand =
- mMotionHelper.getBounds().width() < mExpandedBounds.width()
- && mMotionHelper.getBounds().height() < mExpandedBounds.height();
- mPipResizeGestureHandler.setUserResizeBounds(toExpand ? mExpandedBounds
- : mNormalBounds);
+ final boolean toExpand = mMotionHelper.getBounds().width()
+ < mPipBoundsState.getExpandedBounds().width()
+ && mMotionHelper.getBounds().height()
+ < mPipBoundsState.getExpandedBounds().height();
+ mPipResizeGestureHandler.setUserResizeBounds(toExpand
+ ? mPipBoundsState.getExpandedBounds()
+ : mPipBoundsState.getNormalBounds());
if (toExpand) {
animateToExpandedState(null);
} else {
- animateToUnexpandedState(mNormalBounds);
+ animateToUnexpandedState(mPipBoundsState.getNormalBounds());
}
} else {
// Expand to fullscreen if this is a double tap
@@ -828,35 +829,54 @@ public class PipTouchHandler {
mTouchState.scheduleDoubleTapTimeoutCallback();
}
}
+ mDownSavedFraction = -1f;
return true;
}
+ private void stashEndAction() {
+ if (mPipExclusionBoundsChangeListener != null
+ && mPipExclusionBoundsChangeListener.get() != null) {
+ mPipExclusionBoundsChangeListener.get().accept(mPipBoundsState.getBounds());
+ }
+ }
+
private void flingEndAction() {
if (mShouldHideMenuAfterFling) {
// If the menu is not visible, then we can still be showing the activity for the
// dismiss overlay, so just finish it after the animation completes
mMenuController.hideMenu();
}
+ // Reset exclusion to none.
+ if (mPipExclusionBoundsChangeListener != null
+ && mPipExclusionBoundsChangeListener.get() != null) {
+ mPipExclusionBoundsChangeListener.get().accept(new Rect());
+ }
}
}
+ void setPipExclusionBoundsChangeListener(Consumer<Rect> pipExclusionBoundsChangeListener) {
+ mPipExclusionBoundsChangeListener = new WeakReference<>(pipExclusionBoundsChangeListener);
+ pipExclusionBoundsChangeListener.accept(mPipBoundsState.getBounds());
+ }
+
/**
* Updates the current movement bounds based on whether the menu is currently visible and
* resized.
*/
private void updateMovementBounds() {
- mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(mMotionHelper.getBounds(),
- mInsetBounds, mMovementBounds, mIsImeShowing ? mImeHeight : 0);
- mMotionHelper.setCurrentMovementBounds(mMovementBounds);
+ mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(mMotionHelper.getBounds(),
+ mInsetBounds, mPipBoundsState.getMovementBounds(), mIsImeShowing ? mImeHeight : 0);
+ mMotionHelper.onMovementBoundsChanged();
boolean isMenuExpanded = mMenuState == MENU_STATE_FULL;
- mPipBoundsHandler.setMinEdgeSize(
- isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize : 0);
+ mPipBoundsState.setMinEdgeSize(
+ isMenuExpanded && willResizeMenu() ? mExpandedShortestEdgeSize
+ : mPipBoundsAlgorithm.getDefaultMinSize());
}
private Rect getMovementBounds(Rect curBounds) {
Rect movementBounds = new Rect();
- mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(curBounds, mInsetBounds,
+ mPipBoundsAlgorithm.getSnapAlgorithm().getMovementBounds(curBounds, mInsetBounds,
movementBounds, mIsImeShowing ? mImeHeight : 0);
return movementBounds;
}
@@ -868,18 +888,25 @@ public class PipTouchHandler {
if (!mEnableResize) {
return false;
}
- return mExpandedBounds.width() != mNormalBounds.width()
- || mExpandedBounds.height() != mNormalBounds.height();
+ return mPipBoundsState.getExpandedBounds().width()
+ != mPipBoundsState.getNormalBounds().width()
+ || mPipBoundsState.getExpandedBounds().height()
+ != mPipBoundsState.getNormalBounds().height();
+ }
+
+ /**
+ * Returns the PIP bounds if we're not animating, or the current, temporary animating bounds
+ * otherwise.
+ */
+ Rect getPossiblyAnimatingBounds() {
+ return mPipBoundsState.getAnimatingBoundsState().isAnimating()
+ ? mPipBoundsState.getAnimatingBoundsState().getTemporaryBounds()
+ : mPipBoundsState.getBounds();
}
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
- pw.println(innerPrefix + "mMovementBounds=" + mMovementBounds);
- 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);
@@ -887,9 +914,8 @@ public class PipTouchHandler {
pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
pw.println(innerPrefix + "mSavedSnapFraction=" + mSavedSnapFraction);
pw.println(innerPrefix + "mMovementBoundsExtraOffsets=" + mMovementBoundsExtraOffsets);
- mPipBoundsHandler.dump(pw, innerPrefix);
+ mPipBoundsAlgorithm.dump(pw, innerPrefix);
mTouchState.dump(pw, innerPrefix);
- mMotionHelper.dump(pw, innerPrefix);
if (mPipResizeGestureHandler != null) {
mPipResizeGestureHandler.dump(pw, innerPrefix);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
index 3468b888c06a..56e97b91c9d2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
@@ -48,9 +48,11 @@ import android.view.DisplayInfo;
import com.android.wm.shell.R;
import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipTaskOrganizer;
@@ -106,7 +108,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
private final Context mContext;
private final PipBoundsState mPipBoundsState;
- private final PipBoundsHandler mPipBoundsHandler;
+ private final PipBoundsAlgorithm mPipBoundsAlgorithm;
private final PipTaskOrganizer mPipTaskOrganizer;
private final PipMediaController mPipMediaController;
@@ -180,7 +182,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mHandler.post(() -> {
- mPipBoundsHandler.onImeVisibilityChanged(imeVisible, imeHeight);
+ mPipBoundsState.setImeVisibility(imeVisible, imeHeight);
if (mState == STATE_PIP) {
if (mImeVisible != imeVisible) {
if (imeVisible) {
@@ -202,9 +204,12 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
public void onMovementBoundsChanged(boolean fromImeAdjustment) {
mHandler.post(() -> {
mTmpDisplayInfo.copyFrom(mPipBoundsState.getDisplayInfo());
- // Populate the inset / normal bounds from mPipBoundsHandler first.
- mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mPipBounds,
- mDefaultPipBounds);
+
+ mPipBoundsAlgorithm.getInsetBounds(mTmpInsetBounds);
+ mPipBounds.set(mPipBoundsAlgorithm.getNormalBounds());
+ if (mDefaultPipBounds.isEmpty()) {
+ mDefaultPipBounds.set(mPipBoundsAlgorithm.getDefaultBounds());
+ }
});
}
@@ -221,15 +226,16 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
public PipController(Context context,
PipBoundsState pipBoundsState,
- PipBoundsHandler pipBoundsHandler,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
PipTaskOrganizer pipTaskOrganizer,
PipMediaController pipMediaController,
PipNotification pipNotification,
+ TaskStackListenerImpl taskStackListener,
WindowManagerShellWrapper windowManagerShellWrapper) {
mContext = context;
mPipBoundsState = pipBoundsState;
mPipNotification = pipNotification;
- mPipBoundsHandler = pipBoundsHandler;
+ mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipMediaController = pipMediaController;
// Ensure that we have the display info in case we get calls to update the bounds
// before the listener calls back
@@ -263,6 +269,27 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
Log.e(TAG, "Failed to register pinned stack listener", e);
}
+ // Handle for system task stack changes.
+ taskStackListener.addListener(
+ new TaskStackListenerCallback() {
+ @Override
+ public void onTaskStackChanged() {
+ PipController.this.onTaskStackChanged();
+ }
+
+ @Override
+ public void onActivityPinned(String packageName, int userId, int taskId,
+ int stackId) {
+ PipController.this.onActivityPinned(packageName);
+ }
+
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ PipController.this.onActivityRestartAttempt(task, clearedTask);
+ }
+ });
+
// TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
PipMenuActivity.setPipController(this);
}
@@ -351,8 +378,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
resizePinnedStack(STATE_NO_PIP);
}
- @Override
- public void onActivityPinned(String packageName) {
+ private void onActivityPinned(String packageName) {
if (DEBUG) Log.d(TAG, "onActivityPinned()");
RootTaskInfo taskInfo = getPinnedTaskInfo();
@@ -371,11 +397,9 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
}
}
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ private void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
boolean clearedTask) {
- if (task.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_PINNED) {
+ if (task.getWindowingMode() != WINDOWING_MODE_PINNED) {
return;
}
if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
@@ -384,8 +408,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
movePipToFullscreen();
}
- @Override
- public void onTaskStackChanged() {
+ private void onTaskStackChanged() {
if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
if (getState() != STATE_NO_PIP) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 985dff20ad32..e55f065c1bb2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -27,9 +27,6 @@ import java.util.function.Consumer;
* Interface to engage split screen feature.
*/
public interface SplitScreen {
- /** Returns {@code true} if split screen is supported on the device. */
- boolean isSplitScreenSupported();
-
/** Called when keyguard showing state changed. */
void onKeyguardVisibilityChanged(boolean isShowing);
@@ -48,15 +45,6 @@ public interface SplitScreen {
/** Switch to minimized state if appropriate. */
void setMinimized(boolean minimized);
- /** Called when there's an activity forced resizable. */
- void onActivityForcedResizable(String packageName, int taskId, int reason);
-
- /** Called when there's an activity dismissing split screen. */
- void onActivityDismissingSplitScreen();
-
- /** Called when there's an activity launch on secondary display failed. */
- void onActivityLaunchOnSecondaryDisplayFailed();
-
/** Called when there's a task undocking. */
void onUndockingTask();
@@ -69,6 +57,9 @@ public interface SplitScreen {
/** Registers listener that gets called whenever the existence of the divider changes. */
void registerInSplitScreenListener(Consumer<Boolean> listener);
+ /** Unregisters listener that gets called whenever the existence of the divider changes. */
+ void unregisterInSplitScreenListener(Consumer<Boolean> listener);
+
/** Registers listener that gets called whenever the split screen bounds changes. */
void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener);
@@ -83,4 +74,9 @@ public interface SplitScreen {
* @return {@code true} if it successes to split the primary task.
*/
boolean splitPrimaryTask();
+
+ /**
+ * Exits the split to make the primary task fullscreen.
+ */
+ void dismissSplitToPrimaryTask();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 8b616e8fd1ee..07af289c4f35 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -20,9 +20,11 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.Display.DEFAULT_DISPLAY;
+import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
@@ -48,12 +50,15 @@ import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerCallback;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -81,8 +86,8 @@ public class SplitScreenController implements SplitScreen,
private final WindowManagerProxy mWindowManagerProxy;
private final TaskOrganizer mTaskOrganizer;
- private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
- new ArrayList<>();
+ private final CopyOnWriteArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners
+ = new CopyOnWriteArrayList<>();
private final ArrayList<WeakReference<BiConsumer<Rect, Rect>>> mBoundsChangedListeners =
new ArrayList<>();
@@ -107,7 +112,8 @@ public class SplitScreenController implements SplitScreen,
public SplitScreenController(Context context,
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController imeController, Handler handler, TransactionPool transactionPool,
- ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue) {
+ ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
+ TaskStackListenerImpl taskStackListener) {
mContext = context;
mDisplayController = displayController;
mSystemWindows = systemWindows;
@@ -162,6 +168,40 @@ public class SplitScreenController implements SplitScreen,
mWindowManager = new DividerWindowManager(mSystemWindows);
mDisplayController.addDisplayWindowListener(this);
// Don't initialize the divider or anything until we get the default display.
+
+ taskStackListener.addListener(
+ new TaskStackListenerCallback() {
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ if (!wasVisible || task.getWindowingMode()
+ != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || !mSplits.isSplitScreenSupported()) {
+ return;
+ }
+
+ if (isMinimized()) {
+ onUndockingTask();
+ }
+ }
+
+ @Override
+ public void onActivityForcedResizable(String packageName, int taskId,
+ int reason) {
+ mForcedResizableController.activityForcedResizable(packageName, taskId,
+ reason);
+ }
+
+ @Override
+ public void onActivityDismissingDockedStack() {
+ mForcedResizableController.activityDismissingSplitScreen();
+ }
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayFailed() {
+ mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
+ }
+ });
}
void onSplitScreenSupported() {
@@ -173,11 +213,6 @@ public class SplitScreenController implements SplitScreen,
}
@Override
- public boolean isSplitScreenSupported() {
- return mSplits.isSplitScreenSupported();
- }
-
- @Override
public void onKeyguardVisibilityChanged(boolean showing) {
if (!isSplitActive() || mView == null) {
return;
@@ -404,21 +439,6 @@ public class SplitScreenController implements SplitScreen,
}
@Override
- public void onActivityForcedResizable(String packageName, int taskId, int reason) {
- mForcedResizableController.activityForcedResizable(packageName, taskId, reason);
- }
-
- @Override
- public void onActivityDismissingSplitScreen() {
- mForcedResizableController.activityDismissingSplitScreen();
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayFailed() {
- mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
- }
-
- @Override
public void onUndockingTask() {
if (mView != null) {
mView.onUndockingTask();
@@ -459,6 +479,17 @@ public class SplitScreenController implements SplitScreen,
}
@Override
+ public void unregisterInSplitScreenListener(Consumer<Boolean> listener) {
+ synchronized (mDockedStackExistsListeners) {
+ for (int i = mDockedStackExistsListeners.size() - 1; i >= 0; i--) {
+ if (mDockedStackExistsListeners.get(i) == listener) {
+ mDockedStackExistsListeners.remove(i);
+ }
+ }
+ }
+ }
+
+ @Override
public void registerBoundsChangeListener(BiConsumer<Rect, Rect> listener) {
synchronized (mBoundsChangedListeners) {
mBoundsChangedListeners.add(new WeakReference<>(listener));
@@ -481,9 +512,7 @@ public class SplitScreenController implements SplitScreen,
}
// Note: The set of running tasks from the system is ordered by recency.
final RunningTaskInfo topRunningTask = runningTasks.get(0);
-
- final int activityType = topRunningTask.configuration.windowConfiguration
- .getActivityType();
+ final int activityType = topRunningTask.getActivityType();
if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
return false;
}
@@ -501,6 +530,11 @@ public class SplitScreenController implements SplitScreen,
}
}
+ @Override
+ public void dismissSplitToPrimaryTask() {
+ startDismissSplit(true /* toPrimaryTask */);
+ }
+
/** Notifies the bounds of split screen changed. */
void notifyBoundsChanged(Rect secondaryWindowBounds, Rect secondaryWindowInsets) {
synchronized (mBoundsChangedListeners) {
@@ -519,8 +553,8 @@ public class SplitScreenController implements SplitScreen,
mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
}
- void startDismissSplit() {
- mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, true /* dismissOrMaximize */);
+ void startDismissSplit(boolean toPrimaryTask) {
+ mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, !toPrimaryTask);
updateVisibility(false /* visible */);
mMinimized = false;
// Resets divider bar position to undefined, so new divider bar will apply default position
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
index f709fed78b44..5b2b38ba8189 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskListener.java
@@ -23,7 +23,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.Display.DEFAULT_DISPLAY;
-import static com.android.wm.shell.ShellTaskOrganizer.getWindowingMode;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
import android.app.ActivityManager.RunningTaskInfo;
@@ -42,6 +41,7 @@ import com.android.wm.shell.Transitions;
import com.android.wm.shell.common.SyncTransactionQueue;
import java.io.PrintWriter;
+import java.util.ArrayList;
class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
private static final String TAG = "SplitScreenTaskListener";
@@ -106,7 +106,7 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
return;
}
- final int winMode = getWindowingMode(taskInfo);
+ final int winMode = taskInfo.getWindowingMode();
if (winMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
ProtoLog.v(WM_SHELL_TASK_ORG,
"%s onTaskAppeared Primary taskId=%d", TAG, taskInfo.taskId);
@@ -271,7 +271,7 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
Log.d(TAG, " was in split, so this means leave it "
+ mPrimary.topActivityType + " " + mSecondary.topActivityType);
}
- mSplitScreenController.startDismissSplit();
+ mSplitScreenController.startDismissSplit(false /* toPrimaryTask */);
} else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
// Wasn't in split-mode (both were empty), but now that the primary split is
// populated, we should fully enter split by moving everything else into secondary.
@@ -283,6 +283,21 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
mSplitScreenController.startEnterSplit();
}
} else if (secondaryImpliesMinimize) {
+ // Workaround for b/172686383, we can't rely on the sync bounds change transaction for
+ // the home task to finish before the last updateChildTaskSurface() call even if it's
+ // queued on the sync transaction queue, so ensure that the home task surface is updated
+ // again before we minimize
+ final ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
+ mSplitScreenController.getWmProxy().getHomeAndRecentsTasks(tasks,
+ mSplitScreenController.getSecondaryRoot());
+ for (int i = 0; i < tasks.size(); i++) {
+ final RunningTaskInfo taskInfo = tasks.get(i);
+ final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
+ if (leash != null) {
+ updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */);
+ }
+ }
+
// Both splits are populated but the secondary split has a home/recents stack on top,
// so enter minimized mode.
mSplitScreenController.ensureMinimizedSplit();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
index c51bbeb7b6c2..0307206e2def 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java
@@ -120,7 +120,7 @@ class WindowManagerProxy {
new WindowOrganizer().applyTransaction(t);
}
- private boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out,
+ boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out,
WindowContainerToken parent) {
boolean resizable = false;
List<ActivityManager.RunningTaskInfo> rootTasks = parent == null
@@ -209,8 +209,7 @@ class WindowManagerProxy {
continue;
}
// Only move fullscreen tasks to split secondary.
- if (rootTask.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_FULLSCREEN) {
+ if (rootTask.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
continue;
}
// Since this iterates from bottom to top, update topHomeTask for every fullscreen task
@@ -232,7 +231,7 @@ class WindowManagerProxy {
}
boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
- final int atype = ti.configuration.windowConfiguration.getActivityType();
+ final int atype = ti.getActivityType();
return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
new file mode 100644
index 000000000000..ee79824ff4a7
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -0,0 +1,343 @@
+/*
+ * 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.wm.shell.startingsurface;
+
+import static android.content.Context.CONTEXT_RESTRICTED;
+import static android.content.res.Configuration.EMPTY;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+import android.window.TaskOrganizer;
+
+import com.android.internal.R;
+import com.android.internal.policy.PhoneWindow;
+
+import java.util.function.Consumer;
+
+/**
+ * Implementation to draw the starting window to an application, and remove the starting window
+ * until the application displays its own window.
+ *
+ * When receive {@link TaskOrganizer#addStartingWindow} callback, use this class to create a
+ * starting window and attached to the Task, then when the Task want to remove the starting window,
+ * the TaskOrganizer will receive {@link TaskOrganizer#removeStartingWindow} callback then use this
+ * class to remove the starting window of the Task.
+ * @hide
+ */
+public class StartingSurfaceDrawer {
+ private static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
+ private static final boolean DEBUG_SPLASH_SCREEN = false;
+
+ private final Context mContext;
+ private final DisplayManager mDisplayManager;
+
+ // TODO(b/131727939) remove this when clearing ActivityRecord
+ private static final int REMOVE_WHEN_TIMEOUT = 2000;
+
+ public StartingSurfaceDrawer(Context context) {
+ mContext = context;
+ mDisplayManager = mContext.getSystemService(DisplayManager.class);
+ }
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final SparseArray<TaskScreenView> mTaskScreenViews = new SparseArray<>();
+
+ /** Obtain proper context for showing splash screen on the provided display. */
+ private Context getDisplayContext(Context context, int displayId) {
+ if (displayId == DEFAULT_DISPLAY) {
+ // The default context fits.
+ return context;
+ }
+
+ final Display targetDisplay = mDisplayManager.getDisplay(displayId);
+ if (targetDisplay == null) {
+ // Failed to obtain the non-default display where splash screen should be shown,
+ // lets not show at all.
+ return null;
+ }
+
+ return context.createDisplayContext(targetDisplay);
+ }
+
+ /**
+ * Called when a task need a starting window.
+ */
+ public void addStartingWindow(ActivityManager.RunningTaskInfo taskInfo, IBinder appToken) {
+
+ final ActivityInfo activityInfo = taskInfo.topActivityInfo;
+ final int displayId = taskInfo.displayId;
+ if (activityInfo.packageName == null) {
+ return;
+ }
+
+ CharSequence nonLocalizedLabel = activityInfo.nonLocalizedLabel;
+ int labelRes = activityInfo.labelRes;
+ if (activityInfo.nonLocalizedLabel == null && activityInfo.labelRes == 0) {
+ ApplicationInfo app = activityInfo.applicationInfo;
+ nonLocalizedLabel = app.nonLocalizedLabel;
+ labelRes = app.labelRes;
+ }
+
+ Context context = mContext;
+ final int theme = activityInfo.getThemeResource();
+ if (DEBUG_SPLASH_SCREEN) {
+ Slog.d(TAG, "addSplashScreen " + activityInfo.packageName
+ + ": nonLocalizedLabel=" + nonLocalizedLabel + " theme="
+ + Integer.toHexString(theme) + " task= " + taskInfo.taskId);
+ }
+
+ // Obtain proper context to launch on the right display.
+ final Context displayContext = getDisplayContext(context, displayId);
+ if (displayContext == null) {
+ // Can't show splash screen on requested display, so skip showing at all.
+ return;
+ }
+ context = displayContext;
+
+ if (theme != context.getThemeResId() || labelRes != 0) {
+ try {
+ context = context.createPackageContext(
+ activityInfo.packageName, CONTEXT_RESTRICTED);
+ context.setTheme(theme);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Ignore
+ }
+ }
+
+ final Configuration taskConfig = taskInfo.getConfiguration();
+ if (taskConfig != null && !taskConfig.equals(EMPTY)) {
+ if (DEBUG_SPLASH_SCREEN) {
+ Slog.d(TAG, "addSplashScreen: creating context based"
+ + " on task Configuration " + taskConfig + " for splash screen");
+ }
+ final Context overrideContext = context.createConfigurationContext(taskConfig);
+ overrideContext.setTheme(theme);
+ final TypedArray typedArray = overrideContext.obtainStyledAttributes(
+ com.android.internal.R.styleable.Window);
+ final int resId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0);
+ if (resId != 0 && overrideContext.getDrawable(resId) != null) {
+ // We want to use the windowBackground for the override context if it is
+ // available, otherwise we use the default one to make sure a themed starting
+ // window is displayed for the app.
+ if (DEBUG_SPLASH_SCREEN) {
+ Slog.d(TAG, "addSplashScreen: apply overrideConfig"
+ + taskConfig + " to starting window resId=" + resId);
+ }
+ context = overrideContext;
+ }
+ typedArray.recycle();
+ }
+
+ int windowFlags = 0;
+ if ((activityInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
+ windowFlags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+ }
+
+ final boolean[] showWallpaper = new boolean[1];
+ final int[] splashscreenContentResId = new int[1];
+ getWindowResFromContext(context, a -> {
+ splashscreenContentResId[0] =
+ a.getResourceId(R.styleable.Window_windowSplashscreenContent, 0);
+ showWallpaper[0] = a.getBoolean(R.styleable.Window_windowShowWallpaper, false);
+ });
+ if (showWallpaper[0]) {
+ windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+ }
+
+ final PhoneWindow win = new PhoneWindow(context);
+ win.setIsStartingWindow(true);
+
+ CharSequence label = context.getResources().getText(labelRes, null);
+ // Only change the accessibility title if the label is localized
+ if (label != null) {
+ win.setTitle(label, true);
+ } else {
+ win.setTitle(nonLocalizedLabel, false);
+ }
+
+ win.setType(WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
+
+ // Assumes it's safe to show starting windows of launched apps while
+ // the keyguard is being hidden. This is okay because starting windows never show
+ // secret information.
+ // TODO(b/113840485): Occluded may not only happen on default display
+ if (displayId == DEFAULT_DISPLAY) {
+ windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+ }
+
+ // Force the window flags: this is a fake window, so it is not really
+ // touchable or focusable by the user. We also add in the ALT_FOCUSABLE_IM
+ // flag because we do know that the next window will take input
+ // focus, so we want to get the IME window up on top of us right away.
+ win.setFlags(windowFlags
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+ windowFlags
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+
+ final int iconRes = activityInfo.getIconResource();
+ final int logoRes = activityInfo.getLogoResource();
+ win.setDefaultIcon(iconRes);
+ win.setDefaultLogo(logoRes);
+
+ win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.MATCH_PARENT);
+
+ final WindowManager.LayoutParams params = win.getAttributes();
+ params.token = appToken;
+ params.packageName = activityInfo.packageName;
+ params.windowAnimations = win.getWindowStyle().getResourceId(
+ com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
+ params.privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
+ params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ // Setting as trusted overlay to let touches pass through. This is safe because this
+ // window is controlled by the system.
+ params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+
+ final Resources res = context.getResources();
+ final boolean supportsScreen = res != null && (res.getCompatibilityInfo() != null
+ && res.getCompatibilityInfo().supportsScreen());
+ if (!supportsScreen) {
+ params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+ }
+
+ params.setTitle("Splash Screen " + activityInfo.packageName);
+ addSplashscreenContent(win, context, splashscreenContentResId[0]);
+
+ final View view = win.getDecorView();
+
+ if (DEBUG_SPLASH_SCREEN) {
+ Slog.d(TAG, "Adding splash screen window for "
+ + activityInfo.packageName + " / " + appToken + ": " + view);
+ }
+ final WindowManager wm = context.getSystemService(WindowManager.class);
+ postAddWindow(taskInfo.taskId, appToken, view, wm, params);
+ }
+
+ /**
+ * Called when the content of a task is ready to show, starting window can be removed.
+ */
+ public void removeStartingWindow(ActivityManager.RunningTaskInfo taskInfo) {
+ if (DEBUG_SPLASH_SCREEN) {
+ Slog.d(TAG, "Task start finish, remove starting surface for task " + taskInfo.taskId);
+ }
+ mHandler.post(() -> removeWindowSynced(taskInfo.taskId));
+ }
+
+ protected void postAddWindow(int taskId, IBinder appToken,
+ View view, WindowManager wm, WindowManager.LayoutParams params) {
+ mHandler.post(() -> {
+ boolean shouldSaveView = true;
+ try {
+ wm.addView(view, params);
+ } catch (WindowManager.BadTokenException e) {
+ // ignore
+ Slog.w(TAG, appToken + " already running, starting window not displayed. "
+ + e.getMessage());
+ shouldSaveView = false;
+ } catch (RuntimeException e) {
+ // don't crash if something else bad happens, for example a
+ // failure loading resources because we are loading from an app
+ // on external storage that has been unmounted.
+ Slog.w(TAG, appToken + " failed creating starting window", e);
+ shouldSaveView = false;
+ } finally {
+ if (view != null && view.getParent() == null) {
+ Slog.w(TAG, "view not successfully added to wm, removing view");
+ wm.removeViewImmediate(view);
+ shouldSaveView = false;
+ }
+ }
+
+ if (shouldSaveView) {
+ removeWindowSynced(taskId);
+ mHandler.postDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+ final TaskScreenView tView = new TaskScreenView(view);
+ mTaskScreenViews.put(taskId, tView);
+ }
+ });
+ }
+
+ protected void removeWindowSynced(int taskId) {
+ final TaskScreenView preView = mTaskScreenViews.get(taskId);
+ if (preView != null) {
+ if (preView.mDecorView != null) {
+ if (DEBUG_SPLASH_SCREEN) {
+ Slog.v(TAG, "Removing splash screen window for task: " + taskId);
+ }
+ final WindowManager wm = preView.mDecorView.getContext()
+ .getSystemService(WindowManager.class);
+ wm.removeView(preView.mDecorView);
+ }
+ mTaskScreenViews.remove(taskId);
+ }
+ }
+
+ private void getWindowResFromContext(Context ctx, Consumer<TypedArray> consumer) {
+ final TypedArray a = ctx.obtainStyledAttributes(R.styleable.Window);
+ consumer.accept(a);
+ a.recycle();
+ }
+
+ /**
+ * Record the views in a starting window.
+ */
+ private static class TaskScreenView {
+ private final View mDecorView;
+
+ TaskScreenView(View decorView) {
+ mDecorView = decorView;
+ }
+ }
+
+ private void addSplashscreenContent(PhoneWindow win, Context ctx,
+ int splashscreenContentResId) {
+ if (splashscreenContentResId == 0) {
+ return;
+ }
+ final Drawable drawable = ctx.getDrawable(splashscreenContentResId);
+ if (drawable == null) {
+ return;
+ }
+
+ // We wrap this into a view so the system insets get applied to the drawable.
+ final View v = new View(ctx);
+ v.setBackground(drawable);
+ win.setContentView(v);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
index 8b2f6681554a..9e8330973b40 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidManifest.xml
@@ -32,8 +32,21 @@
<!-- Workaround grant runtime permission exception from b/152733071 -->
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
+ <!-- Force-stop test apps -->
+ <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
+ <!-- Control test app's media session -->
+ <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
<application>
<uses-library android:name="android.test.runner"/>
+
+ <service android:name=".NotificationListener"
+ android:exported="true"
+ android:label="WMShellTestsNotificationListenerService"
+ android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.notification.NotificationListenerService" />
+ </intent-filter>
+ </service>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
new file mode 100644
index 000000000000..ef0390fc2a73
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
@@ -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.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.content.ComponentName
+
+const val IME_WINDOW_NAME = "InputMethod"
+const val PIP_WINDOW_NAME = "PipMenuActivity"
+
+// Test App
+const val TEST_APP_PACKAGE_NAME = "com.android.wm.shell.flicker.testapp"
+// Test App > Pip Activity
+val TEST_APP_PIP_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRelative(
+ TEST_APP_PACKAGE_NAME, ".PipActivity")
+const val TEST_APP_PIP_ACTIVITY_LABEL = "PipApp"
+const val TEST_APP_PIP_ACTIVITY_WINDOW_NAME = "PipActivity"
+// Test App > Ime Activity
+val TEST_APP_IME_ACTIVITY_COMPONENT_NAME: ComponentName = ComponentName.createRelative(
+ TEST_APP_PACKAGE_NAME, ".ImeActivity")
+const val TEST_APP_IME_ACTIVITY_LABEL = "ImeApp"
+
+const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui" \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
index 99f824bb8341..75b55c1e6a9f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/FlickerTestBase.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker
+import android.content.pm.PackageManager
import android.os.RemoteException
import android.os.SystemClock
import android.platform.helpers.IAppHelper
@@ -41,6 +42,9 @@ abstract class FlickerTestBase {
val uiDevice by lazy {
UiDevice.getInstance(instrumentation)
}
+ val packageManager: PackageManager by lazy {
+ instrumentation.context.getPackageManager()
+ }
/**
* Build a test tag for the test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt
new file mode 100644
index 000000000000..51f7a18f60dd
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/NotificationListener.kt
@@ -0,0 +1,103 @@
+/*
+ * 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.wm.shell.flicker
+
+import android.service.notification.NotificationListenerService
+import android.service.notification.StatusBarNotification
+import android.util.Log
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
+
+class NotificationListener : NotificationListenerService() {
+ private val notifications: MutableMap<Any, StatusBarNotification> = mutableMapOf()
+
+ override fun onNotificationPosted(sbn: StatusBarNotification) {
+ if (DEBUG) Log.d(TAG, "onNotificationPosted: $sbn")
+ notifications[sbn.key] = sbn
+ }
+
+ override fun onNotificationRemoved(sbn: StatusBarNotification) {
+ if (DEBUG) Log.d(TAG, "onNotificationRemoved: $sbn")
+ notifications.remove(sbn.key)
+ }
+
+ override fun onListenerConnected() {
+ if (DEBUG) Log.d(TAG, "onListenerConnected")
+ instance = this
+ }
+
+ override fun onListenerDisconnected() {
+ if (DEBUG) Log.d(TAG, "onListenerDisconnected")
+ instance = null
+ notifications.clear()
+ }
+
+ companion object {
+ private const val DEBUG = false
+ private const val TAG = "WMShellFlickerTests_NotificationListener"
+
+ private const val CMD_NOTIFICATION_ALLOW_LISTENER = "cmd notification allow_listener %s"
+ private const val CMD_NOTIFICATION_DISALLOW_LISTENER =
+ "cmd notification disallow_listener %s"
+ private const val COMPONENT_NAME = "com.android.wm.shell.flicker/.NotificationListener"
+
+ private var instance: NotificationListener? = null
+
+ fun startNotificationListener(): Boolean {
+ if (instance != null) {
+ return true
+ }
+
+ runShellCommand(CMD_NOTIFICATION_ALLOW_LISTENER.format(COMPONENT_NAME))
+ return wait { instance != null }
+ }
+
+ fun stopNotificationListener(): Boolean {
+ if (instance == null) {
+ return true
+ }
+
+ runShellCommand(CMD_NOTIFICATION_DISALLOW_LISTENER.format(COMPONENT_NAME))
+ return wait { instance == null }
+ }
+
+ fun findNotification(
+ predicate: (StatusBarNotification) -> Boolean
+ ): StatusBarNotification? {
+ instance?.run {
+ return notifications.values.firstOrNull(predicate)
+ } ?: throw IllegalStateException("NotificationListenerService is not connected")
+ }
+
+ fun waitForNotificationToAppear(
+ predicate: (StatusBarNotification) -> Boolean
+ ): StatusBarNotification? {
+ instance?.let {
+ return waitForResult(extractor = {
+ it.notifications.values.firstOrNull(predicate)
+ }).second
+ } ?: throw IllegalStateException("NotificationListenerService is not connected")
+ }
+
+ fun waitForNotificationToDisappear(
+ predicate: (StatusBarNotification) -> Boolean
+ ): Boolean {
+ return instance?.let {
+ wait { it.notifications.values.none(predicate) }
+ } ?: throw IllegalStateException("NotificationListenerService is not connected")
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt
new file mode 100644
index 000000000000..a6d67355f271
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/WaitUtils.kt
@@ -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.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.os.SystemClock
+
+private const val DEFAULT_TIMEOUT = 10000L
+private const val DEFAULT_POLL_INTERVAL = 1000L
+
+fun wait(condition: () -> Boolean): Boolean {
+ val (success, _) = waitForResult(extractor = condition, validator = { it })
+ return success
+}
+
+fun <R> waitForResult(
+ timeout: Long = DEFAULT_TIMEOUT,
+ interval: Long = DEFAULT_POLL_INTERVAL,
+ extractor: () -> R,
+ validator: (R) -> Boolean = { it != null }
+): Pair<Boolean, R?> {
+ val startTime = SystemClock.uptimeMillis()
+ do {
+ val result = extractor()
+ if (validator(result)) {
+ return (true to result)
+ }
+ SystemClock.sleep(interval)
+ } while (SystemClock.uptimeMillis() - startTime < timeout)
+
+ return (false to null)
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
new file mode 100644
index 000000000000..4ab5c6a20005
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
@@ -0,0 +1,90 @@
+/*
+ * 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.wm.shell.flicker.helpers
+
+import android.app.ActivityManager
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager.FEATURE_LEANBACK
+import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.wm.shell.flicker.TEST_APP_PACKAGE_NAME
+
+abstract class BaseAppHelper(
+ instrumentation: Instrumentation,
+ launcherName: String,
+ private val launcherActivityComponent: ComponentName
+) : StandardAppHelper(
+ instrumentation,
+ TEST_APP_PACKAGE_NAME,
+ launcherName,
+ LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy
+) {
+ protected val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
+
+ protected val context: Context
+ get() = mInstrumentation.context
+
+ private val activityManager: ActivityManager?
+ get() = context.getSystemService(ActivityManager::class.java)
+
+ private val appSelector = By.pkg(packageName).depth(0)
+
+ protected val isTelevision: Boolean
+ get() = context.packageManager.run {
+ hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY)
+ }
+
+ val label: String
+ get() = context.packageManager.run {
+ getApplicationLabel(getApplicationInfo(packageName, 0)).toString()
+ }
+
+ val ui: UiObject2?
+ get() = uiDevice.findObject(appSelector)
+
+ fun launchViaIntent() {
+ context.startActivity(openAppIntent)
+
+ uiDevice.wait(Until.hasObject(appSelector), APP_LAUNCH_WAIT_TIME_MS)
+ }
+
+ fun waitUntilClosed(): Boolean {
+ return uiDevice.wait(Until.gone(appSelector), APP_CLOSE_WAIT_TIME_MS)
+ }
+
+ fun forceStop() = activityManager?.forceStopPackage(packageName)
+
+ override fun getOpenAppIntent(): Intent {
+ val intent = Intent()
+ intent.component = launcherActivityComponent
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ return intent
+ }
+
+ companion object {
+ private const val APP_LAUNCH_WAIT_TIME_MS = 10_000L
+ private const val APP_CLOSE_WAIT_TIME_MS = 3_000L
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
index 0cedc0a7147f..a6650d7f13d1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
@@ -17,37 +17,36 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
import androidx.test.uiautomator.By
-import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
import com.android.server.wm.flicker.helpers.waitForIME
+import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_COMPONENT_NAME
+import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_LABEL
import org.junit.Assert
open class ImeAppHelper(
- instr: Instrumentation,
- launcherName: String = "ImeApp",
- launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
- .getInstance(instr)
- .launcherStrategy
-) : FlickerAppHelper(instr, launcherName, launcherStrategy) {
- open fun openIME(device: UiDevice) {
- val editText = device.wait(
+ instrumentation: Instrumentation
+) : BaseAppHelper(
+ instrumentation,
+ TEST_APP_IME_ACTIVITY_LABEL,
+ TEST_APP_IME_ACTIVITY_COMPONENT_NAME
+) {
+ fun openIME() {
+ val editText = uiDevice.wait(
Until.findObject(By.res(getPackage(), "plain_text_input")),
FIND_TIMEOUT)
Assert.assertNotNull("Text field not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)", editText)
editText.click()
- if (!device.waitForIME()) {
+ if (!uiDevice.waitForIME()) {
Assert.fail("IME did not appear")
}
}
- open fun closeIME(device: UiDevice) {
- device.pressBack()
+ fun closeIME() {
+ uiDevice.pressBack()
// Using only the AccessibilityInfo it is not possible to identify if the IME is active
- device.waitForIdle(1000)
+ uiDevice.waitForIdle(1000)
}
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index 539170202b8a..42686e7e87d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -17,29 +17,79 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
+import android.media.session.MediaController
+import android.media.session.MediaSessionManager
+import android.os.SystemClock
+import android.view.KeyEvent.KEYCODE_WINDOW
import androidx.test.uiautomator.By
-import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.helpers.hasPipWindow
+import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.closePipWindow
-import org.junit.Assert
+import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
+import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_COMPONENT_NAME
+import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_LABEL
+import org.junit.Assert.assertNotNull
class PipAppHelper(
- instr: Instrumentation,
- launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
- .getInstance(instr)
- .launcherStrategy
-) : FlickerAppHelper(instr, "PipApp", launcherStrategy) {
- fun clickEnterPipButton(device: UiDevice) {
- val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"))
- Assert.assertNotNull("Pip button not found, this usually happens when the device " +
+ instrumentation: Instrumentation
+) : BaseAppHelper(
+ instrumentation,
+ TEST_APP_PIP_ACTIVITY_LABEL,
+ TEST_APP_PIP_ACTIVITY_COMPONENT_NAME
+) {
+ private val mediaSessionManager: MediaSessionManager
+ get() = context.getSystemService(MediaSessionManager::class.java)
+ ?: error("Could not get MediaSessionManager")
+
+ private val mediaController: MediaController?
+ get() = mediaSessionManager.getActiveSessions(null).firstOrNull {
+ it.packageName == packageName
+ }
+
+ fun clickEnterPipButton() {
+ val enterPipButton = uiDevice.findObject(By.res(packageName, "enter_pip"))
+ assertNotNull("Pip button not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)", enterPipButton)
enterPipButton.click()
- device.hasPipWindow()
+
+ // TODO(b/172321238): remove this check once hasPipWindow is fixed on TVs
+ if (!isTelevision) {
+ uiDevice.hasPipWindow()
+ } else {
+ // Simply wait for 3 seconds
+ SystemClock.sleep(3_000)
+ }
}
- fun closePipWindow(device: UiDevice) {
- device.closePipWindow()
+ fun clickStartMediaSessionButton() {
+ val startButton = uiDevice.findObject(By.res(packageName, "media_session_start"))
+ assertNotNull("Start button not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)", startButton)
+ startButton.click()
+ }
+
+ fun pauseMedia() = mediaController?.transportControls?.pause()
+ ?: error("No active media session found")
+
+ fun stopMedia() = mediaController?.transportControls?.stop()
+ ?: error("No active media session found")
+
+ fun closePipWindow() {
+ // TODO(b/172321238): remove this check once and simply call closePipWindow once the TV
+ // logic is integrated there.
+ if (!isTelevision) {
+ uiDevice.closePipWindow()
+ } else {
+ // Bring up Pip menu
+ uiDevice.pressKeyCode(KEYCODE_WINDOW)
+
+ // Wait for the menu to come up and render the close button
+ val closeButton = uiDevice.wait(
+ Until.findObject(By.res(SYSTEM_UI_PACKAGE_NAME, "close_button")), 3_000)
+ assertNotNull("Pip menu close button is not found", closeButton)
+ closeButton.click()
+
+ waitUntilClosed()
+ }
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 010aa0d7d832..a1da7c939f60 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -31,6 +31,7 @@ import com.android.wm.shell.flicker.noUncoveredRegions
import com.android.wm.shell.flicker.statusBarLayerIsAlwaysVisible
import com.android.wm.shell.flicker.statusBarLayerRotatesScales
import com.android.wm.shell.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.PIP_WINDOW_NAME
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -79,7 +80,7 @@ class EnterPipTest(
}
}
transitions {
- testApp.clickEnterPipButton(device)
+ testApp.clickEnterPipButton()
device.expandPipWindow()
}
assertions {
@@ -89,7 +90,7 @@ class EnterPipTest(
all("pipWindowBecomesVisible") {
this.showsAppWindow(testApp.`package`)
.then()
- .showsAppWindow(sPipWindowTitle)
+ .showsAppWindow(PIP_WINDOW_NAME)
}
}
@@ -103,7 +104,7 @@ class EnterPipTest(
all("pipLayerBecomesVisible") {
this.showsLayer(testApp.launcherName)
.then()
- .showsLayer(sPipWindowTitle)
+ .showsLayer(PIP_WINDOW_NAME)
}
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 43e022538685..d343f2a7093b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -18,7 +18,6 @@ package com.android.wm.shell.flicker.pip
import android.content.ComponentName
import android.graphics.Region
-import android.support.test.launcherhelper.LauncherStrategyFactory
import android.util.Log
import android.view.Surface
import android.view.WindowManager
@@ -29,6 +28,9 @@ import com.android.server.wm.flicker.dsl.runWithFlicker
import com.android.server.wm.flicker.helpers.closePipWindow
import com.android.server.wm.flicker.helpers.hasPipWindow
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_COMPONENT_NAME
+import com.android.wm.shell.flicker.IME_WINDOW_NAME
+import com.android.wm.shell.flicker.TEST_APP_PIP_ACTIVITY_WINDOW_NAME
import com.android.wm.shell.flicker.helpers.ImeAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -51,19 +53,11 @@ class PipKeyboardTest(
private val windowManager: WindowManager =
instrumentation.context.getSystemService(WindowManager::class.java)
- private val keyboardApp = ImeAppHelper(instrumentation, "ImeApp",
- LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy)
-
- private val KEYBOARD_ACTIVITY: ComponentName = ComponentName.createRelative(
- "com.android.wm.shell.flicker.testapp", ".ImeActivity")
- private val PIP_ACTIVITY_WINDOW_NAME = "PipActivity"
- private val INPUT_METHOD_WINDOW_NAME = "InputMethod"
-
- private val testRepetitions = 10
+ private val keyboardApp = ImeAppHelper(instrumentation)
private val keyboardScenario: FlickerBuilder
get() = FlickerBuilder(instrumentation).apply {
- repeat { testRepetitions }
+ repeat { TEST_REPETITIONS }
// disable layer tracing
withLayerTracing { null }
setup {
@@ -73,11 +67,11 @@ class PipKeyboardTest(
// launch our target pip app
testApp.open()
this.setRotation(rotation)
- testApp.clickEnterPipButton(device)
+ testApp.clickEnterPipButton()
// open an app with an input field and a keyboard
// UiAutomator doesn't support to launch the multiple Activities in a task.
// So use launchActivity() for the Keyboard Activity.
- launchActivity(KEYBOARD_ACTIVITY)
+ launchActivity(TEST_APP_IME_ACTIVITY_COMPONENT_NAME)
}
}
teardown {
@@ -101,10 +95,10 @@ class PipKeyboardTest(
withTestName { testTag }
transitions {
// open the soft keyboard
- keyboardApp.openIME(device)
+ keyboardApp.openIME()
// then close it again
- keyboardApp.closeIME(device)
+ keyboardApp.closeIME()
}
assertions {
windowManagerTrace {
@@ -127,18 +121,18 @@ class PipKeyboardTest(
withTestName { testTag }
transitions {
// open the soft keyboard
- keyboardApp.openIME(device)
+ keyboardApp.openIME()
}
teardown {
eachRun {
// close the keyboard
- keyboardApp.closeIME(device)
+ keyboardApp.closeIME()
}
}
assertions {
windowManagerTrace {
end {
- isAboveWindow(INPUT_METHOD_WINDOW_NAME, PIP_ACTIVITY_WINDOW_NAME)
+ isAboveWindow(IME_WINDOW_NAME, TEST_APP_PIP_ACTIVITY_WINDOW_NAME)
}
}
}
@@ -207,6 +201,8 @@ class PipKeyboardTest(
}
companion object {
+ private const val TEST_REPETITIONS = 10
+
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<Array<Any>> {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
index 3822d69a65f5..c1c34ecfbaec 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTestBase.kt
@@ -24,8 +24,4 @@ abstract class PipTestBase(
rotation: Int
) : NonRotationTestBase(rotationName, rotation) {
protected val testApp = PipAppHelper(instrumentation)
-
- companion object {
- const val sPipWindowTitle = "PipMenuActivity"
- }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
new file mode 100644
index 000000000000..728cc510a79b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
@@ -0,0 +1,153 @@
+/*
+ * 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.wm.shell.flicker.pip.tv
+
+import androidx.test.filters.RequiresDevice
+import androidx.test.uiautomator.UiObject2
+import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
+import com.android.wm.shell.flicker.wait
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip Menu on TV.
+ * To run this test: `atest WMShellFlickerTests:TvPipMenuTests`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+class TvPipMenuTests(rotationName: String, rotation: Int)
+ : TvPipTestBase(rotationName, rotation) {
+
+ private val systemUiResources =
+ packageManager.getResourcesForApplication(SYSTEM_UI_PACKAGE_NAME)
+ private val playButtonDescription = systemUiResources.run {
+ getString(getIdentifier("pip_play", "string", SYSTEM_UI_PACKAGE_NAME))
+ }
+ private val pauseButtonDescription = systemUiResources.run {
+ getString(getIdentifier("pip_pause", "string", SYSTEM_UI_PACKAGE_NAME))
+ }
+
+ @Before
+ override fun setUp() {
+ super.setUp()
+ // Launch the app and go to PiP
+ testApp.launchViaIntent()
+ }
+
+ @Test
+ fun pipMenu_open() {
+ val pipMenu = enterPip_openMenu_assertShown()
+
+ // Make sure it's fullscreen
+ assertTrue("Pip menu should be shown fullscreen", pipMenu.isFullscreen(uiDevice))
+
+ testApp.closePipWindow()
+ }
+
+ @Test
+ fun pipMenu_backButton() {
+ enterPip_openMenu_assertShown()
+
+ // Pressing the Back key should close the Pip menu
+ uiDevice.pressBack()
+ assertTrue("Pip menu should have closed", uiDevice.waitForTvPipMenuToClose())
+
+ testApp.closePipWindow()
+ }
+
+ @Test
+ fun pipMenu_homeButton() {
+ enterPip_openMenu_assertShown()
+
+ // Pressing the Home key should close the Pip menu
+ uiDevice.pressHome()
+ assertTrue("Pip menu should have closed", uiDevice.waitForTvPipMenuToClose())
+
+ testApp.closePipWindow()
+ }
+
+ @Test
+ fun pipMenu_closeButton() {
+ enterPip_openMenu_assertShown()
+
+ // PiP menu should contain the Close button
+ val closeButton = uiDevice.findTvPipMenuCloseButton()
+ ?: fail("\"Close PIP\" button should be shown in Pip menu")
+
+ // Clicking on the Close button should close the app
+ closeButton.click()
+ assertTrue("\"Close PIP\" button should close the PiP", testApp.waitUntilClosed())
+ }
+
+ @Test
+ fun pipMenu_fullscreenButton() {
+ enterPip_openMenu_assertShown()
+
+ // PiP menu should contain the Fullscreen button
+ val fullscreenButton = uiDevice.findTvPipMenuFullscreenButton()
+ ?: fail("\"Full screen\" button should be shown in Pip menu")
+
+ // Clicking on the fullscreen button should return app to the fullscreen mode.
+ // Click, wait for the app to go fullscreen
+ fullscreenButton.click()
+ assertTrue("\"Full screen\" button should open the app fullscreen",
+ wait { testApp.ui?.isFullscreen(uiDevice) ?: false })
+
+ // Close the app
+ uiDevice.pressBack()
+ testApp.waitUntilClosed()
+ }
+
+ @Test
+ fun pipMenu_mediaPlayPauseButtons() {
+ // Start media session before entering PiP
+ testApp.clickStartMediaSessionButton()
+
+ enterPip_openMenu_assertShown()
+
+ // PiP menu should contain the Pause button
+ val pauseButton = uiDevice.findTvPipMenuElementWithDescription(pauseButtonDescription)
+ ?: fail("\"Pause\" button should be shown in Pip menu if there is an active " +
+ "playing media session.")
+
+ // When we pause media, the button should change from Pause to Play
+ pauseButton.click()
+
+ // PiP menu should contain the Play button now
+ uiDevice.waitForTvPipMenuElementWithDescription(playButtonDescription)
+ ?: fail("\"Play\" button should be shown in Pip menu if there is an active " +
+ "paused media session.")
+
+ testApp.closePipWindow()
+ }
+
+ private fun enterPip_openMenu_assertShown(): UiObject2 {
+ testApp.clickEnterPipButton()
+ // Pressing the Window key should bring up Pip menu
+ uiDevice.pressWindowKey()
+ return uiDevice.waitForTvPipMenu() ?: fail("Pip menu should have been shown")
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> = rotationParams
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
new file mode 100644
index 000000000000..7a9b33b46742
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt
@@ -0,0 +1,183 @@
+/*
+ * 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.wm.shell.flicker.pip.tv
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.os.Bundle
+import android.service.notification.StatusBarNotification
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.NotificationListener.Companion.findNotification
+import com.android.wm.shell.flicker.NotificationListener.Companion.startNotificationListener
+import com.android.wm.shell.flicker.NotificationListener.Companion.stopNotificationListener
+import com.android.wm.shell.flicker.NotificationListener.Companion.waitForNotificationToAppear
+import com.android.wm.shell.flicker.NotificationListener.Companion.waitForNotificationToDisappear
+import org.junit.After
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip Notifications on TV.
+ * To run this test: `atest WMShellFlickerTests:TvPipNotificationTests`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+class TvPipNotificationTests(rotationName: String, rotation: Int)
+ : TvPipTestBase(rotationName, rotation) {
+
+ @Before
+ override fun setUp() {
+ super.setUp()
+ val started = startNotificationListener()
+ if (!started) {
+ error("NotificationListener hasn't started")
+ }
+ }
+
+ @After
+ override fun tearDown() {
+ stopNotificationListener()
+ super.tearDown()
+ }
+
+ @Test
+ fun pipNotification_postedAndDismissed() {
+ testApp.launchViaIntent()
+ testApp.clickEnterPipButton()
+
+ assertNotNull("Pip notification should have been posted",
+ waitForNotificationToAppear { it.isPipNotificationWithTitle(testApp.label) })
+
+ testApp.closePipWindow()
+
+ assertTrue("Pip notification should have been dismissed",
+ waitForNotificationToDisappear { it.isPipNotificationWithTitle(testApp.label) })
+ }
+
+ @Test
+ fun pipNotification_closeIntent() {
+ testApp.launchViaIntent()
+ testApp.clickEnterPipButton()
+
+ val notification: StatusBarNotification = waitForNotificationToAppear {
+ it.isPipNotificationWithTitle(testApp.label)
+ } ?: fail("Pip notification should have been posted")
+
+ notification.deleteIntent?.send()
+ ?: fail("Pip notification should contain `delete_intent`")
+
+ assertTrue("Pip should have closed by sending the `delete_intent`",
+ testApp.waitUntilClosed())
+ assertTrue("Pip notification should have been dismissed",
+ waitForNotificationToDisappear { it.isPipNotificationWithTitle(testApp.label) })
+ }
+
+ @Test
+ fun pipNotification_menuIntent() {
+ testApp.launchViaIntent()
+ testApp.clickEnterPipButton()
+
+ val notification: StatusBarNotification = waitForNotificationToAppear {
+ it.isPipNotificationWithTitle(testApp.label)
+ } ?: fail("Pip notification should have been posted")
+
+ notification.contentIntent?.send()
+ ?: fail("Pip notification should contain `content_intent`")
+
+ assertNotNull("Pip menu should have been shown after sending `content_intent`",
+ uiDevice.waitForTvPipMenu())
+
+ uiDevice.pressBack()
+ testApp.closePipWindow()
+ }
+
+ @Test
+ fun pipNotification_mediaSessionTitle_isDisplayed() {
+ testApp.launchViaIntent()
+ // Start media session and to PiP
+ testApp.clickStartMediaSessionButton()
+ testApp.clickEnterPipButton()
+
+ // Wait for the correct notification to show up...
+ waitForNotificationToAppear {
+ it.isPipNotificationWithTitle(TITLE_MEDIA_SESSION_PLAYING)
+ } ?: fail("Pip notification with media session title should have been posted")
+ // ... and make sure "regular" PiP notification is now shown
+ assertNull("Regular notification should not have been posted",
+ findNotification { it.isPipNotificationWithTitle(testApp.label) })
+
+ // Pause the media session. When paused the application updates the title for the media
+ // session. This change should be reflected in the notification.
+ testApp.pauseMedia()
+
+ // Wait for the "paused" notification to show up...
+ waitForNotificationToAppear {
+ it.isPipNotificationWithTitle(TITLE_MEDIA_SESSION_PAUSED)
+ } ?: fail("Pip notification with media session title should have been posted")
+ // ... and make sure "playing" PiP notification is gone
+ assertNull("Regular notification should not have been posted",
+ findNotification { it.isPipNotificationWithTitle(TITLE_MEDIA_SESSION_PLAYING) })
+
+ // Now stop the media session, which should revert the title to the "default" one.
+ testApp.stopMedia()
+
+ // Wait for the "regular" notification to show up...
+ waitForNotificationToAppear {
+ it.isPipNotificationWithTitle(testApp.label)
+ } ?: fail("Pip notification with media session title should have been posted")
+ // ... and make sure previous ("paused") notification is gone
+ assertNull("Regular notification should not have been posted",
+ findNotification { it.isPipNotificationWithTitle(TITLE_MEDIA_SESSION_PAUSED) })
+
+ testApp.closePipWindow()
+ }
+
+ companion object {
+ private const val TITLE_MEDIA_SESSION_PLAYING = "TestApp media is playing"
+ private const val TITLE_MEDIA_SESSION_PAUSED = "TestApp media is paused"
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> = rotationParams
+ }
+}
+
+private val StatusBarNotification.extras: Bundle?
+ get() = notification?.extras
+
+private val StatusBarNotification.title: String
+ get() = extras?.getString(Notification.EXTRA_TITLE) ?: ""
+
+/** Get TV extensions with [android.app.Notification.TvExtender.EXTRA_TV_EXTENDER]. */
+private val StatusBarNotification.tvExtensions: Bundle?
+ get() = extras?.getBundle("android.tv.EXTENSIONS")
+
+/** "Content" TV intent with key [android.app.Notification.TvExtender.EXTRA_CONTENT_INTENT]. */
+private val StatusBarNotification.contentIntent: PendingIntent?
+ get() = tvExtensions?.getParcelable("content_intent")
+
+/** "Delete" TV intent with key [android.app.Notification.TvExtender.EXTRA_DELETE_INTENT]. */
+private val StatusBarNotification.deleteIntent: PendingIntent?
+ get() = tvExtensions?.getParcelable("delete_intent")
+
+private fun StatusBarNotification.isPipNotificationWithTitle(expectedTitle: String): Boolean =
+ tag == "PipNotification" && title == expectedTitle \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
new file mode 100644
index 000000000000..d4acae50911b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
@@ -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.
+ */
+
+package com.android.wm.shell.flicker.pip.tv
+
+import android.app.ActivityManager
+import android.app.IActivityManager
+import android.app.IProcessObserver
+import android.content.pm.PackageManager.FEATURE_LEANBACK
+import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
+import android.os.SystemClock
+import android.view.Surface.ROTATION_0
+import android.view.Surface.rotationToString
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
+import com.android.wm.shell.flicker.pip.PipTestBase
+import org.junit.After
+import org.junit.Assert.assertFalse
+import org.junit.Assume
+import org.junit.Before
+
+abstract class TvPipTestBase(rotationName: String, rotation: Int)
+ : PipTestBase(rotationName, rotation) {
+
+ private val isTelevision: Boolean
+ get() = packageManager.run {
+ hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY)
+ }
+ private val systemUiProcessObserver = SystemUiProcessObserver()
+
+ @Before
+ open fun setUp() {
+ Assume.assumeTrue(isTelevision)
+
+ systemUiProcessObserver.start()
+
+ uiDevice.wakeUpAndGoToHomeScreen()
+ }
+
+ @After
+ open fun tearDown() {
+ if (!isTelevision) return
+
+ testApp.forceStop()
+
+ // Wait for 1 second, and check if the SystemUI has been alive and well since the start.
+ SystemClock.sleep(AFTER_TEXT_PROCESS_CHECK_DELAY)
+ systemUiProcessObserver.stop()
+ assertFalse("SystemUI has died during test execution", systemUiProcessObserver.hasDied)
+ }
+
+ protected fun fail(message: String): Nothing = throw AssertionError(message)
+
+ inner class SystemUiProcessObserver : IProcessObserver.Stub() {
+ private val activityManager: IActivityManager = ActivityManager.getService()
+ private val uiAutomation = instrumentation.uiAutomation
+ private val systemUiUid = packageManager.getPackageUid(SYSTEM_UI_PACKAGE_NAME, 0)
+ var hasDied: Boolean = false
+
+ fun start() {
+ hasDied = false
+ uiAutomation.adoptShellPermissionIdentity(
+ android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ activityManager.registerProcessObserver(this)
+ }
+
+ fun stop() {
+ activityManager.unregisterProcessObserver(this)
+ uiAutomation.dropShellPermissionIdentity()
+ }
+
+ override fun onForegroundActivitiesChanged(pid: Int, uid: Int, foreground: Boolean) {}
+
+ override fun onForegroundServicesChanged(pid: Int, uid: Int, serviceTypes: Int) {}
+
+ override fun onProcessDied(pid: Int, uid: Int) {
+ if (uid == systemUiUid) hasDied = true
+ }
+ }
+
+ companion object {
+ private const val AFTER_TEXT_PROCESS_CHECK_DELAY = 1_000L // 1 sec
+
+ @JvmStatic
+ protected val rotationParams: Collection<Array<Any>> =
+ listOf(arrayOf(rotationToString(ROTATION_0), ROTATION_0))
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
new file mode 100644
index 000000000000..8db8bc67da14
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.wm.shell.flicker.pip.tv
+
+import android.view.KeyEvent
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
+import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
+
+/** Id of the root view in the com.android.wm.shell.pip.tv.PipMenuActivity */
+private const val TV_PIP_MENU_ROOT_ID = "tv_pip_menu"
+private const val TV_PIP_MENU_CLOSE_BUTTON_ID = "close_button"
+private const val TV_PIP_MENU_FULLSCREEN_BUTTON_ID = "full_button"
+
+private const val WAIT_TIME_MS = 3_000L
+
+private val tvPipMenuSelector = By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_ROOT_ID)
+
+fun UiDevice.pressWindowKey() = pressKeyCode(KeyEvent.KEYCODE_WINDOW)
+
+fun UiDevice.waitForTvPipMenu(): UiObject2? =
+ wait(Until.findObject(tvPipMenuSelector), WAIT_TIME_MS)
+
+fun UiDevice.waitForTvPipMenuToClose(): Boolean = wait(Until.gone(tvPipMenuSelector), WAIT_TIME_MS)
+
+fun UiDevice.findTvPipMenuCloseButton(): UiObject2? = findObject(
+ By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_CLOSE_BUTTON_ID))
+
+fun UiDevice.findTvPipMenuFullscreenButton(): UiObject2? = findObject(
+ By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_FULLSCREEN_BUTTON_ID))
+
+fun UiDevice.findTvPipMenuElementWithDescription(desc: String): UiObject2? {
+ val buttonSelector = By.desc(desc)
+ val menuWithButtonSelector = By.copy(tvPipMenuSelector).hasDescendant(buttonSelector)
+ return findObject(menuWithButtonSelector)?.findObject(buttonSelector)
+}
+
+fun UiDevice.waitForTvPipMenuElementWithDescription(desc: String): UiObject2? {
+ val buttonSelector = By.desc(desc)
+ val menuWithButtonSelector = By.copy(tvPipMenuSelector).hasDescendant(buttonSelector)
+ return wait(Until.findObject(menuWithButtonSelector), WAIT_TIME_MS)
+ ?.findObject(buttonSelector)
+}
+
+fun UiObject2.isFullscreen(uiDevice: UiDevice): Boolean = visibleBounds.run {
+ height() == uiDevice.displayHeight && width() == uiDevice.displayWidth
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
index e1870d9c523d..0e79d03cc3ee 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_pip.xml
@@ -18,9 +18,36 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:orientation="vertical"
android:background="@android:color/holo_blue_bright">
- <Button android:layout_width="wrap_content"
+
+ <Button
+ android:id="@+id/enter_pip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Enter PIP"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Media Session"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <Button
+ android:id="@+id/media_session_start"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:id="@+id/enter_pip"
- android:text="Enter PIP"/>
+ android:text="Start"/>
+
+ <Button
+ android:id="@+id/media_session_stop"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Stop"/>
+
+ </LinearLayout>
+
</LinearLayout>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
index 305281691e11..b60068a60b34 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/PipActivity.java
@@ -16,30 +16,114 @@
package com.android.wm.shell.flicker.testapp;
+import static android.media.MediaMetadata.METADATA_KEY_TITLE;
+import static android.media.session.PlaybackState.ACTION_PAUSE;
+import static android.media.session.PlaybackState.ACTION_PLAY;
+import static android.media.session.PlaybackState.ACTION_STOP;
+import static android.media.session.PlaybackState.STATE_PAUSED;
+import static android.media.session.PlaybackState.STATE_PLAYING;
+import static android.media.session.PlaybackState.STATE_STOPPED;
+
import android.app.Activity;
import android.app.PictureInPictureParams;
import android.graphics.Rect;
+import android.media.MediaMetadata;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
import android.os.Bundle;
import android.util.Rational;
+import android.view.Window;
import android.view.WindowManager;
-import android.widget.Button;
public class PipActivity extends Activity {
+ /**
+ * A media session title for when the session is in {@link STATE_PLAYING}.
+ * TvPipNotificationTests check whether the actual notification title matches this string.
+ */
+ private static final String TITLE_STATE_PLAYING = "TestApp media is playing";
+ /**
+ * A media session title for when the session is in {@link STATE_PAUSED}.
+ * TvPipNotificationTests check whether the actual notification title matches this string.
+ */
+ private static final String TITLE_STATE_PAUSED = "TestApp media is paused";
+
+ private MediaSession mMediaSession;
+ private final PlaybackState.Builder mPlaybackStateBuilder = new PlaybackState.Builder()
+ .setActions(ACTION_PLAY | ACTION_PAUSE | ACTION_STOP)
+ .setState(STATE_STOPPED, 0, 1f);
+ private PlaybackState mPlaybackState = mPlaybackStateBuilder.build();
+ private final MediaMetadata.Builder mMediaMetadataBuilder = new MediaMetadata.Builder();
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- WindowManager.LayoutParams p = getWindow().getAttributes();
- p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+
+ final Window window = getWindow();
+ final WindowManager.LayoutParams layoutParams = window.getAttributes();
+ layoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams
.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
- getWindow().setAttributes(p);
+ window.setAttributes(layoutParams);
+
setContentView(R.layout.activity_pip);
- Button enterPip = (Button) findViewById(R.id.enter_pip);
- PictureInPictureParams params = new PictureInPictureParams.Builder()
+ final PictureInPictureParams pipParams = new PictureInPictureParams.Builder()
.setAspectRatio(new Rational(1, 1))
.setSourceRectHint(new Rect(0, 0, 100, 100))
.build();
+ findViewById(R.id.enter_pip).setOnClickListener(v -> enterPictureInPictureMode(pipParams));
+
+ findViewById(R.id.media_session_start)
+ .setOnClickListener(v -> updateMediaSessionState(STATE_PLAYING));
+ findViewById(R.id.media_session_stop)
+ .setOnClickListener(v -> updateMediaSessionState(STATE_STOPPED));
+
+ mMediaSession = new MediaSession(this, "WMShell_TestApp");
+ mMediaSession.setPlaybackState(mPlaybackStateBuilder.build());
+ mMediaSession.setCallback(new MediaSession.Callback() {
+ @Override
+ public void onPlay() {
+ updateMediaSessionState(STATE_PLAYING);
+ }
+
+ @Override
+ public void onPause() {
+ updateMediaSessionState(STATE_PAUSED);
+ }
+
+ @Override
+ public void onStop() {
+ updateMediaSessionState(STATE_STOPPED);
+ }
+ });
+ }
+
+ private void updateMediaSessionState(int newState) {
+ if (mPlaybackState.getState() == newState) {
+ return;
+ }
+ final String title;
+ switch (newState) {
+ case STATE_PLAYING:
+ title = TITLE_STATE_PLAYING;
+ break;
+ case STATE_PAUSED:
+ title = TITLE_STATE_PAUSED;
+ break;
+ case STATE_STOPPED:
+ title = "";
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown state " + newState);
+ }
+
+ mPlaybackStateBuilder.setState(newState, 0, 1f);
+ mPlaybackState = mPlaybackStateBuilder.build();
+
+ mMediaMetadataBuilder.putText(METADATA_KEY_TITLE, title);
- enterPip.setOnClickListener((v) -> enterPictureInPictureMode(params));
+ mMediaSession.setPlaybackState(mPlaybackState);
+ mMediaSession.setMetadata(mMediaMetadataBuilder.build());
+ mMediaSession.setActive(newState != STATE_STOPPED);
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index 9940ea575873..dca27328f192 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -30,6 +30,7 @@ android_test {
"mockito-target-extended-minus-junit4",
"truth-prebuilt",
"testables",
+ "platform-test-annotations",
],
libs: [
diff --git a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
index a8f795ec8a8d..59d9104fb5ba 100644
--- a/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/unittest/AndroidManifest.xml
@@ -22,6 +22,13 @@
<application android:debuggable="true" android:largeHeap="true">
<uses-library android:name="android.test.mock" />
<uses-library android:name="android.test.runner" />
+
+ <activity android:name=".bubbles.BubblesTestActivity"
+ android:allowEmbedded="true"
+ android:documentLaunchMode="always"
+ android:excludeFromRecents="true"
+ android:exported="false"
+ android:resizeableActivity="true" />
</application>
<instrumentation
diff --git a/libs/WindowManager/Shell/tests/unittest/res/layout/main.xml b/libs/WindowManager/Shell/tests/unittest/res/layout/main.xml
new file mode 100644
index 000000000000..0d09f868126e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/res/layout/main.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="this is a test activity"
+ />
+ <EditText
+ android:layout_height="wrap_content"
+ android:id="@+id/editText1"
+ android:layout_width="match_parent">
+ <requestFocus></requestFocus>
+ </EditText>
+</LinearLayout>
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index e4155a257cee..fdf4d31f0281 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -36,6 +36,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.graphics.Rect;
import android.os.Binder;
@@ -71,6 +72,8 @@ public class ShellTaskOrganizerTests {
@Mock
private ITaskOrganizerController mTaskOrganizerController;
+ @Mock
+ private Context mContext;
ShellTaskOrganizer mOrganizer;
private final SyncTransactionQueue mSyncTransactionQueue = mock(SyncTransactionQueue.class);
@@ -106,7 +109,7 @@ public class ShellTaskOrganizerTests {
.when(mTaskOrganizerController).registerTaskOrganizer(any());
} catch (RemoteException e) {}
mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mSyncTransactionQueue,
- mTransactionPool, mTestExecutor, mTestExecutor));
+ mTransactionPool, mTestExecutor, mTestExecutor, mContext));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
index fdebe4e4e6f5..5bdf831a81f4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.pip;
+package com.android.wm.shell;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -24,17 +24,18 @@ import android.testing.TestableContext;
import androidx.test.InstrumentationRegistry;
+import org.junit.After;
import org.junit.Before;
/**
- * Base class that does One Handed specific setup.
+ * Base class that does shell test case setup.
*/
-public abstract class PipTestCase {
+public abstract class ShellTestCase {
protected TestableContext mContext;
@Before
- public void setup() {
+ public void shellSetup() {
final Context context =
InstrumentationRegistry.getInstrumentation().getTargetContext();
final DisplayManager dm = context.getSystemService(DisplayManager.class);
@@ -47,6 +48,14 @@ public abstract class PipTestCase {
.adoptShellPermissionIdentity();
}
+ @After
+ public void shellTearDown() {
+ InstrumentationRegistry
+ .getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+
protected Context getContext() {
return mContext;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
index 5c148598f10a..34f772faf9a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TaskViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -30,7 +30,6 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -45,8 +44,6 @@ import android.window.WindowContainerToken;
import androidx.test.filters.SmallTest;
-import com.android.systemui.SysuiTestCase;
-import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.HandlerExecutor;
import org.junit.After;
@@ -60,8 +57,7 @@ import org.mockito.invocation.InvocationOnMock;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-// TODO: Place in com.android.wm.shell vs. com.android.wm.shell.bubbles on shell migration.
-public class TaskViewTest extends SysuiTestCase {
+public class TaskViewTest extends ShellTestCase {
@Mock
TaskView.Listener mViewListener;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
new file mode 100644
index 000000000000..9ab0f89953e4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairTests.java
@@ -0,0 +1,81 @@
+/*
+ * 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.wm.shell.apppairs;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.ActivityManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link AppPair} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppPairTests {
+
+ private AppPairsController mController;
+ @Mock private SyncTransactionQueue mSyncQueue;
+ @Mock private ShellTaskOrganizer mTaskOrganizer;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mController = new TestAppPairsController(mTaskOrganizer, mSyncQueue);
+ }
+
+ @After
+ public void tearDown() {}
+
+ @Test
+ public void testContains() {
+ final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
+ final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
+
+ final AppPair pair = mController.pairInner(task1, task2);
+ assertThat(pair.contains(task1.taskId)).isTrue();
+ assertThat(pair.contains(task2.taskId)).isTrue();
+
+ pair.unpair();
+ assertThat(pair.contains(task1.taskId)).isFalse();
+ assertThat(pair.contains(task2.taskId)).isFalse();
+ }
+
+ @Test
+ public void testVanishUnpairs() {
+ final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
+ final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
+
+ final AppPair pair = mController.pairInner(task1, task2);
+ assertThat(pair.contains(task1.taskId)).isTrue();
+ assertThat(pair.contains(task2.taskId)).isTrue();
+
+ pair.onTaskVanished(task1);
+ assertThat(pair.contains(task1.taskId)).isFalse();
+ assertThat(pair.contains(task2.taskId)).isFalse();
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
new file mode 100644
index 000000000000..ed85b67c3fea
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsControllerTests.java
@@ -0,0 +1,85 @@
+/*
+ * 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.wm.shell.apppairs;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.ActivityManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link AppPairsController} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppPairsControllerTests {
+ private TestAppPairsController mController;
+ private TestAppPairsPool mPool;
+ @Mock private SyncTransactionQueue mSyncQueue;
+ @Mock private ShellTaskOrganizer mTaskOrganizer;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mController = new TestAppPairsController(mTaskOrganizer, mSyncQueue);
+ mPool = mController.getPool();
+ }
+
+ @After
+ public void tearDown() {}
+
+ @Test
+ public void testPairUnpair() {
+ final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
+ final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
+
+ final AppPair pair = mController.pairInner(task1, task2);
+ assertThat(pair.contains(task1.taskId)).isTrue();
+ assertThat(pair.contains(task2.taskId)).isTrue();
+ assertThat(mPool.poolSize()).isGreaterThan(0);
+
+ mController.unpair(task2.taskId);
+ assertThat(pair.contains(task1.taskId)).isFalse();
+ assertThat(pair.contains(task2.taskId)).isFalse();
+ assertThat(mPool.poolSize()).isGreaterThan(1);
+ }
+
+ @Test
+ public void testUnpair_DontReleaseToPool() {
+ final ActivityManager.RunningTaskInfo task1 = new TestRunningTaskInfoBuilder().build();
+ final ActivityManager.RunningTaskInfo task2 = new TestRunningTaskInfoBuilder().build();
+
+ final AppPair pair = mController.pairInner(task1, task2);
+ assertThat(pair.contains(task1.taskId)).isTrue();
+ assertThat(pair.contains(task2.taskId)).isTrue();
+
+ mController.unpair(task2.taskId, false /* releaseToPool */);
+ assertThat(pair.contains(task1.taskId)).isFalse();
+ assertThat(pair.contains(task2.taskId)).isFalse();
+ assertThat(mPool.poolSize()).isEqualTo(1);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
new file mode 100644
index 000000000000..4a0fe0f28620
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/AppPairsPoolTests.java
@@ -0,0 +1,67 @@
+/*
+ * 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.wm.shell.apppairs;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Tests for {@link AppPairsPool} */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppPairsPoolTests {
+ private TestAppPairsController mController;
+ private TestAppPairsPool mPool;
+ @Mock private SyncTransactionQueue mSyncQueue;
+ @Mock private ShellTaskOrganizer mTaskOrganizer;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mController = new TestAppPairsController(mTaskOrganizer, mSyncQueue);
+ mPool = mController.getPool();
+ }
+
+ @After
+ public void tearDown() {}
+
+ @Test
+ public void testInitialState() {
+ // Pool should always start off with at least 1 entry.
+ assertThat(mPool.poolSize()).isGreaterThan(0);
+ }
+
+ @Test
+ public void testAcquireRelease() {
+ assertThat(mPool.poolSize()).isGreaterThan(0);
+ final AppPair appPair = mPool.acquire();
+ assertThat(mPool.poolSize()).isGreaterThan(0);
+ mPool.release(appPair);
+ assertThat(mPool.poolSize()).isGreaterThan(1);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
new file mode 100644
index 000000000000..7ea5a1b96c07
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.apppairs;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.SyncTransactionQueue;
+
+public class TestAppPairsController extends AppPairsController {
+ TestAppPairsPool mPool;
+
+ public TestAppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue) {
+ super(organizer, syncQueue);
+ mPool = new TestAppPairsPool(this);
+ setPairsPool(mPool);
+ }
+
+ TestAppPairsPool getPool() {
+ return mPool;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsPool.java
index 47a62ce92d11..080f2075344a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/FlickerAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsPool.java
@@ -14,18 +14,21 @@
* limitations under the License.
*/
-package com.android.wm.shell.flicker.helpers
+package com.android.wm.shell.apppairs;
-import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import com.android.server.wm.flicker.helpers.StandardAppHelper
+import android.app.ActivityManager;
-abstract class FlickerAppHelper(
- instr: Instrumentation,
- launcherName: String,
- launcherStrategy: ILauncherStrategy
-) : StandardAppHelper(instr, sFlickerPackage, launcherName, launcherStrategy) {
- companion object {
- var sFlickerPackage = "com.android.wm.shell.flicker.testapp"
+public class TestAppPairsPool extends AppPairsPool{
+ TestAppPairsPool(AppPairsController controller) {
+ super(controller);
+ }
+
+ @Override
+ void incrementPool() {
+ final AppPair entry = new AppPair(mController);
+ final ActivityManager.RunningTaskInfo info =
+ new TestRunningTaskInfoBuilder().build();
+ entry.onTaskAppeared(info, null /* leash */);
+ release(entry);
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestRunningTaskInfoBuilder.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestRunningTaskInfoBuilder.java
new file mode 100644
index 000000000000..76d3a6aaee22
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestRunningTaskInfoBuilder.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.wm.shell.apppairs;
+
+import android.app.ActivityManager;
+import android.graphics.Rect;
+import android.window.IWindowContainerToken;
+import android.window.WindowContainerToken;
+
+public class TestRunningTaskInfoBuilder {
+ static int sNextTaskId = 500;
+ private Rect mBounds = new Rect(0, 0, 100, 100);
+ private WindowContainerToken mToken =
+ new WindowContainerToken(new IWindowContainerToken.Default());
+
+ TestRunningTaskInfoBuilder setBounds(Rect bounds) {
+ mBounds.set(bounds);
+ return this;
+ }
+
+ ActivityManager.RunningTaskInfo build() {
+ final ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
+ info.taskId = sNextTaskId++;
+ info.configuration.windowConfiguration.setBounds(mBounds);
+ info.token = mToken;
+ info.isResizeable = true;
+ return info;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index 31c08ae471ae..7c9b9c37c2c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.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.bubbles;
+package com.android.wm.shell.bubbles;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -35,11 +35,12 @@ import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Pair;
+import android.view.WindowManager;
import androidx.test.filters.SmallTest;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.BubbleData.TimeSource;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.bubbles.BubbleData.TimeSource;
import com.google.common.collect.ImmutableList;
@@ -63,7 +64,7 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class BubbleDataTest extends SysuiTestCase {
+public class BubbleDataTest extends ShellTestCase {
private BubbleEntry mEntryA1;
private BubbleEntry mEntryA2;
@@ -135,8 +136,9 @@ public class BubbleDataTest extends SysuiTestCase {
mBubbleB2 = new Bubble(mEntryB2, mSuppressionListener, mPendingIntentCanceledListener);
mBubbleB3 = new Bubble(mEntryB3, mSuppressionListener, mPendingIntentCanceledListener);
mBubbleC1 = new Bubble(mEntryC1, mSuppressionListener, mPendingIntentCanceledListener);
-
- mBubbleData = new BubbleData(getContext(), mBubbleLogger);
+ TestableBubblePositioner positioner = new TestableBubblePositioner(mContext,
+ mock(WindowManager.class));
+ mBubbleData = new BubbleData(getContext(), mBubbleLogger, positioner);
// Used by BubbleData to set lastAccessedTime
when(mTimeSource.currentTimeMillis()).thenReturn(1000L);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.java
index fd6e2ee66107..69d5244e5ac2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleFlyoutViewTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleFlyoutViewTest.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,12 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles;
+package com.android.wm.shell.bubbles;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotSame;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.graphics.Color;
import android.graphics.PointF;
@@ -30,29 +32,34 @@ import android.widget.TextView;
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mockito;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class BubbleFlyoutViewTest extends SysuiTestCase {
+public class BubbleFlyoutViewTest extends ShellTestCase {
private BubbleFlyoutView mFlyout;
private TextView mFlyoutText;
private TextView mSenderName;
private float[] mDotCenter = new float[2];
private Bubble.FlyoutMessage mFlyoutMessage;
+ @Mock
+ private BubblePositioner mPositioner;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ when(mPositioner.getBubbleBitmapSize()).thenReturn(40);
+ when(mPositioner.getBubbleSize()).thenReturn(60);
+
mFlyoutMessage = new Bubble.FlyoutMessage();
mFlyoutMessage.senderName = "Josh";
mFlyoutMessage.message = "Hello";
@@ -70,7 +77,8 @@ public class BubbleFlyoutViewTest extends SysuiTestCase {
mFlyout.setupFlyoutStartingAsDot(
mFlyoutMessage,
new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
- false);
+ false,
+ mPositioner);
mFlyout.setVisibility(View.VISIBLE);
assertEquals("Hello", mFlyoutText.getText());
@@ -80,10 +88,11 @@ public class BubbleFlyoutViewTest extends SysuiTestCase {
@Test
public void testFlyoutHide_runsCallback() {
- Runnable after = Mockito.mock(Runnable.class);
+ Runnable after = mock(Runnable.class);
mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage,
new PointF(100, 100), 500, true, Color.WHITE, null, after, mDotCenter,
- false);
+ false,
+ mPositioner);
mFlyout.hideFlyout();
verify(after).run();
@@ -93,7 +102,8 @@ public class BubbleFlyoutViewTest extends SysuiTestCase {
public void testSetCollapsePercent() {
mFlyout.setupFlyoutStartingAsDot(mFlyoutMessage,
new PointF(100, 100), 500, true, Color.WHITE, null, null, mDotCenter,
- false);
+ false,
+ mPositioner);
mFlyout.setVisibility(View.VISIBLE);
mFlyout.setCollapsePercent(1f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
index 690a1ad42861..069305212958 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.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.bubbles;
+package com.android.wm.shell.bubbles;
import static com.google.common.truth.Truth.assertThat;
@@ -37,8 +37,8 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -49,7 +49,7 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class BubbleTest extends SysuiTestCase {
+public class BubbleTest extends ShellTestCase {
@Mock
private Notification mNotif;
@Mock
@@ -72,7 +72,7 @@ public class BubbleTest extends SysuiTestCase {
Intent target = new Intent(mContext, BubblesTestActivity.class);
Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
PendingIntent.getActivity(mContext, 0, target, 0),
- Icon.createWithResource(mContext, R.drawable.android))
+ Icon.createWithResource(mContext, R.drawable.bubble_ic_create_bubble))
.build();
when(mSbn.getNotification()).thenReturn(mNotif);
when(mNotif.getBubbleMetadata()).thenReturn(metadata);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTestActivity.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTestActivity.java
new file mode 100644
index 000000000000..d5fbe556045a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTestActivity.java
@@ -0,0 +1,40 @@
+/*
+ * 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.wm.shell.bubbles;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.wm.shell.R;
+
+/**
+ * Referenced by NotificationTestHelper#makeBubbleMetadata
+ */
+public class BubblesTestActivity extends Activity {
+
+ public static final String BUBBLE_ACTIVITY_OPENED = "BUBBLE_ACTIVITY_OPENED";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ Intent i = new Intent(BUBBLE_ACTIVITY_OPENED);
+ sendBroadcast(i);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/TestableBubblePositioner.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/TestableBubblePositioner.java
new file mode 100644
index 000000000000..96bc5335a32c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/TestableBubblePositioner.java
@@ -0,0 +1,35 @@
+/*
+ * 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.wm.shell.bubbles;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.view.WindowManager;
+
+public class TestableBubblePositioner extends BubblePositioner {
+
+ public TestableBubblePositioner(Context context,
+ WindowManager windowManager) {
+ super(context, windowManager);
+
+ updateInternal(Configuration.ORIENTATION_PORTRAIT,
+ Insets.of(0, 0, 0, 0),
+ new Rect(0, 0, 500, 1000));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
index a5bb8ea23559..1eba3c266358 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.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.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
@@ -34,8 +34,8 @@ import android.widget.FrameLayout;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
-import com.android.systemui.bubbles.BubblePositioner;
+import com.android.wm.shell.R;
+import com.android.wm.shell.bubbles.BubblePositioner;
import org.junit.Before;
import org.junit.Ignore;
@@ -64,7 +64,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC
super.setUp();
BubblePositioner positioner = new BubblePositioner(getContext(), mock(WindowManager.class));
- positioner.update(Configuration.ORIENTATION_PORTRAIT,
+ positioner.updateInternal(Configuration.ORIENTATION_PORTRAIT,
Insets.of(0, 0, 0, 0),
new Rect(0, 0, mDisplayWidth, mDisplayHeight));
mExpandedController = new ExpandedAnimationController(positioner, mExpandedViewPadding,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTest.java
index 498330c83dcb..c4edbb286e16 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTest.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.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTestCase.java
index a5f2e8b3db37..a7a7db869776 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTestCase.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.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import static org.mockito.Mockito.when;
@@ -30,8 +30,8 @@ import android.widget.FrameLayout;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
+import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.mockito.Mock;
@@ -50,7 +50,7 @@ import java.util.concurrent.TimeUnit;
*
* See physics-animation-testing.md.
*/
-public class PhysicsAnimationLayoutTestCase extends SysuiTestCase {
+public class PhysicsAnimationLayoutTestCase extends ShellTestCase {
TestablePhysicsAnimationLayout mLayout;
List<View> mViews = new ArrayList<>();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.java
index 7d0abec79de1..f36dcbe7bf4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/StackAnimationControllerTest.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.bubbles.animation;
+package com.android.wm.shell.bubbles.animation;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -27,14 +27,15 @@ import static org.mockito.Mockito.verify;
import android.graphics.PointF;
import android.testing.AndroidTestingRunner;
import android.view.View;
+import android.view.WindowManager;
import android.widget.FrameLayout;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
-import com.android.systemui.bubbles.BubblePositioner;
+import com.android.wm.shell.R;
+import com.android.wm.shell.bubbles.TestableBubblePositioner;
import com.android.wm.shell.common.FloatingContentCoordinator;
import org.junit.Before;
@@ -310,7 +311,7 @@ public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase
super(floatingContentCoordinator,
bubbleCountSupplier,
onBubbleAnimatedOutAction,
- mock(BubblePositioner.class));
+ new TestableBubblePositioner(mContext, mock(WindowManager.class)));
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
index 9b8fd11febe3..416028088294 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
+import com.android.wm.shell.ShellTestCase
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertTrue
@@ -28,7 +28,7 @@ import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class BubblePersistentRepositoryTest : SysuiTestCase() {
+class BubblePersistentRepositoryTest : ShellTestCase() {
private val bubbles = listOf(
BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
index 7ea611c9c6a9..4fab9a5496ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.content.pm.LauncherApps
import android.os.UserHandle
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.eq
+import com.android.wm.shell.ShellTestCase
import junit.framework.Assert.assertEquals
import org.junit.Before
import org.junit.Test
@@ -32,7 +32,7 @@ import org.mockito.Mockito.verifyNoMoreInteractions
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class BubbleVolatileRepositoryTest : SysuiTestCase() {
+class BubbleVolatileRepositoryTest : ShellTestCase() {
private val user0 = UserHandle.of(0)
private val user10 = UserHandle.of(10)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
index 8cf4534ecdce..e0891a95c6a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubbleXmlHelperTest.kt
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.bubbles.storage
+package com.android.wm.shell.bubbles.storage
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
+import com.android.wm.shell.ShellTestCase
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import org.junit.Test
@@ -28,7 +28,7 @@ import java.io.ByteArrayOutputStream
@SmallTest
@RunWith(AndroidTestingRunner::class)
-class BubbleXmlHelperTest : SysuiTestCase() {
+class BubbleXmlHelperTest : ShellTestCase() {
private val bubbles = listOf(
BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
new file mode 100644
index 000000000000..884287209d53
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/TaskStackListenerImplTest.java
@@ -0,0 +1,258 @@
+/*
+ * 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.wm.shell.common;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.IActivityTaskManager;
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link com.android.wm.shell.common.TaskStackListenerImpl}.
+ */
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class TaskStackListenerImplTest {
+
+ @Mock
+ private IActivityTaskManager mActivityTaskManager;
+
+ @Mock
+ private TaskStackListenerCallback mCallback;
+
+ @Mock
+ private TaskStackListenerCallback mOtherCallback;
+
+ private TaskStackListenerImpl mImpl;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mImpl = new TaskStackListenerImpl(mActivityTaskManager);
+ mImpl.setHandler(new ProxyToListenerImplHandler(mImpl));
+ mImpl.addListener(mCallback);
+ mImpl.addListener(mOtherCallback);
+ }
+
+ @Test
+ public void testAddRemoveMultipleListeners_ExpectRegisterUnregisterOnce()
+ throws RemoteException {
+ TaskStackListenerImpl impl = new TaskStackListenerImpl(mActivityTaskManager);
+ impl.setHandler(new ProxyToListenerImplHandler(impl));
+ reset(mActivityTaskManager);
+ impl.addListener(mCallback);
+ impl.addListener(mOtherCallback);
+ verify(mActivityTaskManager, times(1)).registerTaskStackListener(any());
+
+ impl.removeListener(mOtherCallback);
+ impl.removeListener(mCallback);
+ verify(mActivityTaskManager, times(1)).unregisterTaskStackListener(any());
+ }
+
+ @Test
+ public void testOnRecentTaskListUpdated() {
+ mImpl.onRecentTaskListUpdated();
+ verify(mCallback).onRecentTaskListUpdated();
+ verify(mOtherCallback).onRecentTaskListUpdated();
+ }
+
+ @Test
+ public void testOnRecentTaskListFrozenChanged() {
+ mImpl.onRecentTaskListFrozenChanged(true);
+ verify(mCallback).onRecentTaskListFrozenChanged(eq(true));
+ verify(mOtherCallback).onRecentTaskListFrozenChanged(eq(true));
+ }
+
+ @Test
+ public void testOnTaskStackChanged() {
+ mImpl.onTaskStackChanged();
+ verify(mCallback).onTaskStackChangedBackground();
+ verify(mCallback).onTaskStackChanged();
+ verify(mOtherCallback).onTaskStackChangedBackground();
+ verify(mOtherCallback).onTaskStackChanged();
+ }
+
+ @Test
+ public void testOnTaskProfileLocked() {
+ mImpl.onTaskProfileLocked(1, 2);
+ verify(mCallback).onTaskProfileLocked(eq(1), eq(2));
+ verify(mOtherCallback).onTaskProfileLocked(eq(1), eq(2));
+ }
+
+ @Test
+ public void testOnTaskDisplayChanged() {
+ mImpl.onTaskDisplayChanged(1, 2);
+ verify(mCallback).onTaskDisplayChanged(eq(1), eq(2));
+ verify(mOtherCallback).onTaskDisplayChanged(eq(1), eq(2));
+ }
+
+ @Test
+ public void testOnTaskCreated() {
+ mImpl.onTaskCreated(1, new ComponentName("a", "b"));
+ verify(mCallback).onTaskCreated(eq(1), eq(new ComponentName("a", "b")));
+ verify(mOtherCallback).onTaskCreated(eq(1), eq(new ComponentName("a", "b")));
+ }
+
+ @Test
+ public void testOnTaskRemoved() {
+ mImpl.onTaskRemoved(123);
+ verify(mCallback).onTaskRemoved(eq(123));
+ verify(mOtherCallback).onTaskRemoved(eq(123));
+ }
+
+ @Test
+ public void testOnTaskMovedToFront() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onTaskMovedToFront(info);
+ verify(mCallback).onTaskMovedToFront(eq(info));
+ verify(mOtherCallback).onTaskMovedToFront(eq(info));
+ }
+
+ @Test
+ public void testOnTaskDescriptionChanged() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onTaskDescriptionChanged(info);
+ verify(mCallback).onTaskDescriptionChanged(eq(info));
+ verify(mOtherCallback).onTaskDescriptionChanged(eq(info));
+ }
+
+ @Test
+ public void testOnTaskSnapshotChanged() {
+ ActivityManager.TaskSnapshot snapshot = mock(ActivityManager.TaskSnapshot.class);
+ mImpl.onTaskSnapshotChanged(123, snapshot);
+ verify(mCallback).onTaskSnapshotChanged(eq(123), eq(snapshot));
+ verify(mOtherCallback).onTaskSnapshotChanged(eq(123), eq(snapshot));
+ }
+
+ @Test
+ public void testOnBackPressedOnTaskRoot() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onBackPressedOnTaskRoot(info);
+ verify(mCallback).onBackPressedOnTaskRoot(eq(info));
+ verify(mOtherCallback).onBackPressedOnTaskRoot(eq(info));
+ }
+
+ @Test
+ public void testOnActivityRestartAttempt() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onActivityRestartAttempt(info, true, true, true);
+ verify(mCallback).onActivityRestartAttempt(eq(info), eq(true), eq(true), eq(true));
+ verify(mOtherCallback).onActivityRestartAttempt(eq(info), eq(true), eq(true), eq(true));
+ }
+
+ @Test
+ public void testOnActivityPinned() {
+ mImpl.onActivityPinned("abc", 1, 2, 3);
+ verify(mCallback).onActivityPinned(eq("abc"), eq(1), eq(2), eq(3));
+ verify(mOtherCallback).onActivityPinned(eq("abc"), eq(1), eq(2), eq(3));
+ }
+
+ @Test
+ public void testOnActivityUnpinned() {
+ mImpl.onActivityUnpinned();
+ verify(mCallback).onActivityUnpinned();
+ verify(mOtherCallback).onActivityUnpinned();
+ }
+
+ @Test
+ public void testOnActivityForcedResizable() {
+ mImpl.onActivityForcedResizable("abc", 1, 2);
+ verify(mCallback).onActivityForcedResizable(eq("abc"), eq(1), eq(2));
+ verify(mOtherCallback).onActivityForcedResizable(eq("abc"), eq(1), eq(2));
+ }
+
+ @Test
+ public void testOnActivityDismissingDockedStack() {
+ mImpl.onActivityDismissingDockedStack();
+ verify(mCallback).onActivityDismissingDockedStack();
+ verify(mOtherCallback).onActivityDismissingDockedStack();
+ }
+
+ @Test
+ public void testOnActivityLaunchOnSecondaryDisplayFailed() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onActivityLaunchOnSecondaryDisplayFailed(info, 1);
+ verify(mCallback).onActivityLaunchOnSecondaryDisplayFailed(eq(info));
+ verify(mOtherCallback).onActivityLaunchOnSecondaryDisplayFailed(eq(info));
+ }
+
+ @Test
+ public void testOnActivityLaunchOnSecondaryDisplayRerouted() {
+ ActivityManager.RunningTaskInfo info = mock(ActivityManager.RunningTaskInfo.class);
+ mImpl.onActivityLaunchOnSecondaryDisplayRerouted(info, 1);
+ verify(mCallback).onActivityLaunchOnSecondaryDisplayRerouted(eq(info));
+ verify(mOtherCallback).onActivityLaunchOnSecondaryDisplayRerouted(eq(info));
+ }
+
+ @Test
+ public void testOnActivityRequestedOrientationChanged() {
+ mImpl.onActivityRequestedOrientationChanged(1, 2);
+ verify(mCallback).onActivityRequestedOrientationChanged(eq(1), eq(2));
+ verify(mOtherCallback).onActivityRequestedOrientationChanged(eq(1), eq(2));
+ }
+
+ @Test
+ public void testOnActivityRotation() {
+ mImpl.onActivityRotation(123);
+ verify(mCallback).onActivityRotation(eq(123));
+ verify(mOtherCallback).onActivityRotation(eq(123));
+ }
+
+ @Test
+ public void testOnSizeCompatModeActivityChanged() {
+ IBinder b = mock(IBinder.class);
+ mImpl.onSizeCompatModeActivityChanged(123, b);
+ verify(mCallback).onSizeCompatModeActivityChanged(eq(123), eq(b));
+ verify(mOtherCallback).onSizeCompatModeActivityChanged(eq(123), eq(b));
+ }
+
+ /**
+ * Handler that synchronously calls TaskStackListenerImpl#handleMessage() when it receives a
+ * message.
+ */
+ private class ProxyToListenerImplHandler extends Handler {
+ public ProxyToListenerImplHandler(Callback callback) {
+ super(callback);
+ }
+
+ @Override
+ public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+ return mImpl.handleMessage(msg);
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
new file mode 100644
index 000000000000..fad1f057267a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -0,0 +1,368 @@
+/*
+ * 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.wm.shell.draganddrop;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_FULLSCREEN;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
+import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
+
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.app.IActivityTaskManager;
+import android.app.PendingIntent;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.view.DisplayInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target;
+import com.android.wm.shell.splitscreen.DividerView;
+import com.android.wm.shell.splitscreen.SplitScreen;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.function.Consumer;
+
+/**
+ * Tests for the drag and drop policy.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DragAndDropPolicyTest {
+
+ @Mock
+ private Context mContext;
+
+ @Mock
+ private IActivityTaskManager mIActivityTaskManager;
+
+ @Mock
+ private SplitScreen mSplitScreen;
+
+ @Mock
+ private DragAndDropPolicy.Starter mStarter;
+
+ private DisplayLayout mDisplayLayout;
+ private Insets mInsets;
+ private DragAndDropPolicy mPolicy;
+
+ private ClipData mActivityClipData;
+ private ClipData mNonResizeableActivityClipData;
+ private ClipData mTaskClipData;
+ private ClipData mShortcutClipData;
+
+ private ActivityManager.RunningTaskInfo mHomeTask;
+ private ActivityManager.RunningTaskInfo mFullscreenAppTask;
+ private ActivityManager.RunningTaskInfo mNonResizeableFullscreenAppTask;
+ private ActivityManager.RunningTaskInfo mSplitPrimaryAppTask;
+
+ @Before
+ public void setUp() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
+
+ Resources res = mock(Resources.class);
+ Configuration config = new Configuration();
+ doReturn(config).when(res).getConfiguration();
+ DisplayInfo info = new DisplayInfo();
+ info.logicalWidth = 100;
+ info.logicalHeight = 100;
+ mDisplayLayout = new DisplayLayout(info, res, false, false);
+ mInsets = Insets.of(0, 0, 0, 0);
+
+ DividerView divider = mock(DividerView.class);
+ doReturn(divider).when(mSplitScreen).getDividerView();
+ doReturn(new Rect(50, 0, 100, 100)).when(divider)
+ .getNonMinimizedSplitScreenSecondaryBounds();
+
+ doAnswer((Answer<Void>) invocation -> {
+ Consumer<Boolean> callback = invocation.getArgument(0);
+ callback.accept(true);
+ return null;
+ }).when(mSplitScreen).registerInSplitScreenListener(any());
+
+ mPolicy = new DragAndDropPolicy(mContext, mIActivityTaskManager, mSplitScreen, mStarter);
+ mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
+ mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
+ setClipDataResizeable(mNonResizeableActivityClipData, false);
+ mTaskClipData = createClipData(MIMETYPE_APPLICATION_TASK);
+ mShortcutClipData = createClipData(MIMETYPE_APPLICATION_SHORTCUT);
+
+ mHomeTask = createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ mFullscreenAppTask = createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ mNonResizeableFullscreenAppTask =
+ createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ mNonResizeableFullscreenAppTask.isResizeable = false;
+ mSplitPrimaryAppTask = createTaskInfo(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ ACTIVITY_TYPE_STANDARD);
+
+ setIsPhone(false);
+ setInSplitScreen(false);
+ setRunningTask(mFullscreenAppTask);
+ }
+
+ /**
+ * Creates a clip data that is by default resizeable.
+ */
+ private ClipData createClipData(String mimeType) {
+ ClipDescription clipDescription = new ClipDescription(mimeType, new String[] { mimeType });
+ Intent i = new Intent();
+ switch (mimeType) {
+ case MIMETYPE_APPLICATION_SHORTCUT:
+ i.putExtra(Intent.EXTRA_PACKAGE_NAME, "package");
+ i.putExtra(Intent.EXTRA_SHORTCUT_ID, "shortcut_id");
+ break;
+ case MIMETYPE_APPLICATION_TASK:
+ i.putExtra(Intent.EXTRA_TASK_ID, 12345);
+ break;
+ case MIMETYPE_APPLICATION_ACTIVITY:
+ i.putExtra(ClipDescription.EXTRA_PENDING_INTENT, mock(PendingIntent.class));
+ break;
+ }
+ i.putExtra(Intent.EXTRA_USER, android.os.Process.myUserHandle());
+ ClipData.Item item = new ClipData.Item(i);
+ item.setActivityInfo(new ActivityInfo());
+ ClipData data = new ClipData(clipDescription, item);
+ setClipDataResizeable(data, true);
+ return data;
+ }
+
+ private ActivityManager.RunningTaskInfo createTaskInfo(int winMode, int actType) {
+ ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
+ info.configuration.windowConfiguration.setActivityType(actType);
+ info.configuration.windowConfiguration.setWindowingMode(winMode);
+ info.isResizeable = true;
+ return info;
+ }
+
+ private void setRunningTask(ActivityManager.RunningTaskInfo task) throws RemoteException {
+ doReturn(Collections.singletonList(task)).when(mIActivityTaskManager)
+ .getFilteredTasks(anyInt(), anyBoolean());
+ }
+
+ private void setClipDataResizeable(ClipData data, boolean resizeable) {
+ data.getItemAt(0).getActivityInfo().resizeMode = resizeable
+ ? ActivityInfo.RESIZE_MODE_RESIZEABLE
+ : ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ }
+
+ private void setIsPhone(boolean isPhone) {
+ Resources res = mock(Resources.class);
+ Configuration config = mock(Configuration.class);
+ config.smallestScreenWidthDp = isPhone ? 400 : 800;
+ doReturn(config).when(res).getConfiguration();
+ doReturn(res).when(mContext).getResources();
+ }
+
+ private void setInSplitScreen(boolean inSplitscreen) {
+ doReturn(inSplitscreen).when(mSplitScreen).isDividerVisible();
+ }
+
+ @Test
+ public void testDragAppOverFullscreenHome_expectOnlyFullscreenTarget() throws RemoteException {
+ setRunningTask(mHomeTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragAppOverFullscreenApp_expectSplitScreenAndFullscreenTargets()
+ throws RemoteException {
+ setRunningTask(mFullscreenAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
+ // pairs
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_RIGHT);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ reset(mStarter);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
+ verify(mStarter).enterSplitScreen(anyInt(), eq(false));
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenAndFullscreenTargets()
+ throws RemoteException {
+ setIsPhone(true);
+ setRunningTask(mFullscreenAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
+ // pairs
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_BOTTOM);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ reset(mStarter);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
+ verify(mStarter).enterSplitScreen(anyInt(), eq(false));
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragAppOverFullscreenNonResizeableApp_expectOnlyFullscreenTargets()
+ throws RemoteException {
+ setRunningTask(mNonResizeableFullscreenAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragNonResizeableAppOverFullscreenApp_expectOnlyFullscreenTargets()
+ throws RemoteException {
+ setRunningTask(mFullscreenAppTask);
+ mPolicy.start(mDisplayLayout, mNonResizeableActivityClipData);
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragAppOverSplitApp_expectFullscreenAndSplitTargets() throws RemoteException {
+ setInSplitScreen(true);
+ setRunningTask(mSplitPrimaryAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
+ // pairs
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_RIGHT);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ reset(mStarter);
+
+ // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testDragAppOverSplitAppPhone_expectFullscreenAndVerticalSplitTargets()
+ throws RemoteException {
+ setIsPhone(true);
+ setInSplitScreen(true);
+ setRunningTask(mSplitPrimaryAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ // TODO(b/169894807): For now, only allow splitting to the right/bottom until we have split
+ // pairs
+ ArrayList<Target> targets = assertExactTargetTypes(
+ mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_BOTTOM);
+
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ reset(mStarter);
+
+ // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
+ mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
+ verify(mStarter).startIntent(any(), any());
+ }
+
+ @Test
+ public void testTargetHitRects() throws RemoteException {
+ setRunningTask(mFullscreenAppTask);
+ mPolicy.start(mDisplayLayout, mActivityClipData);
+ ArrayList<Target> targets = mPolicy.getTargets(mInsets);
+ for (Target t : targets) {
+ assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.left, t.hitRegion.top) == t);
+ assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.right - 1, t.hitRegion.top) == t);
+ assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.right - 1, t.hitRegion.bottom - 1)
+ == t);
+ assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.left, t.hitRegion.bottom - 1)
+ == t);
+ }
+ }
+
+ private Target filterTargetByType(ArrayList<Target> targets, int type) {
+ for (Target t : targets) {
+ if (type == t.type) {
+ return t;
+ }
+ }
+ fail("Target with type: " + type + " not found");
+ return null;
+ }
+
+ private ArrayList<Target> assertExactTargetTypes(ArrayList<Target> targets,
+ int... expectedTargetTypes) {
+ HashSet<Integer> expected = new HashSet<>();
+ for (int t : expectedTargetTypes) {
+ expected.add(t);
+ }
+ for (Target t : targets) {
+ if (!expected.contains(t.type)) {
+ fail("Found unexpected target type: " + t.type);
+ }
+ expected.remove(t.type);
+ }
+ assertTrue(expected.isEmpty());
+ return targets;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
new file mode 100644
index 000000000000..595440f8d52d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java
@@ -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.wm.shell.hidedisplaycutout;
+
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
+import android.platform.test.annotations.Presubmit;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class HideDisplayCutoutControllerTest {
+ private TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+
+ private HideDisplayCutoutController mHideDisplayCutoutController;
+ @Mock
+ private HideDisplayCutoutOrganizer mMockDisplayAreaOrganizer;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mHideDisplayCutoutController = new HideDisplayCutoutController(
+ mContext, mMockDisplayAreaOrganizer);
+ }
+
+ @Test
+ public void testToggleHideDisplayCutout_On() {
+ mHideDisplayCutoutController.mEnabled = false;
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_hideDisplayCutoutWithDisplayArea, true);
+ reset(mMockDisplayAreaOrganizer);
+ mHideDisplayCutoutController.updateStatus();
+ verify(mMockDisplayAreaOrganizer).enableHideDisplayCutout();
+ }
+
+ @Test
+ public void testToggleHideDisplayCutout_Off() {
+ mHideDisplayCutoutController.mEnabled = true;
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_hideDisplayCutoutWithDisplayArea, false);
+ mHideDisplayCutoutController.updateStatus();
+ verify(mMockDisplayAreaOrganizer).disableHideDisplayCutout();
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
new file mode 100644
index 000000000000..2e4fd6a331ec
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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.wm.shell.hidedisplaycutout;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Configuration;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.platform.test.annotations.Presubmit;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.window.DisplayAreaAppearedInfo;
+import android.window.DisplayAreaInfo;
+import android.window.DisplayAreaOrganizer;
+import android.window.IWindowContainerToken;
+import android.window.WindowContainerToken;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.R;
+import com.android.wm.shell.common.DisplayController;
+
+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;
+
+import java.util.ArrayList;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class HideDisplayCutoutOrganizerTest {
+ private TestableContext mContext = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+
+ @Mock
+ private DisplayController mMockDisplayController;
+ private HideDisplayCutoutOrganizer mOrganizer;
+
+ private DisplayAreaInfo mDisplayAreaInfo;
+ private SurfaceControl mLeash;
+
+ @Mock
+ private Display mDisplay;
+ @Mock
+ private IWindowContainerToken mMockRealToken;
+ private WindowContainerToken mToken;
+
+ private final Rect mFakeDefaultBounds = new Rect(0, 0, 100, 200);
+ private final Insets mFakeDefaultCutoutInsets = Insets.of(0, 10, 0, 0);
+ private final int mFakeStatusBarHeightPortrait = 15;
+ private final int mFakeStatusBarHeightLandscape = 10;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay);
+
+ HideDisplayCutoutOrganizer organizer = new HideDisplayCutoutOrganizer(
+ mContext, mMockDisplayController);
+ mOrganizer = Mockito.spy(organizer);
+ doNothing().when(mOrganizer).unregisterOrganizer();
+ doNothing().when(mOrganizer).applyBoundsAndOffsets(any(), any(), any(), any());
+ doNothing().when(mOrganizer).applyTransaction(any(), any());
+
+ // It will be called when mDisplayAreaMap.containKey(token) is called.
+ Binder binder = new Binder();
+ doReturn(binder).when(mMockRealToken).asBinder();
+ mToken = new WindowContainerToken(mMockRealToken);
+ mLeash = new SurfaceControl();
+ mDisplayAreaInfo = new DisplayAreaInfo(
+ mToken, DEFAULT_DISPLAY, FEATURE_HIDE_DISPLAY_CUTOUT);
+ mDisplayAreaInfo.configuration.orientation = Configuration.ORIENTATION_PORTRAIT;
+ DisplayAreaAppearedInfo info = new DisplayAreaAppearedInfo(mDisplayAreaInfo, mLeash);
+ ArrayList<DisplayAreaAppearedInfo> infoList = new ArrayList<>();
+ infoList.add(info);
+ doReturn(infoList).when(mOrganizer).registerOrganizer(
+ DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
+ }
+
+ @Test
+ public void testEnableHideDisplayCutout() {
+ mOrganizer.enableHideDisplayCutout();
+
+ verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
+ verify(mOrganizer).addDisplayAreaInfoAndLeashToMap(mDisplayAreaInfo, mLeash);
+ verify(mOrganizer).updateBoundsAndOffsets(true);
+ assertThat(mOrganizer.mDisplayAreaMap.containsKey(mDisplayAreaInfo.token)).isTrue();
+ assertThat(mOrganizer.mDisplayAreaMap.containsValue(mLeash)).isTrue();
+ }
+
+ @Test
+ public void testOnDisplayAreaAppeared() {
+ mOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
+
+ assertThat(mOrganizer.mDisplayAreaMap.containsKey(mToken)).isTrue();
+ assertThat(mOrganizer.mDisplayAreaMap.containsValue(mLeash)).isTrue();
+ }
+
+ @Test
+ public void testOnDisplayAreaVanished() {
+ mOrganizer.mDisplayAreaMap.put(mDisplayAreaInfo.token, mLeash);
+ mOrganizer.onDisplayAreaVanished(mDisplayAreaInfo);
+
+ assertThat(mOrganizer.mDisplayAreaMap.containsKey(mDisplayAreaInfo.token)).isFalse();
+ }
+
+ @Test
+ public void testToggleHideDisplayCutout_enable_rot0() {
+ doReturn(mFakeDefaultBounds).when(mOrganizer).getDisplayBoundsOfNaturalOrientation();
+ doReturn(mFakeDefaultCutoutInsets).when(mOrganizer)
+ .getDisplayCutoutInsetsOfNaturalOrientation();
+ mContext.getOrCreateTestableResources().addOverride(
+ R.dimen.status_bar_height_portrait, mFakeStatusBarHeightPortrait);
+ doReturn(Surface.ROTATION_0).when(mDisplay).getRotation();
+ mOrganizer.enableHideDisplayCutout();
+
+ verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
+ verify(mOrganizer).addDisplayAreaInfoAndLeashToMap(mDisplayAreaInfo, mLeash);
+ verify(mOrganizer).updateBoundsAndOffsets(true);
+ assertThat(mOrganizer.mCurrentDisplayBounds).isEqualTo(new Rect(0, 15, 100, 200));
+ assertThat(mOrganizer.mOffsetX).isEqualTo(0);
+ assertThat(mOrganizer.mOffsetY).isEqualTo(15);
+ assertThat(mOrganizer.mRotation).isEqualTo(Surface.ROTATION_0);
+ }
+
+ @Test
+ public void testToggleHideDisplayCutout_enable_rot90() {
+ doReturn(mFakeDefaultBounds).when(mOrganizer).getDisplayBoundsOfNaturalOrientation();
+ doReturn(mFakeDefaultCutoutInsets).when(mOrganizer)
+ .getDisplayCutoutInsetsOfNaturalOrientation();
+ mContext.getOrCreateTestableResources().addOverride(
+ R.dimen.status_bar_height_landscape, mFakeStatusBarHeightLandscape);
+ doReturn(Surface.ROTATION_90).when(mDisplay).getRotation();
+ mOrganizer.enableHideDisplayCutout();
+
+ verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
+ verify(mOrganizer).addDisplayAreaInfoAndLeashToMap(mDisplayAreaInfo, mLeash);
+ verify(mOrganizer).updateBoundsAndOffsets(true);
+ assertThat(mOrganizer.mCurrentDisplayBounds).isEqualTo(new Rect(10, 0, 200, 100));
+ assertThat(mOrganizer.mOffsetX).isEqualTo(10);
+ assertThat(mOrganizer.mOffsetY).isEqualTo(0);
+ assertThat(mOrganizer.mRotation).isEqualTo(Surface.ROTATION_90);
+ }
+
+ @Test
+ public void testToggleHideDisplayCutout_enable_rot270() {
+ doReturn(mFakeDefaultBounds).when(mOrganizer).getDisplayBoundsOfNaturalOrientation();
+ doReturn(mFakeDefaultCutoutInsets).when(mOrganizer)
+ .getDisplayCutoutInsetsOfNaturalOrientation();
+ mContext.getOrCreateTestableResources().addOverride(
+ R.dimen.status_bar_height_landscape, mFakeStatusBarHeightLandscape);
+ doReturn(Surface.ROTATION_270).when(mDisplay).getRotation();
+ mOrganizer.enableHideDisplayCutout();
+
+ verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT);
+ verify(mOrganizer).addDisplayAreaInfoAndLeashToMap(mDisplayAreaInfo, mLeash);
+ verify(mOrganizer).updateBoundsAndOffsets(true);
+ assertThat(mOrganizer.mCurrentDisplayBounds).isEqualTo(new Rect(0, 0, 190, 100));
+ assertThat(mOrganizer.mOffsetX).isEqualTo(0);
+ assertThat(mOrganizer.mOffsetY).isEqualTo(0);
+ assertThat(mOrganizer.mRotation).isEqualTo(Surface.ROTATION_270);
+ }
+
+ @Test
+ public void testToggleHideDisplayCutout_disable() {
+ doReturn(mFakeDefaultBounds).when(mOrganizer).getDisplayBoundsOfNaturalOrientation();
+ doReturn(mFakeDefaultCutoutInsets).when(mOrganizer)
+ .getDisplayCutoutInsetsOfNaturalOrientation();
+ mContext.getOrCreateTestableResources().addOverride(
+ R.dimen.status_bar_height_portrait, mFakeStatusBarHeightPortrait);
+ mOrganizer.enableHideDisplayCutout();
+
+ // disable hide display cutout
+ mOrganizer.disableHideDisplayCutout();
+ verify(mOrganizer).updateBoundsAndOffsets(false);
+ verify(mOrganizer).unregisterOrganizer();
+ assertThat(mOrganizer.mCurrentDisplayBounds).isEqualTo(new Rect(0, 0, 0, 0));
+ assertThat(mOrganizer.mOffsetX).isEqualTo(0);
+ assertThat(mOrganizer.mOffsetY).isEqualTo(0);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 3645f1e56f92..8ef077e5f857 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -33,6 +33,7 @@ import android.view.Display;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import org.junit.Before;
import org.junit.Ignore;
@@ -64,6 +65,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
OneHandedTimeoutHandler mMockTimeoutHandler;
@Mock
IOverlayManager mMockOverlayManager;
+ @Mock
+ TaskStackListenerImpl mMockTaskStackListener;
@Before
public void setUp() throws Exception {
@@ -76,7 +79,8 @@ public class OneHandedControllerTest extends OneHandedTestCase {
mMockTouchHandler,
mMockTutorialHandler,
mMockGestureHandler,
- mMockOverlayManager);
+ mMockOverlayManager,
+ mMockTaskStackListener);
mOneHandedController = Mockito.spy(oneHandedController);
mTimeoutHandler = Mockito.spy(OneHandedTimeoutHandler.get());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java
index c7ae2a09ad67..73a95345e1c9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTestCase.java
@@ -46,6 +46,8 @@ public abstract class OneHandedTestCase {
@Before
public void setupSettings() {
+ assumeTrue(SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false));
+
final Context testContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
final DisplayManager dm = testContext.getSystemService(DisplayManager.class);
@@ -74,13 +76,13 @@ public abstract class OneHandedTestCase {
Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1);
}
- @Before
- public void assumeOneHandedModeSupported() {
- assumeTrue(SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false));
- }
-
@After
public void restoreSettings() {
+ if (mContext == null) {
+ // Return early if one-handed mode is not supported
+ return;
+ }
+
Settings.Secure.putInt(getContext().getContentResolver(),
Settings.Secure.ONE_HANDED_MODE_ENABLED, sOrigEnabled ? 1 : 0);
Settings.Secure.putInt(mContext.getContentResolver(),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
index 3341c9cbacb9..ba8c737924f4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java
@@ -25,6 +25,7 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import org.junit.Before;
import org.junit.Test;
@@ -47,6 +48,8 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
@Mock
IOverlayManager mMockOverlayManager;
+ @Mock
+ TaskStackListenerImpl mMockTaskStackListener;
@Before
public void setUp() {
@@ -60,7 +63,8 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
mTouchHandler,
mTutorialHandler,
mGestureHandler,
- mMockOverlayManager);
+ mMockOverlayManager,
+ mMockTaskStackListener);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 255e74917ca0..55e7a354f4cd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -32,9 +32,7 @@ import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
-import com.android.wm.shell.pip.PipAnimationController;
-import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
-import com.android.wm.shell.pip.PipTestCase;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -49,7 +47,7 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipAnimationControllerTest extends PipTestCase {
+public class PipAnimationControllerTest extends ShellTestCase {
private PipAnimationController mPipAnimationController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
index 37421d910513..7a6e0c1b41fc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
@@ -17,7 +17,6 @@
package com.android.wm.shell.pip;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.graphics.Rect;
@@ -30,15 +29,14 @@ import android.view.Gravity;
import androidx.test.filters.SmallTest;
-import com.android.wm.shell.pip.PipBoundsHandler;
-import com.android.wm.shell.pip.PipTestCase;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
- * Unit tests against {@link PipBoundsHandler}, including but not limited to:
+ * Unit tests against {@link PipBoundsAlgorithm}, including but not limited to:
* - default/movement bounds
* - save/restore PiP position on application lifecycle
* - save/restore PiP position on screen rotation
@@ -46,24 +44,22 @@ import org.junit.runner.RunWith;
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipBoundsHandlerTest extends PipTestCase {
+public class PipBoundsAlgorithmTest extends ShellTestCase {
private static final int ROUNDING_ERROR_MARGIN = 16;
private static final float ASPECT_RATIO_ERROR_MARGIN = 0.01f;
private static final float DEFAULT_ASPECT_RATIO = 1f;
private static final float MIN_ASPECT_RATIO = 0.5f;
private static final float MAX_ASPECT_RATIO = 2f;
- private static final Rect EMPTY_CURRENT_BOUNDS = null;
- private static final Size EMPTY_MINIMAL_SIZE = null;
- private PipBoundsHandler mPipBoundsHandler;
+ private PipBoundsAlgorithm mPipBoundsAlgorithm;
private DisplayInfo mDefaultDisplayInfo;
private PipBoundsState mPipBoundsState;
@Before
public void setUp() throws Exception {
initializeMockResources();
- mPipBoundsState = new PipBoundsState();
- mPipBoundsHandler = new PipBoundsHandler(mContext, mPipBoundsState);
+ mPipBoundsState = new PipBoundsState(mContext);
+ mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState);
mPipBoundsState.setDisplayInfo(mDefaultDisplayInfo);
}
@@ -97,7 +93,7 @@ public class PipBoundsHandlerTest extends PipTestCase {
@Test
public void getDefaultAspectRatio() {
assertEquals("Default aspect ratio matches resources",
- DEFAULT_ASPECT_RATIO, mPipBoundsHandler.getDefaultAspectRatio(),
+ DEFAULT_ASPECT_RATIO, mPipBoundsAlgorithm.getDefaultAspectRatio(),
ASPECT_RATIO_ERROR_MARGIN);
}
@@ -108,15 +104,15 @@ public class PipBoundsHandlerTest extends PipTestCase {
res.addOverride(com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio,
newDefaultAspectRatio);
- mPipBoundsHandler.onConfigurationChanged(mContext);
+ mPipBoundsAlgorithm.onConfigurationChanged(mContext);
assertEquals("Default aspect ratio should be reloaded",
- mPipBoundsHandler.getDefaultAspectRatio(), newDefaultAspectRatio,
+ mPipBoundsAlgorithm.getDefaultAspectRatio(), newDefaultAspectRatio,
ASPECT_RATIO_ERROR_MARGIN);
}
@Test
- public void getDestinationBounds_returnBoundsMatchesAspectRatio() {
+ public void getEntryDestinationBounds_returnBoundsMatchesAspectRatio() {
final float[] aspectRatios = new float[] {
(MIN_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2,
DEFAULT_ASPECT_RATIO,
@@ -124,8 +120,7 @@ public class PipBoundsHandlerTest extends PipTestCase {
};
for (float aspectRatio : aspectRatios) {
mPipBoundsState.setAspectRatio(aspectRatio);
- final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
final float actualAspectRatio =
destinationBounds.width() / (destinationBounds.height() * 1f);
assertEquals("Destination bounds matches the given aspect ratio",
@@ -134,32 +129,31 @@ public class PipBoundsHandlerTest extends PipTestCase {
}
@Test
- public void getDestinationBounds_invalidAspectRatio_returnsDefaultAspectRatio() {
+ public void getEntryDestinationBounds_invalidAspectRatio_returnsDefaultAspectRatio() {
final float[] invalidAspectRatios = new float[] {
MIN_ASPECT_RATIO / 2,
MAX_ASPECT_RATIO * 2
};
for (float aspectRatio : invalidAspectRatios) {
mPipBoundsState.setAspectRatio(aspectRatio);
- final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
final float actualAspectRatio =
destinationBounds.width() / (destinationBounds.height() * 1f);
assertEquals("Destination bounds fallbacks to default aspect ratio",
- mPipBoundsHandler.getDefaultAspectRatio(), actualAspectRatio,
+ mPipBoundsAlgorithm.getDefaultAspectRatio(), actualAspectRatio,
ASPECT_RATIO_ERROR_MARGIN);
}
}
@Test
- public void getDestinationBounds_withCurrentBounds_returnBoundsMatchesAspectRatio() {
+ public void getAdjustedDestinationBounds_returnBoundsMatchesAspectRatio() {
final float aspectRatio = (DEFAULT_ASPECT_RATIO + MAX_ASPECT_RATIO) / 2;
final Rect currentBounds = new Rect(0, 0, 0, 100);
currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left;
mPipBoundsState.setAspectRatio(aspectRatio);
- final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(currentBounds,
- EMPTY_MINIMAL_SIZE);
+ final Rect destinationBounds = mPipBoundsAlgorithm.getAdjustedDestinationBounds(
+ currentBounds, aspectRatio);
final float actualAspectRatio =
destinationBounds.width() / (destinationBounds.height() * 1f);
@@ -168,7 +162,7 @@ public class PipBoundsHandlerTest extends PipTestCase {
}
@Test
- public void getDestinationBounds_withMinSize_returnMinBounds() {
+ public void getEntryDestinationBounds_withMinSize_returnMinBounds() {
final float[] aspectRatios = new float[] {
(MIN_ASPECT_RATIO + DEFAULT_ASPECT_RATIO) / 2,
DEFAULT_ASPECT_RATIO,
@@ -183,8 +177,8 @@ public class PipBoundsHandlerTest extends PipTestCase {
final float aspectRatio = aspectRatios[i];
final Size minimalSize = minimalSizes[i];
mPipBoundsState.setAspectRatio(aspectRatio);
- final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, minimalSize);
+ mPipBoundsState.setOverrideMinSize(minimalSize);
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
assertTrue("Destination bounds is no smaller than minimal requirement",
(destinationBounds.width() == minimalSize.getWidth()
&& destinationBounds.height() >= minimalSize.getHeight())
@@ -198,15 +192,16 @@ public class PipBoundsHandlerTest extends PipTestCase {
}
@Test
- public void getDestinationBounds_withCurrentBounds_ignoreMinBounds() {
+ public void getAdjustedDestinationBounds_ignoreMinBounds() {
final float aspectRatio = (DEFAULT_ASPECT_RATIO + MAX_ASPECT_RATIO) / 2;
final Rect currentBounds = new Rect(0, 0, 0, 100);
currentBounds.right = (int) (currentBounds.height() * aspectRatio) + currentBounds.left;
final Size minSize = new Size(currentBounds.width() / 2, currentBounds.height() / 2);
mPipBoundsState.setAspectRatio(aspectRatio);
- final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
- currentBounds, minSize);
+ mPipBoundsState.setOverrideMinSize(minSize);
+ final Rect destinationBounds = mPipBoundsAlgorithm.getAdjustedDestinationBounds(
+ currentBounds, aspectRatio);
assertTrue("Destination bounds ignores minimal size",
destinationBounds.width() > minSize.getWidth()
@@ -214,33 +209,29 @@ public class PipBoundsHandlerTest extends PipTestCase {
}
@Test
- public void getDestinationBounds_reentryStateExists_restoreLastSize() {
+ public void getEntryDestinationBounds_reentryStateExists_restoreLastSize() {
mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO);
- final Rect reentryBounds = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ final Rect reentryBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
reentryBounds.scale(1.25f);
- final float reentrySnapFraction = mPipBoundsHandler.getSnapFraction(reentryBounds);
+ final float reentrySnapFraction = mPipBoundsAlgorithm.getSnapFraction(reentryBounds);
mPipBoundsState.saveReentryState(reentryBounds, reentrySnapFraction);
- final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
assertEquals(reentryBounds.width(), destinationBounds.width());
assertEquals(reentryBounds.height(), destinationBounds.height());
}
@Test
- public void getDestinationBounds_reentryStateExists_restoreLastPosition() {
+ public void getEntryDestinationBounds_reentryStateExists_restoreLastPosition() {
mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO);
- final Rect reentryBounds = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ final Rect reentryBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
reentryBounds.offset(0, -100);
- final float reentrySnapFraction = mPipBoundsHandler.getSnapFraction(reentryBounds);
+ final float reentrySnapFraction = mPipBoundsAlgorithm.getSnapFraction(reentryBounds);
mPipBoundsState.saveReentryState(reentryBounds, reentrySnapFraction);
- final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
assertBoundsInclusionWithMargin("restoreLastPosition", reentryBounds, destinationBounds);
}
@@ -249,12 +240,10 @@ public class PipBoundsHandlerTest extends PipTestCase {
public void setShelfHeight_offsetBounds() {
final int shelfHeight = 100;
mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO);
- final Rect oldPosition = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ final Rect oldPosition = mPipBoundsAlgorithm.getEntryDestinationBounds();
- mPipBoundsHandler.setShelfHeight(true, shelfHeight);
- final Rect newPosition = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ mPipBoundsState.setShelfVisibility(true, shelfHeight);
+ final Rect newPosition = mPipBoundsAlgorithm.getEntryDestinationBounds();
oldPosition.offset(0, -shelfHeight);
assertBoundsInclusionWithMargin("offsetBounds by shelf", oldPosition, newPosition);
@@ -264,27 +253,23 @@ public class PipBoundsHandlerTest extends PipTestCase {
public void onImeVisibilityChanged_offsetBounds() {
final int imeHeight = 100;
mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO);
- final Rect oldPosition = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ final Rect oldPosition = mPipBoundsAlgorithm.getEntryDestinationBounds();
- mPipBoundsHandler.onImeVisibilityChanged(true, imeHeight);
- final Rect newPosition = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ mPipBoundsState.setImeVisibility(true, imeHeight);
+ final Rect newPosition = mPipBoundsAlgorithm.getEntryDestinationBounds();
oldPosition.offset(0, -imeHeight);
assertBoundsInclusionWithMargin("offsetBounds by IME", oldPosition, newPosition);
}
@Test
- public void getDestinationBounds_noReentryState_useDefaultBounds() {
+ public void getEntryDestinationBounds_noReentryState_useDefaultBounds() {
mPipBoundsState.setAspectRatio(DEFAULT_ASPECT_RATIO);
- final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ final Rect defaultBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
mPipBoundsState.clearReentryState();
- final Rect actualBounds = mPipBoundsHandler.getDestinationBounds(
- EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+ final Rect actualBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
assertBoundsInclusionWithMargin("useDefaultBounds", defaultBounds, actualBounds);
}
@@ -297,13 +282,4 @@ public class PipBoundsHandlerTest extends PipTestCase {
+ " with error margin " + ROUNDING_ERROR_MARGIN,
expectedWithMargin.contains(actual));
}
-
- private void assertNonBoundsInclusionWithMargin(String from, Rect expected, Rect actual) {
- final Rect expectedWithMargin = new Rect(expected);
- expectedWithMargin.inset(-ROUNDING_ERROR_MARGIN, -ROUNDING_ERROR_MARGIN);
- assertFalse(from + ": expect " + expected
- + " not contains " + actual
- + " with error margin " + ROUNDING_ERROR_MARGIN,
- expectedWithMargin.contains(actual));
- }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
index dc9399edaa3b..59e10c189046 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
@@ -19,6 +19,9 @@ package com.android.wm.shell.pip;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import android.content.ComponentName;
import android.graphics.Rect;
@@ -28,17 +31,21 @@ import android.util.Size;
import androidx.test.filters.SmallTest;
+import com.android.wm.shell.ShellTestCase;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.function.BiConsumer;
+
/**
* Tests for {@link PipBoundsState}.
*/
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
-public class PipBoundsStateTest extends PipTestCase {
+public class PipBoundsStateTest extends ShellTestCase {
private static final Rect DEFAULT_BOUNDS = new Rect(0, 0, 10, 10);
private static final float DEFAULT_SNAP_FRACTION = 1.0f;
@@ -49,7 +56,7 @@ public class PipBoundsStateTest extends PipTestCase {
@Before
public void setUp() {
- mPipBoundsState = new PipBoundsState();
+ mPipBoundsState = new PipBoundsState(mContext);
mTestComponentName1 = new ComponentName(mContext, "component1");
mTestComponentName2 = new ComponentName(mContext, "component2");
}
@@ -107,4 +114,25 @@ public class PipBoundsStateTest extends PipTestCase {
assertNull(mPipBoundsState.getReentryState());
}
+
+ @Test
+ public void testSetShelfVisibility_changed_callbackInvoked() {
+ final BiConsumer<Boolean, Integer> callback = mock(BiConsumer.class);
+ mPipBoundsState.setOnShelfVisibilityChangeCallback(callback);
+
+ mPipBoundsState.setShelfVisibility(true, 100);
+
+ verify(callback).accept(true, 100);
+ }
+
+ @Test
+ public void testSetShelfVisibility_notChanged_callbackNotInvoked() {
+ final BiConsumer<Boolean, Integer> callback = mock(BiConsumer.class);
+ mPipBoundsState.setShelfVisibility(true, 100);
+ mPipBoundsState.setOnShelfVisibilityChangeCallback(callback);
+
+ mPipBoundsState.setShelfVisibility(true, 100);
+
+ verify(callback, never()).accept(true, 100);
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 39381c6d677e..8d3774cee1e0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -18,7 +18,7 @@ package com.android.wm.shell.pip;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doNothing;
@@ -30,16 +30,19 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.PictureInPictureParams;
import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.os.RemoteException;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Rational;
+import android.util.Size;
import android.view.DisplayInfo;
import android.window.WindowContainerToken;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.pip.phone.PipMenuActivityController;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -58,11 +61,11 @@ import java.util.Optional;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class PipTaskOrganizerTest extends PipTestCase {
+public class PipTaskOrganizerTest extends ShellTestCase {
private PipTaskOrganizer mSpiedPipTaskOrganizer;
@Mock private DisplayController mMockdDisplayController;
- @Mock private PipBoundsHandler mMockPipBoundsHandler;
+ @Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
@Mock private PipMenuActivityController mMenuActivityController;
@Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
@Mock private PipUiEventLogger mMockPipUiEventLogger;
@@ -78,9 +81,9 @@ public class PipTaskOrganizerTest extends PipTestCase {
MockitoAnnotations.initMocks(this);
mComponent1 = new ComponentName(mContext, "component1");
mComponent2 = new ComponentName(mContext, "component2");
- mPipBoundsState = new PipBoundsState();
+ mPipBoundsState = new PipBoundsState(mContext);
mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, mPipBoundsState,
- mMockPipBoundsHandler, mMenuActivityController, mMockPipSurfaceTransactionHelper,
+ mMockPipBoundsAlgorithm, mMenuActivityController, mMockPipSurfaceTransactionHelper,
mMockOptionalSplitScreen, mMockdDisplayController, mMockPipUiEventLogger,
mMockShellTaskOrganizer));
preparePipTaskOrg();
@@ -113,6 +116,15 @@ public class PipTaskOrganizerTest extends PipTestCase {
}
@Test
+ public void startSwipePipToHome_updatesOverrideMinSize() {
+ final Size minSize = new Size(100, 80);
+
+ mSpiedPipTaskOrganizer.startSwipePipToHome(mComponent1, createActivityInfo(minSize), null);
+
+ assertEquals(minSize, mPipBoundsState.getOverrideMinSize());
+ }
+
+ @Test
public void onTaskAppeared_updatesAspectRatio() {
final Rational aspectRatio = new Rational(2, 1);
@@ -131,6 +143,17 @@ public class PipTaskOrganizerTest extends PipTestCase {
}
@Test
+ public void onTaskAppeared_updatesOverrideMinSize() {
+ final Size minSize = new Size(100, 80);
+
+ mSpiedPipTaskOrganizer.onTaskAppeared(
+ createTaskInfo(mComponent1, createPipParams(null), minSize),
+ null /* leash */);
+
+ assertEquals(minSize, mPipBoundsState.getOverrideMinSize());
+ }
+
+ @Test
public void onTaskInfoChanged_updatesAspectRatioIfChanged() {
final Rational startAspectRatio = new Rational(2, 1);
final Rational newAspectRatio = new Rational(1, 2);
@@ -154,11 +177,23 @@ public class PipTaskOrganizerTest extends PipTestCase {
assertEquals(mComponent2, mPipBoundsState.getLastPipComponentName());
}
+ @Test
+ public void onTaskInfoChanged_updatesOverrideMinSize() {
+ mSpiedPipTaskOrganizer.onTaskAppeared(createTaskInfo(mComponent1,
+ createPipParams(null)), null /* leash */);
+
+ final Size minSize = new Size(100, 80);
+ mSpiedPipTaskOrganizer.onTaskInfoChanged(createTaskInfo(mComponent2,
+ createPipParams(null), minSize));
+
+ assertEquals(minSize, mPipBoundsState.getOverrideMinSize());
+ }
+
private void preparePipTaskOrg() {
final DisplayInfo info = new DisplayInfo();
mPipBoundsState.setDisplayInfo(info);
- when(mMockPipBoundsHandler.getDestinationBounds(any(), any())).thenReturn(new Rect());
- when(mMockPipBoundsHandler.getDestinationBounds(any(), any(), anyBoolean()))
+ when(mMockPipBoundsAlgorithm.getEntryDestinationBounds()).thenReturn(new Rect());
+ when(mMockPipBoundsAlgorithm.getAdjustedDestinationBounds(any(), anyFloat()))
.thenReturn(new Rect());
mPipBoundsState.setDisplayInfo(info);
mSpiedPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA);
@@ -168,13 +203,28 @@ public class PipTaskOrganizerTest extends PipTestCase {
private static ActivityManager.RunningTaskInfo createTaskInfo(
ComponentName componentName, PictureInPictureParams params) {
+ return createTaskInfo(componentName, params, null /* minSize */);
+ }
+
+ private static ActivityManager.RunningTaskInfo createTaskInfo(
+ ComponentName componentName, PictureInPictureParams params, Size minSize) {
final ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
info.token = mock(WindowContainerToken.class);
info.pictureInPictureParams = params;
info.topActivity = componentName;
+ if (minSize != null) {
+ info.topActivityInfo = createActivityInfo(minSize);
+ }
return info;
}
+ private static ActivityInfo createActivityInfo(Size minSize) {
+ final ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.windowLayout = new ActivityInfo.WindowLayout(
+ 0, 0, 0, 0, 0, minSize.getWidth(), minSize.getHeight());
+ return activityInfo;
+ }
+
private static PictureInPictureParams createPipParams(Rational aspectRatio) {
return new PictureInPictureParams.Builder()
.setAspectRatio(aspectRatio)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 5f0f1964814f..88c8eb902a6f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -35,14 +35,15 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipTaskOrganizer;
-import com.android.wm.shell.pip.PipTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -56,27 +57,29 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class PipControllerTest extends PipTestCase {
+public class PipControllerTest extends ShellTestCase {
private PipController mPipController;
@Mock private DisplayController mMockDisplayController;
@Mock private PipMenuActivityController mMockPipMenuActivityController;
@Mock private PipAppOpsListener mMockPipAppOpsListener;
- @Mock private PipBoundsHandler mMockPipBoundsHandler;
+ @Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
@Mock private PipMediaController mMockPipMediaController;
@Mock private PipTaskOrganizer mMockPipTaskOrganizer;
@Mock private PipTouchHandler mMockPipTouchHandler;
@Mock private WindowManagerShellWrapper mMockWindowManagerShellWrapper;
@Mock private PipBoundsState mMockPipBoundsState;
+ @Mock private TaskStackListenerImpl mMockTaskStackListener;
@Mock private ShellExecutor mMockExecutor;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mPipController = new PipController(mContext, mMockDisplayController,
- mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState,
+ mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipBoundsState,
mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
- mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockExecutor);
+ mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
+ mMockExecutor);
doAnswer(invocation -> {
((Runnable) invocation.getArgument(0)).run();
return null;
@@ -106,9 +109,10 @@ public class PipControllerTest extends PipTestCase {
when(spyContext.getPackageManager()).thenReturn(mockPackageManager);
assertNull(PipController.create(spyContext, mMockDisplayController,
- mMockPipAppOpsListener, mMockPipBoundsHandler, mMockPipBoundsState,
+ mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipBoundsState,
mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
- mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockExecutor));
+ mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
+ mMockExecutor));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index 3f60cc01f20b..b25c74d12818 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -31,17 +31,13 @@ import android.util.Size;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.FloatingContentCoordinator;
-import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipSnapAlgorithm;
import com.android.wm.shell.pip.PipTaskOrganizer;
-import com.android.wm.shell.pip.PipTestCase;
import com.android.wm.shell.pip.PipUiEventLogger;
-import com.android.wm.shell.pip.phone.PipMenuActivityController;
-import com.android.wm.shell.pip.phone.PipMotionHelper;
-import com.android.wm.shell.pip.phone.PipResizeGestureHandler;
-import com.android.wm.shell.pip.phone.PipTouchHandler;
import org.junit.Before;
import org.junit.Test;
@@ -59,7 +55,7 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipTouchHandlerTest extends PipTestCase {
+public class PipTouchHandlerTest extends ShellTestCase {
private PipTouchHandler mPipTouchHandler;
@@ -76,7 +72,7 @@ public class PipTouchHandlerTest extends PipTestCase {
private PipUiEventLogger mPipUiEventLogger;
private PipBoundsState mPipBoundsState;
- private PipBoundsHandler mPipBoundsHandler;
+ private PipBoundsAlgorithm mPipBoundsAlgorithm;
private PipSnapAlgorithm mPipSnapAlgorithm;
private PipMotionHelper mMotionHelper;
private PipResizeGestureHandler mPipResizeGestureHandler;
@@ -92,13 +88,13 @@ public class PipTouchHandlerTest extends PipTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mPipBoundsState = new PipBoundsState();
- mPipBoundsHandler = new PipBoundsHandler(mContext, mPipBoundsState);
- mPipSnapAlgorithm = mPipBoundsHandler.getSnapAlgorithm();
+ mPipBoundsState = new PipBoundsState(mContext);
+ mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState);
+ mPipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
mPipSnapAlgorithm = new PipSnapAlgorithm(mContext);
mPipTouchHandler = new PipTouchHandler(mContext, mPipMenuActivityController,
- mPipBoundsHandler, mPipBoundsState, mPipTaskOrganizer, mFloatingContentCoordinator,
- mPipUiEventLogger);
+ mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer,
+ mFloatingContentCoordinator, mPipUiEventLogger);
mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
mPipTouchHandler.setPipMotionHelper(mMotionHelper);
@@ -124,7 +120,7 @@ public class PipTouchHandlerTest extends PipTestCase {
mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);
- assertEquals(expectedMinMovementBounds, mPipTouchHandler.mNormalMovementBounds);
+ assertEquals(expectedMinMovementBounds, mPipBoundsState.getNormalMovementBounds());
verify(mPipResizeGestureHandler, times(1))
.updateMinSize(mMinBounds.width(), mMinBounds.height());
}
@@ -143,7 +139,7 @@ public class PipTouchHandlerTest extends PipTestCase {
mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);
- assertEquals(expectedMaxMovementBounds, mPipTouchHandler.mExpandedMovementBounds);
+ assertEquals(expectedMaxMovementBounds, mPipBoundsState.getExpandedMovementBounds());
verify(mPipResizeGestureHandler, times(1))
.updateMaxSize(maxBounds.width(), maxBounds.height());
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
index 40667f76b17e..000f7e8b2e85 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchStateTest.java
@@ -35,8 +35,7 @@ import android.view.ViewConfiguration;
import androidx.test.filters.SmallTest;
-import com.android.wm.shell.pip.PipTestCase;
-import com.android.wm.shell.pip.phone.PipTouchState;
+import com.android.wm.shell.ShellTestCase;
import org.junit.Before;
import org.junit.Test;
@@ -47,7 +46,7 @@ import java.util.concurrent.CountDownLatch;
@RunWith(AndroidTestingRunner.class)
@SmallTest
@RunWithLooper
-public class PipTouchStateTest extends PipTestCase {
+public class PipTouchStateTest extends ShellTestCase {
private PipTouchState mTouchState;
private CountDownLatch mDoubleTapCallbackTriggeredLatch;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
new file mode 100644
index 000000000000..f5628abb100f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -0,0 +1,147 @@
+/*
+ * 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 unittest.src.com.android.wm.shell.startingsurface;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.testing.TestableContext;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for the starting surface drawer.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StartingSurfaceDrawerTests {
+ @Mock
+ private IBinder mBinder;
+ @Mock
+ private WindowManager mMockWindowManager;
+
+ TestStartingSurfaceDrawer mStartingSurfaceDrawer;
+
+ static final class TestStartingSurfaceDrawer extends StartingSurfaceDrawer{
+ int mAddWindowForTask = 0;
+
+ TestStartingSurfaceDrawer(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void postAddWindow(int taskId, IBinder appToken,
+ View view, WindowManager wm, WindowManager.LayoutParams params) {
+ // listen for addView
+ mAddWindowForTask = taskId;
+ }
+
+ @Override
+ protected void removeWindowSynced(int taskId) {
+ // listen for removeView
+ if (mAddWindowForTask == taskId) {
+ mAddWindowForTask = 0;
+ }
+ }
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ final TestableContext context = new TestableContext(
+ InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+ final WindowManager realWindowManager = context.getSystemService(WindowManager.class);
+ final WindowMetrics metrics = realWindowManager.getMaximumWindowMetrics();
+ context.addMockSystemService(WindowManager.class, mMockWindowManager);
+
+ spyOn(context);
+ spyOn(realWindowManager);
+ try {
+ doReturn(context).when(context).createPackageContext(anyString(), anyInt());
+ } catch (PackageManager.NameNotFoundException e) {
+ //
+ }
+ doReturn(metrics).when(mMockWindowManager).getMaximumWindowMetrics();
+ doNothing().when(mMockWindowManager).addView(any(), any());
+
+ mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(context));
+ }
+
+ @Test
+ public void testAddSplashScreenSurface() {
+ final int taskId = 1;
+ final Handler mainLoop = new Handler(Looper.getMainLooper());
+ final ActivityManager.RunningTaskInfo taskInfo =
+ createTaskInfo(taskId, WINDOWING_MODE_FULLSCREEN);
+ mStartingSurfaceDrawer.addStartingWindow(taskInfo, mBinder);
+ waitHandlerIdle(mainLoop);
+ verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any());
+ assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId);
+
+ mStartingSurfaceDrawer.removeStartingWindow(taskInfo);
+ waitHandlerIdle(mainLoop);
+ verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId));
+ assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, 0);
+ }
+
+ private ActivityManager.RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
+ ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ final ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ info.packageName = "test";
+ info.theme = android.R.style.Theme;
+ taskInfo.topActivityInfo = info;
+ taskInfo.taskId = taskId;
+ taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
+ return taskInfo;
+ }
+
+ private static void waitHandlerIdle(Handler handler) {
+ handler.runWithScissors(() -> { }, 0 /* timeout */);
+ }
+}
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 903ca2aa0783..8330363f3c84 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -61,6 +61,9 @@ cc_library {
],
export_include_dirs: ["include"],
export_shared_lib_headers: ["libz"],
+ static_libs: ["libincfs-utils"],
+ whole_static_libs: ["libincfs-utils"],
+ export_static_lib_headers: ["libincfs-utils"],
target: {
android: {
srcs: [
@@ -69,13 +72,14 @@ cc_library {
"CursorWindow.cpp",
],
shared_libs: [
- "libziparchive",
"libbase",
"libbinder",
"liblog",
"libcutils",
+ "libincfs",
"libutils",
"libz",
+ "libziparchive",
],
static: {
enabled: false,
@@ -86,11 +90,11 @@ cc_library {
enabled: false,
},
static_libs: [
- "libziparchive",
"libbase",
- "liblog",
"libcutils",
+ "liblog",
"libutils",
+ "libziparchive",
],
shared_libs: [
"libz",
@@ -160,10 +164,17 @@ cc_test {
"tests/ObbFile_test.cpp",
"tests/PosixUtils_test.cpp",
],
- shared_libs: common_test_libs + ["libbinder", "liblog", "libui"],
+ shared_libs: common_test_libs + [
+ "libbinder",
+ "liblog",
+ "libui",
+ ],
},
host: {
- static_libs: common_test_libs + ["liblog", "libz"],
+ static_libs: common_test_libs + [
+ "liblog",
+ "libz",
+ ],
},
},
data: [
@@ -204,10 +215,20 @@ cc_library {
export_include_dirs: ["include"],
target: {
android: {
- shared_libs: common_test_libs + ["libbinder", "liblog"],
+ shared_libs: common_test_libs + [
+ "libbinder",
+ "liblog",
+ ],
},
host: {
- static_libs: common_test_libs + ["libbinder", "liblog"],
+ static_libs: common_test_libs + [
+ "libbinder",
+ "liblog",
+ ],
+ },
+ darwin: {
+ // libbinder is not supported on mac
+ enabled: false,
},
},
}
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index e15b42d46f53..cb56a5172a45 100755
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -25,13 +25,11 @@
#include "android-base/unique_fd.h"
#include "android-base/utf8.h"
#include "utils/Compat.h"
-#include "utils/FileMap.h"
#include "ziparchive/zip_archive.h"
#include "androidfw/Asset.h"
#include "androidfw/Idmap.h"
#include "androidfw/misc.h"
-#include "androidfw/ResourceTypes.h"
#include "androidfw/Util.h"
namespace android {
@@ -161,50 +159,46 @@ class ZipAssetsProvider : public AssetsProvider {
}
const int fd = ::GetFileDescriptor(zip_handle_.get());
- const off64_t fd_offset = ::GetFileDescriptorOffset(zip_handle_.get());
+ const off64_t fd_offset = ::GetFileDescriptorOffset(zip_handle_.get());
+ incfs::IncFsFileMap asset_map;
if (entry.method == kCompressDeflated) {
- std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
- if (!map->create(GetPath(), fd, entry.offset + fd_offset, entry.compressed_length,
- true /*readOnly*/)) {
+ if (!asset_map.Create(fd, entry.offset + fd_offset, entry.compressed_length, GetPath())) {
LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
return {};
}
std::unique_ptr<Asset> asset =
- Asset::createFromCompressedMap(std::move(map), entry.uncompressed_length, mode);
+ Asset::createFromCompressedMap(std::move(asset_map), entry.uncompressed_length, mode);
if (asset == nullptr) {
LOG(ERROR) << "Failed to decompress '" << path << "' in APK '" << friendly_name_ << "'";
return {};
}
return asset;
- } else {
- std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
- if (!map->create(GetPath(), fd, entry.offset + fd_offset, entry.uncompressed_length,
- true /*readOnly*/)) {
- LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
- return {};
- }
+ }
- unique_fd ufd;
- if (!GetPath()) {
- // If the `path` is not set, create a new `fd` for the new Asset to own in order to create
- // new file descriptors using Asset::openFileDescriptor. If the path is set, it will be used
- // to create new file descriptors.
- ufd = unique_fd(dup(fd));
- if (!ufd.ok()) {
- LOG(ERROR) << "Unable to dup fd '" << path << "' in APK '" << friendly_name_ << "'";
- return {};
- }
- }
+ if (!asset_map.Create(fd, entry.offset + fd_offset, entry.uncompressed_length, GetPath())) {
+ LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
+ return {};
+ }
- std::unique_ptr<Asset> asset = Asset::createFromUncompressedMap(std::move(map),
- std::move(ufd), mode);
- if (asset == nullptr) {
- LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
+ unique_fd ufd;
+ if (!GetPath()) {
+ // If the `path` is not set, create a new `fd` for the new Asset to own in order to create
+ // new file descriptors using Asset::openFileDescriptor. If the path is set, it will be used
+ // to create new file descriptors.
+ ufd = unique_fd(dup(fd));
+ if (!ufd.ok()) {
+ LOG(ERROR) << "Unable to dup fd '" << path << "' in APK '" << friendly_name_ << "'";
return {};
}
- return asset;
}
+
+ auto asset = Asset::createFromUncompressedMap(std::move(asset_map), mode, std::move(ufd));
+ if (asset == nullptr) {
+ LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
+ return {};
+ }
+ return asset;
}
private:
@@ -446,8 +440,8 @@ std::unique_ptr<Asset> ApkAssets::CreateAssetFromFd(base::unique_fd fd,
}
}
- std::unique_ptr<FileMap> file_map = util::make_unique<FileMap>();
- if (!file_map->create(path, fd, offset, static_cast<size_t>(length), true /*readOnly*/)) {
+ incfs::IncFsFileMap file_map;
+ if (!file_map.Create(fd, offset, static_cast<size_t>(length), path)) {
LOG(ERROR) << "Failed to mmap file '" << ((path) ? path : "anon") << "': "
<< SystemErrorCodeToString(errno);
return {};
@@ -456,8 +450,8 @@ std::unique_ptr<Asset> ApkAssets::CreateAssetFromFd(base::unique_fd fd,
// If `path` is set, do not pass ownership of the `fd` to the new Asset since
// Asset::openFileDescriptor can use `path` to create new file descriptors.
return Asset::createFromUncompressedMap(std::move(file_map),
- (path) ? base::unique_fd(-1) : std::move(fd),
- Asset::AccessMode::ACCESS_RANDOM);
+ Asset::AccessMode::ACCESS_RANDOM,
+ (path) ? base::unique_fd(-1) : std::move(fd));
}
std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
@@ -493,15 +487,14 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
loaded_apk->idmap_asset_ = std::move(idmap_asset);
loaded_apk->loaded_idmap_ = std::move(idmap);
- const StringPiece data(
- reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
- loaded_apk->resources_asset_->getLength());
- if (data.data() == nullptr || data.empty()) {
+ const auto data = loaded_apk->resources_asset_->getIncFsBuffer(true /* aligned */);
+ const size_t length = loaded_apk->resources_asset_->getLength();
+ if (!data || length == 0) {
LOG(ERROR) << "Failed to read '" << kResourcesArsc << "' data in APK '" << path << "'.";
return {};
}
- loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, loaded_apk->loaded_idmap_.get(),
+ loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, length, loaded_apk->loaded_idmap_.get(),
property_flags);
if (!loaded_apk->loaded_arsc_) {
LOG(ERROR) << "Failed to load '" << kResourcesArsc << "' in APK '" << path << "'.";
@@ -525,15 +518,15 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadTableImpl(
new ApkAssets(std::move(assets), path, last_mod_time, property_flags));
loaded_apk->resources_asset_ = std::move(resources_asset);
- const StringPiece data(
- reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
- loaded_apk->resources_asset_->getLength());
- if (data.data() == nullptr || data.empty()) {
+ const auto data = loaded_apk->resources_asset_->getIncFsBuffer(true /* aligned */);
+ const size_t length = loaded_apk->resources_asset_->getLength();
+ if (!data || length == 0) {
LOG(ERROR) << "Failed to read resources table data in '" << path << "'.";
return {};
}
- loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, nullptr, property_flags);
+ loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, length, nullptr /* loaded_idmap */,
+ property_flags);
if (loaded_apk->loaded_arsc_ == nullptr) {
LOG(ERROR) << "Failed to read resources table in '" << path << "'.";
return {};
@@ -550,7 +543,6 @@ bool ApkAssets::IsUpToDate() const {
}
return (!loaded_idmap_ || loaded_idmap_->IsUpToDate()) &&
last_mod_time_ == getFileModDate(path_.c_str());
-
}
} // namespace android
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index cd30c184d5a4..4fbe4a3efbdd 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -298,34 +298,18 @@ Asset::Asset(void)
/*
* Create a new Asset from a memory mapping.
*/
-/*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap, AccessMode mode)
+/*static*/ std::unique_ptr<Asset> Asset::createFromUncompressedMap(incfs::IncFsFileMap&& dataMap,
+ AccessMode mode,
+ base::unique_fd fd)
{
- _FileAsset* pAsset;
- status_t result;
-
- pAsset = new _FileAsset;
- result = pAsset->openChunk(dataMap, base::unique_fd(-1));
- if (result != NO_ERROR) {
- delete pAsset;
- return NULL;
- }
-
- pAsset->mAccessMode = mode;
- return pAsset;
-}
+ auto pAsset = util::make_unique<_FileAsset>();
-/*static*/ std::unique_ptr<Asset> Asset::createFromUncompressedMap(std::unique_ptr<FileMap> dataMap,
- base::unique_fd fd, AccessMode mode)
-{
- std::unique_ptr<_FileAsset> pAsset = util::make_unique<_FileAsset>();
-
- status_t result = pAsset->openChunk(dataMap.get(), std::move(fd));
+ status_t result = pAsset->openChunk(std::move(dataMap), std::move(fd));
if (result != NO_ERROR) {
return NULL;
}
// We succeeded, so relinquish control of dataMap
- (void) dataMap.release();
pAsset->mAccessMode = mode;
return std::move(pAsset);
}
@@ -333,35 +317,18 @@ Asset::Asset(void)
/*
* Create a new Asset from compressed data in a memory mapping.
*/
-/*static*/ Asset* Asset::createFromCompressedMap(FileMap* dataMap,
- size_t uncompressedLen, AccessMode mode)
+/*static*/ std::unique_ptr<Asset> Asset::createFromCompressedMap(incfs::IncFsFileMap&& dataMap,
+ size_t uncompressedLen,
+ AccessMode mode)
{
- _CompressedAsset* pAsset;
- status_t result;
-
- pAsset = new _CompressedAsset;
- result = pAsset->openChunk(dataMap, uncompressedLen);
- if (result != NO_ERROR) {
- delete pAsset;
- return NULL;
- }
+ auto pAsset = util::make_unique<_CompressedAsset>();
- pAsset->mAccessMode = mode;
- return pAsset;
-}
-
-/*static*/ std::unique_ptr<Asset> Asset::createFromCompressedMap(std::unique_ptr<FileMap> dataMap,
- size_t uncompressedLen, AccessMode mode)
-{
- std::unique_ptr<_CompressedAsset> pAsset = util::make_unique<_CompressedAsset>();
-
- status_t result = pAsset->openChunk(dataMap.get(), uncompressedLen);
+ status_t result = pAsset->openChunk(std::move(dataMap), uncompressedLen);
if (result != NO_ERROR) {
return NULL;
}
// We succeeded, so relinquish control of dataMap
- (void) dataMap.release();
pAsset->mAccessMode = mode;
return std::move(pAsset);
}
@@ -414,7 +381,7 @@ off64_t Asset::handleSeek(off64_t offset, int whence, off64_t curPosn, off64_t m
* Constructor.
*/
_FileAsset::_FileAsset(void)
- : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mFd(-1), mMap(NULL), mBuf(NULL)
+ : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mFd(-1), mBuf(NULL)
{
// Register the Asset with the global list here after it is fully constructed and its
// vtable pointer points to this concrete type. b/31113965
@@ -441,7 +408,7 @@ _FileAsset::~_FileAsset(void)
status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, size_t length)
{
assert(mFp == NULL); // no reopen
- assert(mMap == NULL);
+ assert(!mMap.has_value());
assert(fd >= 0);
assert(offset >= 0);
@@ -484,15 +451,15 @@ status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, siz
/*
* Create the chunk from the map.
*/
-status_t _FileAsset::openChunk(FileMap* dataMap, base::unique_fd fd)
+status_t _FileAsset::openChunk(incfs::IncFsFileMap&& dataMap, base::unique_fd fd)
{
assert(mFp == NULL); // no reopen
- assert(mMap == NULL);
+ assert(!mMap.has_value());
assert(dataMap != NULL);
- mMap = dataMap;
+ mMap = std::move(dataMap);
mStart = -1; // not used
- mLength = dataMap->getDataLength();
+ mLength = mMap->length();
mFd = std::move(fd);
assert(mOffset == 0);
@@ -528,10 +495,15 @@ ssize_t _FileAsset::read(void* buf, size_t count)
if (!count)
return 0;
- if (mMap != NULL) {
+ if (mMap.has_value()) {
/* copy from mapped area */
//printf("map read\n");
- memcpy(buf, (char*)mMap->getDataPtr() + mOffset, count);
+ const auto readPos = mMap->data().offset(mOffset).convert<char>();
+ if (!readPos.verify(count)) {
+ return -1;
+ }
+
+ memcpy(buf, readPos.unsafe_ptr(), count);
actual = count;
} else if (mBuf != NULL) {
/* copy from buffer */
@@ -594,10 +566,6 @@ off64_t _FileAsset::seek(off64_t offset, int whence)
*/
void _FileAsset::close(void)
{
- if (mMap != NULL) {
- delete mMap;
- mMap = NULL;
- }
if (mBuf != NULL) {
delete[] mBuf;
mBuf = NULL;
@@ -624,16 +592,21 @@ void _FileAsset::close(void)
* level and we'd be using a different object, but we didn't, so we
* deal with it here.
*/
-const void* _FileAsset::getBuffer(bool wordAligned)
+const void* _FileAsset::getBuffer(bool aligned)
+{
+ return getIncFsBuffer(aligned).unsafe_ptr();
+}
+
+incfs::map_ptr<void> _FileAsset::getIncFsBuffer(bool aligned)
{
/* subsequent requests just use what we did previously */
if (mBuf != NULL)
return mBuf;
- if (mMap != NULL) {
- if (!wordAligned) {
- return mMap->getDataPtr();
+ if (mMap.has_value()) {
+ if (!aligned) {
+ return mMap->data();
}
- return ensureAlignment(mMap);
+ return ensureAlignment(*mMap);
}
assert(mFp != NULL);
@@ -671,47 +644,44 @@ const void* _FileAsset::getBuffer(bool wordAligned)
mBuf = buf;
return mBuf;
} else {
- FileMap* map;
-
- map = new FileMap;
- if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) {
- delete map;
+ incfs::IncFsFileMap map;
+ if (!map.Create(fileno(mFp), mStart, mLength, NULL /* file_name */ )) {
return NULL;
}
ALOGV(" getBuffer: mapped\n");
- mMap = map;
- if (!wordAligned) {
- return mMap->getDataPtr();
+ mMap = std::move(map);
+ if (!aligned) {
+ return mMap->data();
}
- return ensureAlignment(mMap);
+ return ensureAlignment(*mMap);
}
}
int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const
{
- if (mMap != NULL) {
+ if (mMap.has_value()) {
if (mFd.ok()) {
- *outStart = mMap->getDataOffset();
- *outLength = mMap->getDataLength();
- const int fd = dup(mFd);
- if (fd < 0) {
- ALOGE("Unable to dup fd (%d).", mFd.get());
- return -1;
- }
- lseek64(fd, 0, SEEK_SET);
- return fd;
+ *outStart = mMap->offset();
+ *outLength = mMap->length();
+ const int fd = dup(mFd);
+ if (fd < 0) {
+ ALOGE("Unable to dup fd (%d).", mFd.get());
+ return -1;
+ }
+ lseek64(fd, 0, SEEK_SET);
+ return fd;
}
- const char* fname = mMap->getFileName();
+ const char* fname = mMap->file_name();
if (fname == NULL) {
fname = mFileName;
}
if (fname == NULL) {
return -1;
}
- *outStart = mMap->getDataOffset();
- *outLength = mMap->getDataLength();
+ *outStart = mMap->offset();
+ *outLength = mMap->length();
return open(fname, O_RDONLY | O_BINARY);
}
if (mFileName == NULL) {
@@ -722,16 +692,21 @@ int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const
return open(mFileName, O_RDONLY | O_BINARY);
}
-const void* _FileAsset::ensureAlignment(FileMap* map)
+incfs::map_ptr<void> _FileAsset::ensureAlignment(const incfs::IncFsFileMap& map)
{
- void* data = map->getDataPtr();
- if ((((size_t)data)&0x3) == 0) {
+ const auto data = map.data();
+ if (util::IsFourByteAligned(data)) {
// We can return this directly if it is aligned on a word
// boundary.
ALOGV("Returning aligned FileAsset %p (%s).", this,
getAssetSource());
return data;
}
+
+ if (!data.convert<uint8_t>().verify(mLength)) {
+ return NULL;
+ }
+
// If not aligned on a word boundary, then we need to copy it into
// our own buffer.
ALOGV("Copying FileAsset %p (%s) to buffer size %d to make it aligned.", this,
@@ -741,7 +716,8 @@ const void* _FileAsset::ensureAlignment(FileMap* map)
ALOGE("alloc of %ld bytes failed\n", (long) mLength);
return NULL;
}
- memcpy(buf, data, mLength);
+
+ memcpy(buf, data.unsafe_ptr(), mLength);
mBuf = buf;
return buf;
}
@@ -757,7 +733,7 @@ const void* _FileAsset::ensureAlignment(FileMap* map)
*/
_CompressedAsset::_CompressedAsset(void)
: mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0),
- mMap(NULL), mFd(-1), mZipInflater(NULL), mBuf(NULL)
+ mFd(-1), mZipInflater(NULL), mBuf(NULL)
{
// Register the Asset with the global list here after it is fully constructed and its
// vtable pointer points to this concrete type. b/31113965
@@ -786,7 +762,7 @@ status_t _CompressedAsset::openChunk(int fd, off64_t offset,
int compressionMethod, size_t uncompressedLen, size_t compressedLen)
{
assert(mFd < 0); // no re-open
- assert(mMap == NULL);
+ assert(!mMap.has_value());
assert(fd >= 0);
assert(offset >= 0);
assert(compressedLen > 0);
@@ -815,20 +791,20 @@ status_t _CompressedAsset::openChunk(int fd, off64_t offset,
*
* Nothing is expanded until the first read call.
*/
-status_t _CompressedAsset::openChunk(FileMap* dataMap, size_t uncompressedLen)
+status_t _CompressedAsset::openChunk(incfs::IncFsFileMap&& dataMap, size_t uncompressedLen)
{
assert(mFd < 0); // no re-open
- assert(mMap == NULL);
+ assert(!mMap.has_value());
assert(dataMap != NULL);
- mMap = dataMap;
+ mMap = std::move(dataMap);
mStart = -1; // not used
- mCompressedLen = dataMap->getDataLength();
+ mCompressedLen = mMap->length();
mUncompressedLen = uncompressedLen;
assert(mOffset == 0);
if (uncompressedLen > StreamingZipInflater::OUTPUT_CHUNK_SIZE) {
- mZipInflater = new StreamingZipInflater(dataMap, uncompressedLen);
+ mZipInflater = new StreamingZipInflater(&(*mMap), uncompressedLen);
}
return NO_ERROR;
}
@@ -901,11 +877,6 @@ off64_t _CompressedAsset::seek(off64_t offset, int whence)
*/
void _CompressedAsset::close(void)
{
- if (mMap != NULL) {
- delete mMap;
- mMap = NULL;
- }
-
delete[] mBuf;
mBuf = NULL;
@@ -940,8 +911,8 @@ const void* _CompressedAsset::getBuffer(bool)
goto bail;
}
- if (mMap != NULL) {
- if (!ZipUtils::inflateToBuffer(mMap->getDataPtr(), buf,
+ if (mMap.has_value()) {
+ if (!ZipUtils::inflateToBuffer(mMap->data(), buf,
mUncompressedLen, mCompressedLen))
goto bail;
} else {
@@ -976,3 +947,6 @@ bail:
return mBuf;
}
+incfs::map_ptr<void> _CompressedAsset::getIncFsBuffer(bool aligned) {
+ return incfs::map_ptr<void>(getBuffer(aligned));
+}
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index f7c83371f79c..fb2b57193b83 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -917,7 +917,7 @@ Asset* AssetManager::openAssetFromFileLocked(const String8& pathName,
Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile,
const ZipEntryRO entry, AccessMode mode, const String8& entryName)
{
- Asset* pAsset = NULL;
+ std::unique_ptr<Asset> pAsset;
// TODO: look for previously-created shared memory slice?
uint16_t method;
@@ -932,28 +932,28 @@ Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile,
return NULL;
}
- FileMap* dataMap = pZipFile->createEntryFileMap(entry);
- if (dataMap == NULL) {
+ std::optional<incfs::IncFsFileMap> dataMap = pZipFile->createEntryIncFsFileMap(entry);
+ if (!dataMap.has_value()) {
ALOGW("create map from entry failed\n");
return NULL;
}
if (method == ZipFileRO::kCompressStored) {
- pAsset = Asset::createFromUncompressedMap(dataMap, mode);
+ pAsset = Asset::createFromUncompressedMap(std::move(*dataMap), mode);
ALOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.string(),
- dataMap->getFileName(), mode, pAsset);
+ dataMap->file_name(), mode, pAsset.get());
} else {
- pAsset = Asset::createFromCompressedMap(dataMap,
+ pAsset = Asset::createFromCompressedMap(std::move(*dataMap),
static_cast<size_t>(uncompressedLen), mode);
ALOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.string(),
- dataMap->getFileName(), mode, pAsset);
+ dataMap->file_name(), mode, pAsset.get());
}
if (pAsset == NULL) {
/* unexpected */
ALOGW("create from segment failed\n");
}
- return pAsset;
+ return pAsset.release();
}
/*
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 99dd3134ff8a..c49dc28124b2 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -38,9 +38,43 @@
namespace android {
+namespace {
+
+using EntryValue = std::variant<Res_value, incfs::verified_map_ptr<ResTable_map_entry>>;
+
+base::expected<EntryValue, IOError> GetEntryValue(
+ incfs::verified_map_ptr<ResTable_entry> table_entry) {
+ const uint16_t entry_size = dtohs(table_entry->size);
+
+ // Check if the entry represents a bag value.
+ if (entry_size >= sizeof(ResTable_map_entry) &&
+ (dtohs(table_entry->flags) & ResTable_entry::FLAG_COMPLEX)) {
+ const auto map_entry = table_entry.convert<ResTable_map_entry>();
+ if (!map_entry) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ return map_entry.verified();
+ }
+
+ // The entry represents a non-bag value.
+ const auto entry_value = table_entry.offset(entry_size).convert<Res_value>();
+ if (!entry_value) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ Res_value value;
+ value.copyFrom_dtoh(entry_value.value());
+ return value;
+}
+
+} // namespace
+
struct FindEntryResult {
- // A pointer to the value of the resource table entry.
- std::variant<Res_value, const ResTable_map_entry*> entry;
+ // The cookie representing the ApkAssets in which the value resides.
+ ApkAssetsCookie cookie;
+
+ // The value of the resource table entry. Either an android::Res_value for non-bag types or an
+ // incfs::verified_map_ptr<ResTable_map_entry> for bag types.
+ EntryValue entry;
// The configuration for which the resulting entry was defined. This is already swapped to host
// endianness.
@@ -265,7 +299,7 @@ const std::unordered_map<std::string, std::string>*
}
const PackageGroup& package_group = package_groups_[idx];
- if (package_group.packages_.size() == 0) {
+ if (package_group.packages_.empty()) {
return nullptr;
}
@@ -310,14 +344,14 @@ bool AssetManager2::GetOverlayablesToString(const android::StringPiece& package_
for (auto it = loaded_package->begin(); it != loaded_package->end(); it++) {
const OverlayableInfo* info = loaded_package->GetOverlayableInfo(*it);
if (info != nullptr) {
- ResourceName res_name;
- if (!GetResourceName(*it, &res_name)) {
+ auto res_name = GetResourceName(*it);
+ if (!res_name.has_value()) {
ANDROID_LOG(ERROR) << base::StringPrintf(
"Unable to retrieve name of overlayable resource 0x%08x", *it);
return false;
}
- const std::string name = ToFormattedResourceString(&res_name);
+ const std::string name = ToFormattedResourceString(*res_name);
output.append(base::StringPrintf(
"resource='%s' overlayable='%s' actor='%s' policy='0x%08x'\n",
name.c_str(), info->name.c_str(), info->actor.c_str(), info->policy_flags));
@@ -365,8 +399,8 @@ std::set<std::string> AssetManager2::GetNonSystemOverlayPaths() const {
return non_system_overlays;
}
-std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_system,
- bool exclude_mipmap) const {
+base::expected<std::set<ResTable_config>, IOError> AssetManager2::GetResourceConfigurations(
+ bool exclude_system, bool exclude_mipmap) const {
ATRACE_NAME("AssetManager::GetResourceConfigurations");
const auto non_system_overlays =
(exclude_system) ? GetNonSystemOverlayPaths() : std::set<std::string>();
@@ -386,7 +420,10 @@ std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_
continue;
}
- package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
+ auto result = package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
+ if (UNLIKELY(!result.has_value())) {
+ return base::unexpected(result.error());
+ }
}
}
return configurations;
@@ -501,11 +538,11 @@ std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
return apk_assets_[cookie]->GetAssetsProvider()->Open(filename, mode);
}
-ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
- bool /*stop_at_first_match*/,
- bool ignore_configuration,
- FindEntryResult* out_entry) const {
- if (resource_resolution_logging_enabled_) {
+base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
+ uint32_t resid, uint16_t density_override, bool stop_at_first_match,
+ bool ignore_configuration) const {
+ const bool logging_enabled = resource_resolution_logging_enabled_;
+ if (UNLIKELY(logging_enabled)) {
// Clear the last logged resource resolution.
ResetResourceResolution();
last_resolution_.resid = resid;
@@ -523,94 +560,96 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
}
// Retrieve the package group from the package id of the resource id.
- if (!is_valid_resid(resid)) {
+ if (UNLIKELY(!is_valid_resid(resid))) {
LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
- return kInvalidCookie;
+ return base::unexpected(std::nullopt);
}
const uint32_t package_id = get_package_id(resid);
const uint8_t type_idx = get_type_id(resid) - 1;
const uint16_t entry_idx = get_entry_id(resid);
uint8_t package_idx = package_ids_[package_id];
- if (package_idx == 0xff) {
+ if (UNLIKELY(package_idx == 0xff)) {
ANDROID_LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.",
package_id, resid);
- return kInvalidCookie;
+ return base::unexpected(std::nullopt);
}
const PackageGroup& package_group = package_groups_[package_idx];
- ApkAssetsCookie cookie = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
- false /* stop_at_first_match */,
- ignore_configuration, out_entry);
- if (UNLIKELY(cookie == kInvalidCookie)) {
- return kInvalidCookie;
+ auto result = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
+ stop_at_first_match, ignore_configuration);
+ if (UNLIKELY(!result.has_value())) {
+ return base::unexpected(result.error());
}
- if (!apk_assets_[cookie]->IsLoader()) {
+ if (!stop_at_first_match && !ignore_configuration && !apk_assets_[result->cookie]->IsLoader()) {
for (const auto& id_map : package_group.overlays_) {
auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
if (!overlay_entry) {
// No id map entry exists for this target resource.
continue;
- } else if (overlay_entry.IsInlineValue()) {
+ }
+ if (overlay_entry.IsInlineValue()) {
// The target resource is overlaid by an inline value not represented by a resource.
- out_entry->entry = overlay_entry.GetInlineValue();
- out_entry->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
- cookie = id_map.cookie;
+ result->entry = overlay_entry.GetInlineValue();
+ result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
+ result->cookie = id_map.cookie;
continue;
}
- FindEntryResult overlay_result;
- ApkAssetsCookie overlay_cookie = FindEntry(overlay_entry.GetResourceId(), density_override,
- false /* stop_at_first_match */,
- ignore_configuration, &overlay_result);
- if (UNLIKELY(overlay_cookie == kInvalidCookie)) {
+ auto overlay_result = FindEntry(overlay_entry.GetResourceId(), density_override,
+ false /* stop_at_first_match */,
+ false /* ignore_configuration */);
+ if (UNLIKELY(IsIOError(overlay_result))) {
+ return base::unexpected(overlay_result.error());
+ }
+ if (!overlay_result.has_value()) {
continue;
}
- if (!overlay_result.config.isBetterThan(out_entry->config, desired_config)
- && overlay_result.config.compare(out_entry->config) != 0) {
+ if (!overlay_result->config.isBetterThan(result->config, desired_config)
+ && overlay_result->config.compare(result->config) != 0) {
// The configuration of the entry for the overlay must be equal to or better than the target
// configuration to be chosen as the better value.
continue;
}
- cookie = overlay_cookie;
- out_entry->entry = overlay_result.entry;
- out_entry->config = overlay_result.config;
- out_entry->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
- if (resource_resolution_logging_enabled_) {
+ result->cookie = overlay_result->cookie;
+ result->entry = overlay_result->entry;
+ result->config = overlay_result->config;
+ result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
+
+ if (UNLIKELY(logging_enabled)) {
last_resolution_.steps.push_back(
- Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result.config.toString(),
- overlay_result.package_name});
+ Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result->config.toString(),
+ overlay_result->package_name});
}
}
}
- if (resource_resolution_logging_enabled_) {
- last_resolution_.cookie = cookie;
- last_resolution_.type_string_ref = out_entry->type_string_ref;
- last_resolution_.entry_string_ref = out_entry->entry_string_ref;
+ if (UNLIKELY(logging_enabled)) {
+ last_resolution_.cookie = result->cookie;
+ last_resolution_.type_string_ref = result->type_string_ref;
+ last_resolution_.entry_string_ref = result->entry_string_ref;
}
- return cookie;
+ return result;
}
-ApkAssetsCookie AssetManager2::FindEntryInternal(const PackageGroup& package_group,
- uint8_t type_idx, uint16_t entry_idx,
- const ResTable_config& desired_config,
- bool /*stop_at_first_match*/,
- bool ignore_configuration,
- FindEntryResult* out_entry) const {
+base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
+ const PackageGroup& package_group, uint8_t type_idx, uint16_t entry_idx,
+ const ResTable_config& desired_config, bool stop_at_first_match,
+ bool ignore_configuration) const {
+ const bool logging_enabled = resource_resolution_logging_enabled_;
ApkAssetsCookie best_cookie = kInvalidCookie;
const LoadedPackage* best_package = nullptr;
- const ResTable_type* best_type = nullptr;
+ incfs::verified_map_ptr<ResTable_type> best_type;
const ResTable_config* best_config = nullptr;
ResTable_config best_config_copy;
- uint32_t best_offset = 0u;
- uint32_t type_flags = 0u;
+ uint32_t best_offset = 0U;
+ uint32_t type_flags = 0U;
- Resolution::Step::Type resolution_type = Resolution::Step::Type::NO_ENTRY;
+ auto resolution_type = Resolution::Step::Type::NO_ENTRY;
std::vector<Resolution::Step> resolution_steps;
// If desired_config is the same as the set configuration, then we can use our filtered list
@@ -630,17 +669,20 @@ ApkAssetsCookie AssetManager2::FindEntryInternal(const PackageGroup& package_gro
continue;
}
+ auto entry_flags = type_spec->GetFlagsForEntryIndex(entry_idx);
+ if (UNLIKELY(!entry_flags)) {
+ return base::unexpected(entry_flags.error());
+ }
+ type_flags |= entry_flags.value();
+
// If the package is an overlay or custom loader,
// then even configurations that are the same MUST be chosen.
const bool package_is_loader = loaded_package->IsCustomLoader();
- type_flags |= type_spec->GetFlagsForEntryIndex(entry_idx);
if (use_fast_path) {
const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
- const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations;
- const size_t type_count = candidate_configs.size();
- for (uint32_t i = 0; i < type_count; i++) {
- const ResTable_config& this_config = candidate_configs[i];
+ for (const auto& type_config : filtered_group.type_configs) {
+ const ResTable_config& this_config = type_config.config;
// We can skip calling ResTable_config::match() because we know that all candidate
// configurations that do NOT match have been filtered-out.
@@ -652,7 +694,7 @@ ApkAssetsCookie AssetManager2::FindEntryInternal(const PackageGroup& package_gro
} else if (package_is_loader && this_config.compare(*best_config) == 0) {
resolution_type = Resolution::Step::Type::OVERLAID_LOADER;
} else {
- if (resource_resolution_logging_enabled_) {
+ if (UNLIKELY(logging_enabled)) {
resolution_type = (package_is_loader) ? Resolution::Step::Type::SKIPPED_LOADER
: Resolution::Step::Type::SKIPPED;
resolution_steps.push_back(Resolution::Step{resolution_type,
@@ -664,10 +706,13 @@ ApkAssetsCookie AssetManager2::FindEntryInternal(const PackageGroup& package_gro
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
- const ResTable_type* type = filtered_group.types[i];
- const uint32_t offset = LoadedPackage::GetEntryOffset(type, entry_idx);
- if (offset == ResTable_type::NO_ENTRY) {
- if (resource_resolution_logging_enabled_) {
+ const auto& type = type_config.type;
+ const auto offset = LoadedPackage::GetEntryOffset(type, entry_idx);
+ if (UNLIKELY(IsIOError(offset))) {
+ return base::unexpected(offset.error());
+ }
+ if (!offset.has_value()) {
+ if (UNLIKELY(logging_enabled)) {
if (package_is_loader) {
resolution_type = Resolution::Step::Type::NO_ENTRY_LOADER;
} else {
@@ -684,9 +729,9 @@ ApkAssetsCookie AssetManager2::FindEntryInternal(const PackageGroup& package_gro
best_package = loaded_package;
best_type = type;
best_config = &this_config;
- best_offset = offset;
+ best_offset = offset.value();
- if (resource_resolution_logging_enabled_) {
+ if (UNLIKELY(logging_enabled)) {
last_resolution_.steps.push_back(Resolution::Step{resolution_type,
this_config.toString(),
&loaded_package->GetPackageName()});
@@ -700,10 +745,11 @@ ApkAssetsCookie AssetManager2::FindEntryInternal(const PackageGroup& package_gro
// ResTable_config, we must copy it.
const auto iter_end = type_spec->types + type_spec->type_count;
for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- ResTable_config this_config{};
+ const incfs::verified_map_ptr<ResTable_type>& type = *iter;
+ ResTable_config this_config{};
if (!ignore_configuration) {
- this_config.copyFromDtoH((*iter)->config);
+ this_config.copyFromDtoH(type->config);
if (!this_config.match(desired_config)) {
continue;
}
@@ -722,24 +768,27 @@ ApkAssetsCookie AssetManager2::FindEntryInternal(const PackageGroup& package_gro
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
- const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, entry_idx);
- if (offset == ResTable_type::NO_ENTRY) {
+ const auto offset = LoadedPackage::GetEntryOffset(type, entry_idx);
+ if (UNLIKELY(IsIOError(offset))) {
+ return base::unexpected(offset.error());
+ }
+ if (!offset.has_value()) {
continue;
}
best_cookie = cookie;
best_package = loaded_package;
- best_type = *iter;
+ best_type = type;
best_config_copy = this_config;
best_config = &best_config_copy;
- best_offset = offset;
+ best_offset = offset.value();
- if (ignore_configuration) {
+ if (stop_at_first_match) {
// Any configuration will suffice, so break.
break;
}
- if (resource_resolution_logging_enabled_) {
+ if (UNLIKELY(logging_enabled)) {
last_resolution_.steps.push_back(Resolution::Step{resolution_type,
this_config.toString(),
&loaded_package->GetPackageName()});
@@ -749,36 +798,35 @@ ApkAssetsCookie AssetManager2::FindEntryInternal(const PackageGroup& package_gro
}
if (UNLIKELY(best_cookie == kInvalidCookie)) {
- return kInvalidCookie;
+ return base::unexpected(std::nullopt);
}
- const ResTable_entry* best_entry = LoadedPackage::GetEntryFromOffset(best_type, best_offset);
- if (UNLIKELY(best_entry == nullptr)) {
- return kInvalidCookie;
+ auto best_entry_result = LoadedPackage::GetEntryFromOffset(best_type, best_offset);
+ if (!best_entry_result.has_value()) {
+ return base::unexpected(best_entry_result.error());
}
- const uint16_t entry_size = dtohs(best_entry->size);
- if (entry_size >= sizeof(ResTable_map_entry) &&
- (dtohs(best_entry->flags) & ResTable_entry::FLAG_COMPLEX)) {
- // The entry represents a bag/map.
- out_entry->entry = reinterpret_cast<const ResTable_map_entry*>(best_entry);
- } else {
- // The entry represents a value.
- Res_value value;
- value.copyFrom_dtoh(*reinterpret_cast<const Res_value*>(
- reinterpret_cast<const uint8_t*>(best_entry) + entry_size));
- out_entry->entry = value;
- }
-
- out_entry->config = *best_config;
- out_entry->type_flags = type_flags;
- out_entry->package_name = &best_package->GetPackageName();
- out_entry->type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
- out_entry->entry_string_ref =
- StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
- out_entry->dynamic_ref_table = package_group.dynamic_ref_table.get();
-
- return best_cookie;
+ const incfs::map_ptr<ResTable_entry> best_entry = *best_entry_result;
+ if (!best_entry) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ const auto entry = GetEntryValue(best_entry.verified());
+ if (!entry.has_value()) {
+ return base::unexpected(entry.error());
+ }
+
+ return FindEntryResult{
+ .cookie = best_cookie,
+ .entry = *entry,
+ .config = *best_config,
+ .type_flags = type_flags,
+ .package_name = &best_package->GetPackageName(),
+ .type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1),
+ .entry_string_ref = StringPoolRef(best_package->GetKeyStringPool(),
+ best_entry->key.index),
+ .dynamic_ref_table = package_group.dynamic_ref_table.get(),
+ };
}
void AssetManager2::ResetResourceResolution() const {
@@ -799,30 +847,28 @@ void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) {
std::string AssetManager2::GetLastResourceResolution() const {
if (!resource_resolution_logging_enabled_) {
LOG(ERROR) << "Must enable resource resolution logging before getting path.";
- return std::string();
+ return {};
}
auto cookie = last_resolution_.cookie;
if (cookie == kInvalidCookie) {
LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path.";
- return std::string();
+ return {};
}
uint32_t resid = last_resolution_.resid;
std::vector<Resolution::Step>& steps = last_resolution_.steps;
-
- ResourceName resource_name;
std::string resource_name_string;
const LoadedPackage* package =
apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
if (package != nullptr) {
- ToResourceName(last_resolution_.type_string_ref,
- last_resolution_.entry_string_ref,
- package->GetPackageName(),
- &resource_name);
- resource_name_string = ToFormattedResourceString(&resource_name);
+ auto resource_name = ToResourceName(last_resolution_.type_string_ref,
+ last_resolution_.entry_string_ref,
+ package->GetPackageName());
+ resource_name_string = resource_name.has_value() ?
+ ToFormattedResourceString(resource_name.value()) : "<unknown>";
}
std::stringstream log_stream;
@@ -875,200 +921,201 @@ std::string AssetManager2::GetLastResourceResolution() const {
return log_stream.str();
}
-bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
- FindEntryResult entry;
- ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
- true /* stop_at_first_match */,
- true /* ignore_configuration */, &entry);
- if (cookie == kInvalidCookie) {
- return false;
+base::expected<AssetManager2::ResourceName, NullOrIOError> AssetManager2::GetResourceName(
+ uint32_t resid) const {
+ auto result = FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */,
+ true /* ignore_configuration */);
+ if (!result.has_value()) {
+ return base::unexpected(result.error());
}
- return ToResourceName(entry.type_string_ref,
- entry.entry_string_ref,
- *entry.package_name,
- out_name);
+ return ToResourceName(result->type_string_ref,
+ result->entry_string_ref,
+ *result->package_name);
}
-bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
- FindEntryResult entry;
- ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
- false /* stop_at_first_match */,
- true /* ignore_configuration */, &entry);
- if (cookie != kInvalidCookie) {
- *out_flags = entry.type_flags;
- return true;
+base::expected<AssetManager2::SelectedValue, NullOrIOError> AssetManager2::GetResource(
+ uint32_t resid, bool may_be_bag, uint16_t density_override) const {
+ auto result = FindEntry(resid, density_override, false /* stop_at_first_match */,
+ false /* ignore_configuration */);
+ if (!result.has_value()) {
+ return base::unexpected(result.error());
}
- return false;
-}
-ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
- uint16_t density_override, Res_value* out_value,
- ResTable_config* out_selected_config,
- uint32_t* out_flags) const {
- FindEntryResult entry;
- ApkAssetsCookie cookie = FindEntry(resid, density_override, false /* stop_at_first_match */,
- false /* ignore_configuration */, &entry);
- if (cookie == kInvalidCookie) {
- return kInvalidCookie;
- }
-
- auto result_map_entry = std::get_if<const ResTable_map_entry*>(&entry.entry);
+ auto result_map_entry = std::get_if<incfs::verified_map_ptr<ResTable_map_entry>>(&result->entry);
if (result_map_entry != nullptr) {
if (!may_be_bag) {
LOG(ERROR) << base::StringPrintf("Resource %08x is a complex map type.", resid);
- return kInvalidCookie;
+ return base::unexpected(std::nullopt);
}
// Create a reference since we can't represent this complex type as a Res_value.
- out_value->dataType = Res_value::TYPE_REFERENCE;
- out_value->data = resid;
- *out_selected_config = entry.config;
- *out_flags = entry.type_flags;
- return cookie;
+ return SelectedValue(Res_value::TYPE_REFERENCE, resid, result->cookie, result->type_flags,
+ resid, result->config);
}
// Convert the package ID to the runtime assigned package ID.
- *out_value = std::get<Res_value>(entry.entry);
- entry.dynamic_ref_table->lookupResourceValue(out_value);
+ Res_value value = std::get<Res_value>(result->entry);
+ result->dynamic_ref_table->lookupResourceValue(&value);
- *out_selected_config = entry.config;
- *out_flags = entry.type_flags;
- return cookie;
+ return SelectedValue(value.dataType, value.data, result->cookie, result->type_flags,
+ resid, result->config);
}
-ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
- ResTable_config* in_out_selected_config,
- uint32_t* in_out_flags,
- uint32_t* out_last_reference) const {
- constexpr const int kMaxIterations = 20;
-
- for (size_t iteration = 0u; in_out_value->dataType == Res_value::TYPE_REFERENCE &&
- in_out_value->data != 0u && iteration < kMaxIterations;
- iteration++) {
- *out_last_reference = in_out_value->data;
- uint32_t new_flags = 0u;
- cookie = GetResource(in_out_value->data, true /*may_be_bag*/, 0u /*density_override*/,
- in_out_value, in_out_selected_config, &new_flags);
- if (cookie == kInvalidCookie) {
- return kInvalidCookie;
+base::expected<std::monostate, NullOrIOError> AssetManager2::ResolveReference(
+ AssetManager2::SelectedValue& value, bool cache_value) const {
+ if (value.type != Res_value::TYPE_REFERENCE || value.data == 0U) {
+ // Not a reference. Nothing to do.
+ return {};
+ }
+
+ const uint32_t original_flags = value.flags;
+ const uint32_t original_resid = value.data;
+ if (cache_value) {
+ auto cached_value = cached_resolved_values_.find(value.data);
+ if (cached_value != cached_resolved_values_.end()) {
+ value = cached_value->second;
+ value.flags |= original_flags;
+ return {};
}
- if (in_out_flags != nullptr) {
- *in_out_flags |= new_flags;
+ }
+
+ uint32_t combined_flags = 0U;
+ uint32_t resolve_resid = original_resid;
+ constexpr const uint32_t kMaxIterations = 20;
+ for (uint32_t i = 0U;; i++) {
+ auto result = GetResource(resolve_resid, true /*may_be_bag*/);
+ if (!result.has_value()) {
+ return base::unexpected(result.error());
}
- if (*out_last_reference == in_out_value->data) {
- // This reference can't be resolved, so exit now and let the caller deal with it.
- return cookie;
+
+ if (result->type != Res_value::TYPE_REFERENCE ||
+ result->data == Res_value::DATA_NULL_UNDEFINED ||
+ result->data == resolve_resid || i == kMaxIterations) {
+ result->flags |= combined_flags;
+ if (cache_value) {
+ cached_resolved_values_[original_resid] = *result;
+ }
+
+ // Add the original flags after caching the result so queries with a different set of original
+ // flags do not include these original flags.
+ value = *result;
+ value.flags |= original_flags;
+ return {};
}
+
+ combined_flags |= result->flags;
+ resolve_resid = result->data;
}
- return cookie;
}
-const std::vector<uint32_t> AssetManager2::GetBagResIdStack(uint32_t resid) {
+const std::vector<uint32_t> AssetManager2::GetBagResIdStack(uint32_t resid) const {
auto cached_iter = cached_bag_resid_stacks_.find(resid);
if (cached_iter != cached_bag_resid_stacks_.end()) {
return cached_iter->second;
- } else {
- auto found_resids = std::vector<uint32_t>();
- GetBag(resid, found_resids);
- // Cache style stacks if they are not already cached.
- cached_bag_resid_stacks_[resid] = found_resids;
- return found_resids;
}
+
+ std::vector<uint32_t> found_resids;
+ GetBag(resid, found_resids);
+ cached_bag_resid_stacks_.emplace(resid, found_resids);
+ return found_resids;
}
-const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
- auto found_resids = std::vector<uint32_t>();
- auto bag = GetBag(resid, found_resids);
+base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::ResolveBag(
+ AssetManager2::SelectedValue& value) const {
+ if (UNLIKELY(value.type != Res_value::TYPE_REFERENCE)) {
+ return base::unexpected(std::nullopt);
+ }
- // Cache style stacks if they are not already cached.
- auto cached_iter = cached_bag_resid_stacks_.find(resid);
- if (cached_iter == cached_bag_resid_stacks_.end()) {
- cached_bag_resid_stacks_[resid] = found_resids;
+ auto bag = GetBag(value.data);
+ if (bag.has_value()) {
+ value.flags |= (*bag)->type_spec_flags;
}
return bag;
}
-static bool compare_bag_entries(const ResolvedBag::Entry& entry1,
- const ResolvedBag::Entry& entry2) {
- return entry1.key < entry2.key;
+base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(uint32_t resid) const {
+ std::vector<uint32_t> found_resids;
+ return GetBag(resid, found_resids);
}
-const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& child_resids) {
- auto cached_iter = cached_bags_.find(resid);
- if (cached_iter != cached_bags_.end()) {
+base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(
+ uint32_t resid, std::vector<uint32_t>& child_resids) const {
+ if (auto cached_iter = cached_bags_.find(resid); cached_iter != cached_bags_.end()) {
return cached_iter->second.get();
}
- FindEntryResult entry;
- ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
- false /* stop_at_first_match */,
- false /* ignore_configuration */,
- &entry);
- if (cookie == kInvalidCookie) {
- return nullptr;
+ auto entry = FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */,
+ false /* ignore_configuration */);
+ if (!entry.has_value()) {
+ return base::unexpected(entry.error());
}
- auto result_map_entry = std::get_if<const ResTable_map_entry*>(&entry.entry);
- if (result_map_entry == nullptr) {
+ auto entry_map = std::get_if<incfs::verified_map_ptr<ResTable_map_entry>>(&entry->entry);
+ if (entry_map == nullptr) {
// Not a bag, nothing to do.
- return nullptr;
+ return base::unexpected(std::nullopt);
}
- auto map = reinterpret_cast<const ResTable_map_entry*>(*result_map_entry);
- auto map_entry = reinterpret_cast<const ResTable_map*>(
- reinterpret_cast<const uint8_t*>(map) + map->size);
- const ResTable_map* const map_entry_end = map_entry + dtohl(map->count);
+ auto map = *entry_map;
+ auto map_entry = map.offset(dtohs(map->size)).convert<ResTable_map>();
+ const auto map_entry_end = map_entry + dtohl(map->count);
// Keep track of ids that have already been seen to prevent infinite loops caused by circular
- // dependencies between bags
+ // dependencies between bags.
child_resids.push_back(resid);
uint32_t parent_resid = dtohl(map->parent.ident);
- if (parent_resid == 0U || std::find(child_resids.begin(), child_resids.end(), parent_resid)
- != child_resids.end()) {
- // There is no parent or a circular dependency exist, meaning there is nothing to inherit and
- // we can do a simple copy of the entries in the map.
+ if (parent_resid == 0U ||
+ std::find(child_resids.begin(), child_resids.end(), parent_resid) != child_resids.end()) {
+ // There is no parent or a circular parental dependency exist, meaning there is nothing to
+ // inherit and we can do a simple copy of the entries in the map.
const size_t entry_count = map_entry_end - map_entry;
util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>(
malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))};
bool sort_entries = false;
- ResolvedBag::Entry* new_entry = new_bag->entries;
- for (; map_entry != map_entry_end; ++map_entry) {
+ for (auto new_entry = new_bag->entries; map_entry != map_entry_end; ++map_entry) {
+ if (UNLIKELY(!map_entry)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
uint32_t new_key = dtohl(map_entry->name.ident);
if (!is_internal_resid(new_key)) {
// Attributes, arrays, etc don't have a resource id as the name. They specify
// other data, which would be wrong to change via a lookup.
- if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
+ if (UNLIKELY(entry->dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
resid);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
}
- new_entry->cookie = cookie;
+
+ new_entry->cookie = entry->cookie;
new_entry->key = new_key;
new_entry->key_pool = nullptr;
new_entry->type_pool = nullptr;
new_entry->style = resid;
new_entry->value.copyFrom_dtoh(map_entry->value);
- status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
- if (err != NO_ERROR) {
+ status_t err = entry->dynamic_ref_table->lookupResourceValue(&new_entry->value);
+ if (UNLIKELY(err != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf(
"Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.", new_entry->value.dataType,
new_entry->value.data, new_key);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
+
sort_entries = sort_entries ||
(new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
++new_entry;
}
if (sort_entries) {
- std::sort(new_bag->entries, new_bag->entries + entry_count, compare_bag_entries);
+ std::sort(new_bag->entries, new_bag->entries + entry_count,
+ [](auto&& lhs, auto&& rhs) { return lhs.key < rhs.key; });
}
- new_bag->type_spec_flags = entry.type_flags;
+ new_bag->type_spec_flags = entry->type_flags;
new_bag->entry_count = static_cast<uint32_t>(entry_count);
ResolvedBag* result = new_bag.get();
cached_bags_[resid] = std::move(new_bag);
@@ -1076,54 +1123,58 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
}
// In case the parent is a dynamic reference, resolve it.
- entry.dynamic_ref_table->lookupResourceId(&parent_resid);
+ entry->dynamic_ref_table->lookupResourceId(&parent_resid);
// Get the parent and do a merge of the keys.
- const ResolvedBag* parent_bag = GetBag(parent_resid, child_resids);
- if (parent_bag == nullptr) {
+ const auto parent_bag = GetBag(parent_resid, child_resids);
+ if (UNLIKELY(!parent_bag.has_value())) {
// Failed to get the parent that should exist.
LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid,
resid);
- return nullptr;
+ return base::unexpected(parent_bag.error());
}
// Create the max possible entries we can make. Once we construct the bag,
// we will realloc to fit to size.
- const size_t max_count = parent_bag->entry_count + dtohl(map->count);
+ const size_t max_count = (*parent_bag)->entry_count + dtohl(map->count);
util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>(
malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry))))};
ResolvedBag::Entry* new_entry = new_bag->entries;
- const ResolvedBag::Entry* parent_entry = parent_bag->entries;
- const ResolvedBag::Entry* const parent_entry_end = parent_entry + parent_bag->entry_count;
+ const ResolvedBag::Entry* parent_entry = (*parent_bag)->entries;
+ const ResolvedBag::Entry* const parent_entry_end = parent_entry + (*parent_bag)->entry_count;
// The keys are expected to be in sorted order. Merge the two bags.
bool sort_entries = false;
while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
+ if (UNLIKELY(!map_entry)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
uint32_t child_key = dtohl(map_entry->name.ident);
if (!is_internal_resid(child_key)) {
- if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) {
+ if (UNLIKELY(entry->dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key,
resid);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
}
if (child_key <= parent_entry->key) {
// Use the child key if it comes before the parent
// or is equal to the parent (overrides).
- new_entry->cookie = cookie;
+ new_entry->cookie = entry->cookie;
new_entry->key = child_key;
new_entry->key_pool = nullptr;
new_entry->type_pool = nullptr;
new_entry->value.copyFrom_dtoh(map_entry->value);
new_entry->style = resid;
- status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
- if (err != NO_ERROR) {
+ status_t err = entry->dynamic_ref_table->lookupResourceValue(&new_entry->value);
+ if (UNLIKELY(err != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf(
"Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.", new_entry->value.dataType,
new_entry->value.data, child_key);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
++map_entry;
} else {
@@ -1143,25 +1194,29 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
// Finish the child entries if they exist.
while (map_entry != map_entry_end) {
+ if (UNLIKELY(!map_entry)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
uint32_t new_key = dtohl(map_entry->name.ident);
if (!is_internal_resid(new_key)) {
- if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
+ if (UNLIKELY(entry->dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
resid);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
}
- new_entry->cookie = cookie;
+ new_entry->cookie = entry->cookie;
new_entry->key = new_key;
new_entry->key_pool = nullptr;
new_entry->type_pool = nullptr;
new_entry->value.copyFrom_dtoh(map_entry->value);
new_entry->style = resid;
- status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
- if (err != NO_ERROR) {
+ status_t err = entry->dynamic_ref_table->lookupResourceValue(&new_entry->value);
+ if (UNLIKELY(err != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf("Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.",
new_entry->value.dataType, new_entry->value.data, new_key);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
sort_entries = sort_entries ||
(new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
@@ -1185,11 +1240,12 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>&
}
if (sort_entries) {
- std::sort(new_bag->entries, new_bag->entries + actual_count, compare_bag_entries);
+ std::sort(new_bag->entries, new_bag->entries + actual_count,
+ [](auto&& lhs, auto&& rhs) { return lhs.key < rhs.key; });
}
// Combine flags from the parent and our own bag.
- new_bag->type_spec_flags = entry.type_flags | parent_bag->type_spec_flags;
+ new_bag->type_spec_flags = entry->type_flags | (*parent_bag)->type_spec_flags;
new_bag->entry_count = static_cast<uint32_t>(actual_count);
ResolvedBag* result = new_bag.get();
cached_bags_[resid] = std::move(new_bag);
@@ -1208,16 +1264,16 @@ static bool Utf8ToUtf16(const StringPiece& str, std::u16string* out) {
return true;
}
-uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
- const std::string& fallback_type,
- const std::string& fallback_package) const {
+base::expected<uint32_t, NullOrIOError> AssetManager2::GetResourceId(
+ const std::string& resource_name, const std::string& fallback_type,
+ const std::string& fallback_package) const {
StringPiece package_name, type, entry;
if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) {
- return 0u;
+ return base::unexpected(std::nullopt);
}
if (entry.empty()) {
- return 0u;
+ return base::unexpected(std::nullopt);
}
if (package_name.empty()) {
@@ -1230,12 +1286,12 @@ uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
std::u16string type16;
if (!Utf8ToUtf16(type, &type16)) {
- return 0u;
+ return base::unexpected(std::nullopt);
}
std::u16string entry16;
if (!Utf8ToUtf16(entry, &entry16)) {
- return 0u;
+ return base::unexpected(std::nullopt);
}
const StringPiece16 kAttr16 = u"attr";
@@ -1249,20 +1305,24 @@ uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
break;
}
- uint32_t resid = package->FindEntryByName(type16, entry16);
- if (resid == 0u && kAttr16 == type16) {
+ base::expected<uint32_t, NullOrIOError> resid = package->FindEntryByName(type16, entry16);
+ if (UNLIKELY(IsIOError(resid))) {
+ return base::unexpected(resid.error());
+ }
+
+ if (!resid.has_value() && kAttr16 == type16) {
// Private attributes in libraries (such as the framework) are sometimes encoded
// under the type '^attr-private' in order to leave the ID space of public 'attr'
// free for future additions. Check '^attr-private' for the same name.
resid = package->FindEntryByName(kAttrPrivate16, entry16);
}
- if (resid != 0u) {
- return fix_package_id(resid, package_group.dynamic_ref_table->mAssignedPackageId);
+ if (resid.has_value()) {
+ return fix_package_id(*resid, package_group.dynamic_ref_table->mAssignedPackageId);
}
}
}
- return 0u;
+ return base::unexpected(std::nullopt);
}
void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) {
@@ -1282,8 +1342,7 @@ void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) {
ResTable_config this_config;
this_config.copyFromDtoH((*iter)->config);
if (!filter_incompatible_configs || this_config.match(configuration_)) {
- group.configurations.push_back(this_config);
- group.types.push_back(*iter);
+ group.type_configs.push_back(TypeConfig{*iter, this_config});
}
}
});
@@ -1309,6 +1368,8 @@ void AssetManager2::InvalidateCaches(uint32_t diff) {
++iter;
}
}
+
+ cached_resolved_values_.clear();
}
uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const {
@@ -1354,16 +1415,16 @@ struct Theme::Package {
std::array<util::unique_cptr<ThemeType>, kTypeCount> types;
};
-bool Theme::ApplyStyle(uint32_t resid, bool force) {
+base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid, bool force) {
ATRACE_NAME("Theme::ApplyStyle");
- const ResolvedBag* bag = asset_manager_->GetBag(resid);
- if (bag == nullptr) {
- return false;
+ auto bag = asset_manager_->GetBag(resid);
+ if (!bag.has_value()) {
+ return base::unexpected(bag.error());
}
// Merge the flags from this style.
- type_spec_flags_ |= bag->type_spec_flags;
+ type_spec_flags_ |= (*bag)->type_spec_flags;
int last_type_idx = -1;
int last_package_idx = -1;
@@ -1373,14 +1434,14 @@ bool Theme::ApplyStyle(uint32_t resid, bool force) {
// Iterate backwards, because each bag is sorted in ascending key ID order, meaning we will only
// need to perform one resize per type.
using reverse_bag_iterator = std::reverse_iterator<const ResolvedBag::Entry*>;
- const auto bag_iter_end = reverse_bag_iterator(begin(bag));
- for (auto bag_iter = reverse_bag_iterator(end(bag)); bag_iter != bag_iter_end; ++bag_iter) {
- const uint32_t attr_resid = bag_iter->key;
+ const auto rbegin = reverse_bag_iterator(begin(*bag));
+ for (auto it = reverse_bag_iterator(end(*bag)); it != rbegin; ++it) {
+ const uint32_t attr_resid = it->key;
// If the resource ID passed in is not a style, the key can be some other identifier that is not
// a resource ID. We should fail fast instead of operating with strange resource IDs.
if (!is_valid_resid(attr_resid)) {
- return false;
+ return base::unexpected(std::nullopt);
}
// We don't use the 0-based index for the type so that we can avoid doing ID validation
@@ -1428,20 +1489,18 @@ bool Theme::ApplyStyle(uint32_t resid, bool force) {
ThemeEntry& entry = last_type->entries[entry_idx];
if (force || (entry.value.dataType == Res_value::TYPE_NULL &&
entry.value.data != Res_value::DATA_NULL_EMPTY)) {
- entry.cookie = bag_iter->cookie;
- entry.type_spec_flags |= bag->type_spec_flags;
- entry.value = bag_iter->value;
+ entry.cookie = it->cookie;
+ entry.type_spec_flags |= (*bag)->type_spec_flags;
+ entry.value = it->value;
}
}
- return true;
+ return {};
}
-ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value,
- uint32_t* out_flags) const {
- int cnt = 20;
+std::optional<AssetManager2::SelectedValue> Theme::GetAttribute(uint32_t resid) const {
+ int cnt = 20;
uint32_t type_spec_flags = 0u;
-
do {
const int package_idx = get_package_id(resid);
const Package* package = packages_[package_idx].get();
@@ -1461,43 +1520,42 @@ ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value,
resid = entry.value.data;
continue;
}
- return kInvalidCookie;
+ return std::nullopt;
}
// @null is different than @empty.
if (entry.value.dataType == Res_value::TYPE_NULL &&
entry.value.data != Res_value::DATA_NULL_EMPTY) {
- return kInvalidCookie;
+ return std::nullopt;
}
- *out_value = entry.value;
- *out_flags = type_spec_flags;
- return entry.cookie;
+ return AssetManager2::SelectedValue(entry.value.dataType, entry.value.data, entry.cookie,
+ type_spec_flags, 0U /* resid */, {} /* config */);
}
}
}
break;
} while (true);
- return kInvalidCookie;
+ return std::nullopt;
}
-ApkAssetsCookie Theme::ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
- ResTable_config* in_out_selected_config,
- uint32_t* in_out_type_spec_flags,
- uint32_t* out_last_ref) const {
- if (in_out_value->dataType == Res_value::TYPE_ATTRIBUTE) {
- uint32_t new_flags;
- cookie = GetAttribute(in_out_value->data, in_out_value, &new_flags);
- if (cookie == kInvalidCookie) {
- return kInvalidCookie;
- }
+base::expected<std::monostate, NullOrIOError> Theme::ResolveAttributeReference(
+ AssetManager2::SelectedValue& value) const {
+ if (value.type != Res_value::TYPE_ATTRIBUTE) {
+ return asset_manager_->ResolveReference(value);
+ }
- if (in_out_type_spec_flags != nullptr) {
- *in_out_type_spec_flags |= new_flags;
- }
+ std::optional<AssetManager2::SelectedValue> result = GetAttribute(value.data);
+ if (!result.has_value()) {
+ return base::unexpected(std::nullopt);
}
- return asset_manager_->ResolveReference(cookie, in_out_value, in_out_selected_config,
- in_out_type_spec_flags, out_last_ref);
+
+ auto resolve_result = asset_manager_->ResolveReference(*result, true /* cache_value */);
+ if (resolve_result.has_value()) {
+ result->flags |= value.flags;
+ value = *result;
+ }
+ return resolve_result;
}
void Theme::Clear() {
@@ -1507,9 +1565,9 @@ void Theme::Clear() {
}
}
-void Theme::SetTo(const Theme& o) {
+base::expected<std::monostate, IOError> Theme::SetTo(const Theme& o) {
if (this == &o) {
- return;
+ return {};
}
type_spec_flags_ = o.type_spec_flags_;
@@ -1560,10 +1618,8 @@ void Theme::SetTo(const Theme& o) {
// Map the runtime package of the source apk asset to the destination apk asset.
if (src_asset->GetPath() == dest_asset->GetPath()) {
- const std::vector<std::unique_ptr<const LoadedPackage>>& src_packages =
- src_asset->GetLoadedArsc()->GetPackages();
- const std::vector<std::unique_ptr<const LoadedPackage>>& dest_packages =
- dest_asset->GetLoadedArsc()->GetPackages();
+ const auto& src_packages = src_asset->GetLoadedArsc()->GetPackages();
+ const auto& dest_packages = dest_asset->GetLoadedArsc()->GetPackages();
SourceToDestinationRuntimePackageMap package_map;
@@ -1660,15 +1716,20 @@ void Theme::SetTo(const Theme& o) {
int attribute_dest_package_id = p;
if (attribute_dest_package_id != 0x01) {
// Find the cookie of the attribute resource id in the source AssetManager
- FindEntryResult attribute_entry_result;
- ApkAssetsCookie attribute_cookie =
+ base::expected<FindEntryResult, NullOrIOError> attribute_entry_result =
o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ ,
true /* stop_at_first_match */,
- true /* ignore_configuration */,
- &attribute_entry_result);
+ true /* ignore_configuration */);
+ if (UNLIKELY(IsIOError(attribute_entry_result))) {
+ return base::unexpected(GetIOError(attribute_entry_result.error()));
+ }
+ if (!attribute_entry_result.has_value()) {
+ continue;
+ }
// Determine the package id of the attribute in the destination AssetManager.
- auto attribute_package_map = src_asset_cookie_id_map.find(attribute_cookie);
+ auto attribute_package_map = src_asset_cookie_id_map.find(
+ attribute_entry_result->cookie);
if (attribute_package_map == src_asset_cookie_id_map.end()) {
continue;
}
@@ -1712,6 +1773,7 @@ void Theme::SetTo(const Theme& o) {
}
}
}
+ return {};
}
void Theme::Dump() const {
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index e62fb614e195..347b4ec8346c 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -24,9 +24,12 @@
#include "androidfw/AttributeFinder.h"
constexpr bool kDebugStyles = false;
+#define DEBUG_LOG(...) do { if (kDebugStyles) { ALOGI(__VA_ARGS__); } } while(0)
namespace android {
+namespace {
+
// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
static uint32_t ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
return cookie != kInvalidCookie ? static_cast<uint32_t>(cookie + 1) : static_cast<uint32_t>(-1);
@@ -36,8 +39,7 @@ class XmlAttributeFinder
: public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
public:
explicit XmlAttributeFinder(const ResXMLParser* parser)
- : BackTrackingAttributeFinder(
- 0, parser != nullptr ? parser->getAttributeCount() : 0),
+ : BackTrackingAttributeFinder(0, parser != nullptr ? parser->getAttributeCount() : 0),
parser_(parser) {}
inline uint32_t GetAttribute(size_t index) const {
@@ -61,136 +63,149 @@ class BagAttributeFinder
}
};
-bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
- uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
- size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
- if (kDebugStyles) {
- ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
- def_style_attr, def_style_res);
+base::expected<const ResolvedBag*, NullOrIOError> GetStyleBag(Theme* theme,
+ uint32_t theme_attribute_resid,
+ uint32_t fallback_resid,
+ uint32_t* out_theme_flags) {
+ // Load the style from the attribute if specified.
+ if (theme_attribute_resid != 0U) {
+ std::optional<AssetManager2::SelectedValue> value = theme->GetAttribute(theme_attribute_resid);
+ if (value.has_value()) {
+ *out_theme_flags |= value->flags;
+ auto result = theme->GetAssetManager()->ResolveBag(*value);
+ if (result.has_value() || IsIOError(result)) {
+ return result;
+ }
+ }
}
- AssetManager2* assetmanager = theme->GetAssetManager();
- ResTable_config config;
- Res_value value;
+ // Fallback to loading the style from the resource id if specified.
+ if (fallback_resid != 0U) {
+ return theme->GetAssetManager()->GetBag(fallback_resid);
+ }
- int indices_idx = 0;
+ return base::unexpected(std::nullopt);
+}
- // Load default style from attribute, if specified...
- uint32_t def_style_flags = 0u;
- if (def_style_attr != 0) {
- Res_value value;
- if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- def_style_res = value.data;
- }
- }
+base::expected<const ResolvedBag*, NullOrIOError> GetXmlStyleBag(Theme* theme,
+ ResXMLParser* xml_parser,
+ uint32_t* out_theme_flags) {
+ if (xml_parser == nullptr) {
+ return base::unexpected(std::nullopt);
}
- // Retrieve the default style bag, if requested.
- const ResolvedBag* default_style_bag = nullptr;
- if (def_style_res != 0) {
- default_style_bag = assetmanager->GetBag(def_style_res);
- if (default_style_bag != nullptr) {
- def_style_flags |= default_style_bag->type_spec_flags;
+ // Retrieve the style resource ID associated with the current XML tag's style attribute.
+ Res_value value;
+ const ssize_t idx = xml_parser->indexOfStyle();
+ if (idx < 0 || xml_parser->getAttributeValue(idx, &value) < 0) {
+ return base::unexpected(std::nullopt);
+ }
+
+ if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
+ // Resolve the attribute with out theme.
+ if (std::optional<AssetManager2::SelectedValue> result = theme->GetAttribute(value.data)) {
+ *out_theme_flags |= result->flags;
+ return theme->GetAssetManager()->ResolveBag(*result);
}
}
- BagAttributeFinder def_style_attr_finder(default_style_bag);
+ if (value.dataType == Res_value::TYPE_REFERENCE) {
+ return theme->GetAssetManager()->GetBag(value.data);
+ }
+
+ return base::unexpected(std::nullopt);
+}
+
+} // namespace
+
+base::expected<std::monostate, IOError> ResolveAttrs(Theme* theme, uint32_t def_style_attr,
+ uint32_t def_style_res, uint32_t* src_values,
+ size_t src_values_length, uint32_t* attrs,
+ size_t attrs_length, uint32_t* out_values,
+ uint32_t* out_indices) {
+ DEBUG_LOG("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme, def_style_attr,
+ def_style_res);
+
+ int indices_idx = 0;
+ const AssetManager2* assetmanager = theme->GetAssetManager();
+
+ // Load default style from attribute or resource id, if specified...
+ uint32_t def_style_theme_flags = 0U;
+ const auto default_style_bag = GetStyleBag(theme, def_style_attr, def_style_res,
+ &def_style_theme_flags);
+ if (UNLIKELY(IsIOError(default_style_bag))) {
+ return base::unexpected(GetIOError(default_style_bag.error()));
+ }
+
+ BagAttributeFinder def_style_attr_finder(default_style_bag.value_or(nullptr));
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
for (size_t ii = 0; ii < attrs_length; ii++) {
const uint32_t cur_ident = attrs[ii];
-
- if (kDebugStyles) {
- ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
- }
-
- ApkAssetsCookie cookie = kInvalidCookie;
- uint32_t type_set_flags = 0;
-
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- config.density = 0;
+ DEBUG_LOG("RETRIEVING ATTR 0x%08x...", cur_ident);
// Try to find a value for this attribute... we prioritize values
// coming from, first XML attributes, then XML style, then default
// style, and finally the theme.
// Retrieve the current input value if available.
+ AssetManager2::SelectedValue value{};
if (src_values_length > 0 && src_values[ii] != 0) {
- value.dataType = Res_value::TYPE_ATTRIBUTE;
+ value.type = Res_value::TYPE_ATTRIBUTE;
value.data = src_values[ii];
- if (kDebugStyles) {
- ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
+ DEBUG_LOG("-> From values: type=0x%x, data=0x%08x", value.type, value.data);
} else {
const ResolvedBag::Entry* const entry = def_style_attr_finder.Find(cur_ident);
if (entry != def_style_attr_finder.end()) {
- cookie = entry->cookie;
- type_set_flags = def_style_flags;
- value = entry->value;
- if (kDebugStyles) {
- ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
+ value = AssetManager2::SelectedValue(*default_style_bag, *entry);
+ value.flags |= def_style_theme_flags;
+ DEBUG_LOG("-> From def style: type=0x%x, data=0x%08x", value.type, value.data);
}
}
- uint32_t resid = 0;
- if (value.dataType != Res_value::TYPE_NULL) {
+ if (value.type != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ApkAssetsCookie new_cookie =
- theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
- }
- if (kDebugStyles) {
- ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
+ const auto result = theme->ResolveAttributeReference(value);
+ if (UNLIKELY(IsIOError(result))) {
+ return base::unexpected(GetIOError(result.error()));
}
+ DEBUG_LOG("-> Resolved attr: type=0x%x, data=0x%08x", value.type, value.data);
} else if (value.data != Res_value::DATA_NULL_EMPTY) {
// If we still don't have a value for this attribute, try to find it in the theme!
- ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
- if (new_cookie != kInvalidCookie) {
- if (kDebugStyles) {
- ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- new_cookie =
- assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
- }
- if (kDebugStyles) {
- ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+ if (auto attr_value = theme->GetAttribute(cur_ident)) {
+ value = *attr_value;
+ DEBUG_LOG("-> From theme: type=0x%x, data=0x%08x", value.type, value.data);
+
+ const auto result = assetmanager->ResolveReference(value, true /* cache_value */);
+ if (UNLIKELY(IsIOError(result))) {
+ return base::unexpected(GetIOError(result.error()));
}
+ DEBUG_LOG("-> Resolved theme: type=0x%x, data=0x%08x", value.type, value.data);
}
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- if (kDebugStyles) {
- ALOGI("-> Setting to @null!");
- }
- value.dataType = Res_value::TYPE_NULL;
+ if (value.type == Res_value::TYPE_REFERENCE && value.data == 0) {
+ DEBUG_LOG("-> Setting to @null!");
+ value.type = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- cookie = kInvalidCookie;
+ value.cookie = kInvalidCookie;
}
- if (kDebugStyles) {
- ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
- }
+ DEBUG_LOG("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.type, value.data);
// Write the final value back to Java.
- out_values[STYLE_TYPE] = value.dataType;
+ out_values[STYLE_TYPE] = value.type;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
- out_values[STYLE_RESOURCE_ID] = resid;
- out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
- out_values[STYLE_DENSITY] = config.density;
+ out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(value.cookie);
+ out_values[STYLE_RESOURCE_ID] = value.resid;
+ out_values[STYLE_CHANGING_CONFIGURATIONS] = value.flags;
+ out_values[STYLE_DENSITY] = value.config.density;
if (out_indices != nullptr &&
- (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
- indices_idx++;
- out_indices[indices_idx] = ii;
+ (value.type != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
+ out_indices[++indices_idx] = ii;
}
out_values += STYLE_NUM_ENTRIES;
@@ -199,93 +214,46 @@ bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
if (out_indices != nullptr) {
out_indices[0] = indices_idx;
}
- return true;
+ return {};
}
-void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
- uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
- uint32_t* out_values, uint32_t* out_indices) {
- if (kDebugStyles) {
- ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
- def_style_attr, def_style_resid, xml_parser);
- }
-
- AssetManager2* assetmanager = theme->GetAssetManager();
- ResTable_config config;
- Res_value value;
+base::expected<std::monostate, IOError> ApplyStyle(Theme* theme, ResXMLParser* xml_parser,
+ uint32_t def_style_attr,
+ uint32_t def_style_resid,
+ const uint32_t* attrs, size_t attrs_length,
+ uint32_t* out_values, uint32_t* out_indices) {
+ DEBUG_LOG("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
+ def_style_attr, def_style_resid, xml_parser);
int indices_idx = 0;
+ const AssetManager2* assetmanager = theme->GetAssetManager();
// Load default style from attribute, if specified...
- uint32_t def_style_flags = 0u;
- if (def_style_attr != 0) {
- Res_value value;
- if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- def_style_resid = value.data;
- }
- }
+ uint32_t def_style_theme_flags = 0U;
+ const auto default_style_bag = GetStyleBag(theme, def_style_attr, def_style_resid,
+ &def_style_theme_flags);
+ if (IsIOError(default_style_bag)) {
+ return base::unexpected(GetIOError(default_style_bag.error()));
}
// Retrieve the style resource ID associated with the current XML tag's style attribute.
- uint32_t style_resid = 0u;
- uint32_t style_flags = 0u;
- if (xml_parser != nullptr) {
- ssize_t idx = xml_parser->indexOfStyle();
- if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
- if (value.dataType == value.TYPE_ATTRIBUTE) {
- // Resolve the attribute with out theme.
- if (theme->GetAttribute(value.data, &value, &style_flags) == kInvalidCookie) {
- value.dataType = Res_value::TYPE_NULL;
- }
- }
-
- if (value.dataType == value.TYPE_REFERENCE) {
- style_resid = value.data;
- }
- }
- }
-
- // Retrieve the default style bag, if requested.
- const ResolvedBag* default_style_bag = nullptr;
- if (def_style_resid != 0) {
- default_style_bag = assetmanager->GetBag(def_style_resid);
- if (default_style_bag != nullptr) {
- def_style_flags |= default_style_bag->type_spec_flags;
- }
+ uint32_t xml_style_theme_flags = 0U;
+ const auto xml_style_bag = GetXmlStyleBag(theme, xml_parser, &def_style_theme_flags);
+ if (IsIOError(xml_style_bag)) {
+ return base::unexpected(GetIOError(xml_style_bag.error()));
}
- BagAttributeFinder def_style_attr_finder(default_style_bag);
-
- // Retrieve the style class bag, if requested.
- const ResolvedBag* xml_style_bag = nullptr;
- if (style_resid != 0) {
- xml_style_bag = assetmanager->GetBag(style_resid);
- if (xml_style_bag != nullptr) {
- style_flags |= xml_style_bag->type_spec_flags;
- }
- }
-
- BagAttributeFinder xml_style_attr_finder(xml_style_bag);
-
- // Retrieve the XML attributes, if requested.
+ BagAttributeFinder def_style_attr_finder(default_style_bag.value_or(nullptr));
+ BagAttributeFinder xml_style_attr_finder(xml_style_bag.value_or(nullptr));
XmlAttributeFinder xml_attr_finder(xml_parser);
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
for (size_t ii = 0; ii < attrs_length; ii++) {
const uint32_t cur_ident = attrs[ii];
+ DEBUG_LOG("RETRIEVING ATTR 0x%08x...", cur_ident);
- if (kDebugStyles) {
- ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
- }
-
- ApkAssetsCookie cookie = kInvalidCookie;
- uint32_t type_set_flags = 0u;
-
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- config.density = 0;
+ AssetManager2::SelectedValue value{};
uint32_t value_source_resid = 0;
// Try to find a value for this attribute... we prioritize values
@@ -296,178 +264,152 @@ void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident);
if (xml_attr_idx != xml_attr_finder.end()) {
// We found the attribute we were looking for.
- xml_parser->getAttributeValue(xml_attr_idx, &value);
- if (kDebugStyles) {
- ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
+ Res_value attribute_value;
+ xml_parser->getAttributeValue(xml_attr_idx, &attribute_value);
+ value.type = attribute_value.dataType;
+ value.data = attribute_value.data;
value_source_resid = xml_parser->getSourceResourceId();
+ DEBUG_LOG("-> From XML: type=0x%x, data=0x%08x", value.type, value.data);
}
- if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
+ if (value.type == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
// Walk through the style class values looking for the requested attribute.
const ResolvedBag::Entry* entry = xml_style_attr_finder.Find(cur_ident);
if (entry != xml_style_attr_finder.end()) {
- // We found the attribute we were looking for.
- cookie = entry->cookie;
- type_set_flags = style_flags;
- value = entry->value;
+ value = AssetManager2::SelectedValue(*xml_style_bag, *entry);
+ value.flags |= xml_style_theme_flags;
value_source_resid = entry->style;
- if (kDebugStyles) {
- ALOGI("-> From style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
- entry->style);
- }
+ DEBUG_LOG("-> From style: type=0x%x, data=0x%08x, style=0x%08x", value.type, value.data,
+ value_source_resid);
}
}
- if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
+ if (value.type == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
// Walk through the default style values looking for the requested attribute.
const ResolvedBag::Entry* entry = def_style_attr_finder.Find(cur_ident);
if (entry != def_style_attr_finder.end()) {
- // We found the attribute we were looking for.
- cookie = entry->cookie;
- type_set_flags = def_style_flags;
- value = entry->value;
- if (kDebugStyles) {
- ALOGI("-> From def style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
- entry->style);
- }
+ value = AssetManager2::SelectedValue(*default_style_bag, *entry);
+ value.flags |= def_style_theme_flags;
value_source_resid = entry->style;
+ DEBUG_LOG("-> From def style: type=0x%x, data=0x%08x, style=0x%08x", value.type, value.data,
+ entry->style);
}
}
- uint32_t resid = 0u;
- if (value.dataType != Res_value::TYPE_NULL) {
+ if (value.type != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ApkAssetsCookie new_cookie =
- theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
- }
-
- if (kDebugStyles) {
- ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
+ auto result = theme->ResolveAttributeReference(value);
+ if (UNLIKELY(IsIOError(result))) {
+ return base::unexpected(GetIOError(result.error()));
}
+ DEBUG_LOG("-> Resolved attr: type=0x%x, data=0x%08x", value.type, value.data);
} else if (value.data != Res_value::DATA_NULL_EMPTY) {
// If we still don't have a value for this attribute, try to find it in the theme!
- ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
- // TODO: set value_source_resid for the style in the theme that was used.
- if (new_cookie != kInvalidCookie) {
- if (kDebugStyles) {
- ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- new_cookie =
- assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
- }
+ if (auto attr_value = theme->GetAttribute(cur_ident)) {
+ value = *attr_value;
+ DEBUG_LOG("-> From theme: type=0x%x, data=0x%08x", value.type, value.data);
- if (kDebugStyles) {
- ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+ auto result = assetmanager->ResolveReference(value, true /* cache_value */);
+ if (UNLIKELY(IsIOError(result))) {
+ return base::unexpected(GetIOError(result.error()));
}
+ DEBUG_LOG("-> Resolved theme: type=0x%x, data=0x%08x", value.type, value.data);
+ // TODO: set value_source_resid for the style in the theme that was used.
}
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- if (kDebugStyles) {
- ALOGI("-> Setting to @null!");
- }
- value.dataType = Res_value::TYPE_NULL;
+ if (value.type == Res_value::TYPE_REFERENCE && value.data == 0U) {
+ DEBUG_LOG("-> Setting to @null!");
+ value.type = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- cookie = kInvalidCookie;
+ value.cookie = kInvalidCookie;
}
- if (kDebugStyles) {
- ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
- }
+ DEBUG_LOG("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.type, value.data);
// Write the final value back to Java.
- out_values[STYLE_TYPE] = value.dataType;
+ out_values[STYLE_TYPE] = value.type;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
- out_values[STYLE_RESOURCE_ID] = resid;
- out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
- out_values[STYLE_DENSITY] = config.density;
+ out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(value.cookie);
+ out_values[STYLE_RESOURCE_ID] = value.resid;
+ out_values[STYLE_CHANGING_CONFIGURATIONS] = value.flags;
+ out_values[STYLE_DENSITY] = value.config.density;
out_values[STYLE_SOURCE_RESOURCE_ID] = value_source_resid;
- if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
- indices_idx++;
-
+ if (value.type != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
// out_indices must NOT be nullptr.
- out_indices[indices_idx] = ii;
+ out_indices[++indices_idx] = ii;
}
out_values += STYLE_NUM_ENTRIES;
}
// out_indices must NOT be nullptr.
out_indices[0] = indices_idx;
+ return {};
}
-bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
- size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
- ResTable_config config;
- Res_value value;
-
+base::expected<std::monostate, IOError> RetrieveAttributes(AssetManager2* assetmanager,
+ ResXMLParser* xml_parser,
+ uint32_t* attrs,
+ size_t attrs_length,
+ uint32_t* out_values,
+ uint32_t* out_indices) {
int indices_idx = 0;
// Retrieve the XML attributes, if requested.
- const size_t xml_attr_count = xml_parser->getAttributeCount();
size_t ix = 0;
+ const size_t xml_attr_count = xml_parser->getAttributeCount();
uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix);
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
for (size_t ii = 0; ii < attrs_length; ii++) {
const uint32_t cur_ident = attrs[ii];
- ApkAssetsCookie cookie = kInvalidCookie;
- uint32_t type_set_flags = 0u;
-
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- config.density = 0;
+ AssetManager2::SelectedValue value{};
// Try to find a value for this attribute...
// Skip through XML attributes until the end or the next possible match.
while (ix < xml_attr_count && cur_ident > cur_xml_attr) {
- ix++;
- cur_xml_attr = xml_parser->getAttributeNameResID(ix);
+ cur_xml_attr = xml_parser->getAttributeNameResID(++ix);
}
+
// Retrieve the current XML attribute if it matches, and step to next.
if (ix < xml_attr_count && cur_ident == cur_xml_attr) {
- xml_parser->getAttributeValue(ix, &value);
- ix++;
- cur_xml_attr = xml_parser->getAttributeNameResID(ix);
+ Res_value attribute_value;
+ xml_parser->getAttributeValue(ix, &attribute_value);
+ value.type = attribute_value.dataType;
+ value.data = attribute_value.data;
+ cur_xml_attr = xml_parser->getAttributeNameResID(++ix);
}
- uint32_t resid = 0u;
- if (value.dataType != Res_value::TYPE_NULL) {
+ if (value.type != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ApkAssetsCookie new_cookie =
- assetmanager->ResolveReference(cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
+ auto result = assetmanager->ResolveReference(value);
+ if (UNLIKELY(IsIOError(result))) {
+ return base::unexpected(GetIOError(result.error()));
}
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- value.dataType = Res_value::TYPE_NULL;
+ if (value.type == Res_value::TYPE_REFERENCE && value.data == 0U) {
+ value.type = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- cookie = kInvalidCookie;
+ value.cookie = kInvalidCookie;
}
// Write the final value back to Java.
- out_values[STYLE_TYPE] = value.dataType;
+ out_values[STYLE_TYPE] = value.type;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
- out_values[STYLE_RESOURCE_ID] = resid;
- out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
- out_values[STYLE_DENSITY] = config.density;
+ out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(value.cookie);
+ out_values[STYLE_RESOURCE_ID] = value.resid;
+ out_values[STYLE_CHANGING_CONFIGURATIONS] = value.flags;
+ out_values[STYLE_DENSITY] = value.config.density;
if (out_indices != nullptr &&
- (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
- indices_idx++;
- out_indices[indices_idx] = ii;
+ (value.type != Res_value::TYPE_NULL ||
+ value.data == Res_value::DATA_NULL_EMPTY)) {
+ out_indices[++indices_idx] = ii;
}
out_values += STYLE_NUM_ENTRIES;
@@ -476,7 +418,7 @@ bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, u
if (out_indices != nullptr) {
out_indices[0] = indices_idx;
}
- return true;
+ return {};
}
} // namespace android
diff --git a/libs/androidfw/ChunkIterator.cpp b/libs/androidfw/ChunkIterator.cpp
index 8fc321968055..25c8aa64e492 100644
--- a/libs/androidfw/ChunkIterator.cpp
+++ b/libs/androidfw/ChunkIterator.cpp
@@ -15,6 +15,7 @@
*/
#include "androidfw/Chunk.h"
+#include "androidfw/Util.h"
#include "android-base/logging.h"
@@ -23,11 +24,11 @@ namespace android {
Chunk ChunkIterator::Next() {
CHECK(len_ != 0) << "called Next() after last chunk";
- const ResChunk_header* this_chunk = next_chunk_;
+ const incfs::map_ptr<ResChunk_header> this_chunk = next_chunk_;
+ CHECK((bool) this_chunk) << "Next() called without verifying next chunk";
// We've already checked the values of this_chunk, so safely increment.
- next_chunk_ = reinterpret_cast<const ResChunk_header*>(
- reinterpret_cast<const uint8_t*>(this_chunk) + dtohl(this_chunk->size));
+ next_chunk_ = this_chunk.offset(dtohl(this_chunk->size)).convert<ResChunk_header>();
len_ -= dtohl(this_chunk->size);
if (len_ != 0) {
@@ -36,7 +37,7 @@ Chunk ChunkIterator::Next() {
VerifyNextChunk();
}
}
- return Chunk(this_chunk);
+ return Chunk(this_chunk.verified());
}
// TODO(b/111401637) remove this and have full resource file verification
@@ -47,6 +48,13 @@ bool ChunkIterator::VerifyNextChunkNonFatal() {
last_error_was_fatal_ = false;
return false;
}
+
+ if (!next_chunk_) {
+ last_error_ = "failed to read chunk from data";
+ last_error_was_fatal_ = false;
+ return false;
+ }
+
const size_t size = dtohl(next_chunk_->size);
if (size > len_) {
last_error_ = "chunk size is bigger than given data";
@@ -58,12 +66,10 @@ bool ChunkIterator::VerifyNextChunkNonFatal() {
// Returns false if there was an error.
bool ChunkIterator::VerifyNextChunk() {
- const uintptr_t header_start = reinterpret_cast<uintptr_t>(next_chunk_);
-
// This data must be 4-byte aligned, since we directly
// access 32-bit words, which must be aligned on
// certain architectures.
- if (header_start & 0x03) {
+ if (!util::IsFourByteAligned(next_chunk_)) {
last_error_ = "header not aligned on 4-byte boundary";
return false;
}
@@ -73,6 +79,11 @@ bool ChunkIterator::VerifyNextChunk() {
return false;
}
+ if (!next_chunk_) {
+ last_error_ = "failed to read chunk from data";
+ return false;
+ }
+
const size_t header_size = dtohs(next_chunk_->headerSize);
const size_t size = dtohl(next_chunk_->size);
if (header_size < sizeof(ResChunk_header)) {
@@ -90,7 +101,7 @@ bool ChunkIterator::VerifyNextChunk() {
return false;
}
- if ((size | header_size) & 0x03) {
+ if ((size | header_size) & 0x03U) {
last_error_ = "header sizes are not aligned on 4-byte boundary";
return false;
}
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index 4e03ce5d9584..a61309514143 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -52,22 +52,22 @@ OverlayStringPool::~OverlayStringPool() {
uninit();
}
-const char16_t* OverlayStringPool::stringAt(size_t idx, size_t* outLen) const {
+base::expected<StringPiece16, NullOrIOError> OverlayStringPool::stringAt(size_t idx) const {
const size_t offset = dtohl(data_header_->string_pool_index_offset);
if (idmap_string_pool_ != nullptr && idx >= ResStringPool::size() && idx >= offset) {
- return idmap_string_pool_->stringAt(idx - offset, outLen);
+ return idmap_string_pool_->stringAt(idx - offset);
}
- return ResStringPool::stringAt(idx, outLen);
+ return ResStringPool::stringAt(idx);
}
-const char* OverlayStringPool::string8At(size_t idx, size_t* outLen) const {
+base::expected<StringPiece, NullOrIOError> OverlayStringPool::string8At(size_t idx) const {
const size_t offset = dtohl(data_header_->string_pool_index_offset);
if (idmap_string_pool_ != nullptr && idx >= ResStringPool::size() && idx >= offset) {
- return idmap_string_pool_->string8At(idx - offset, outLen);
+ return idmap_string_pool_->string8At(idx - offset);
}
- return ResStringPool::string8At(idx, outLen);
+ return ResStringPool::string8At(idx);
}
size_t OverlayStringPool::size() const {
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 70bb441f94cb..2fc3b05011c2 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -38,7 +38,7 @@
#include "androidfw/ResourceUtils.h"
#include "androidfw/Util.h"
-using ::android::base::StringPrintf;
+using android::base::StringPrintf;
namespace android {
@@ -51,17 +51,17 @@ namespace {
// the Type structs.
class TypeSpecPtrBuilder {
public:
- explicit TypeSpecPtrBuilder(const ResTable_typeSpec* header)
+ explicit TypeSpecPtrBuilder(incfs::verified_map_ptr<ResTable_typeSpec> header)
: header_(header) {
}
- void AddType(const ResTable_type* type) {
+ void AddType(incfs::verified_map_ptr<ResTable_type> type) {
types_.push_back(type);
}
TypeSpecPtr Build() {
// Check for overflow.
- using ElementType = const ResTable_type*;
+ using ElementType = incfs::verified_map_ptr<ResTable_type>;
if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(ElementType) <
types_.size()) {
return {};
@@ -77,8 +77,8 @@ class TypeSpecPtrBuilder {
private:
DISALLOW_COPY_AND_ASSIGN(TypeSpecPtrBuilder);
- const ResTable_typeSpec* header_;
- std::vector<const ResTable_type*> types_;
+ incfs::verified_map_ptr<ResTable_typeSpec> header_;
+ std::vector<incfs::verified_map_ptr<ResTable_type>> types_;
};
} // namespace
@@ -88,7 +88,7 @@ LoadedPackage::~LoadedPackage() = default;
// Precondition: The header passed in has already been verified, so reading any fields and trusting
// the ResChunk_header is safe.
-static bool VerifyResTableType(const ResTable_type* header) {
+static bool VerifyResTableType(incfs::map_ptr<ResTable_type> header) {
if (header->id == 0) {
LOG(ERROR) << "RES_TABLE_TYPE_TYPE has invalid ID 0.";
return false;
@@ -115,89 +115,99 @@ static bool VerifyResTableType(const ResTable_type* header) {
return false;
}
- if (entries_offset & 0x03) {
+ if (entries_offset & 0x03U) {
LOG(ERROR) << "RES_TABLE_TYPE_TYPE entries start at unaligned address.";
return false;
}
return true;
}
-static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset) {
+static base::expected<std::monostate, NullOrIOError> VerifyResTableEntry(
+ incfs::verified_map_ptr<ResTable_type> type, uint32_t entry_offset) {
// Check that the offset is aligned.
- if (entry_offset & 0x03) {
+ if (UNLIKELY(entry_offset & 0x03U)) {
LOG(ERROR) << "Entry at offset " << entry_offset << " is not 4-byte aligned.";
- return false;
+ return base::unexpected(std::nullopt);
}
// Check that the offset doesn't overflow.
- if (entry_offset > std::numeric_limits<uint32_t>::max() - dtohl(type->entriesStart)) {
+ if (UNLIKELY(entry_offset > std::numeric_limits<uint32_t>::max() - dtohl(type->entriesStart))) {
// Overflow in offset.
LOG(ERROR) << "Entry at offset " << entry_offset << " is too large.";
- return false;
+ return base::unexpected(std::nullopt);
}
const size_t chunk_size = dtohl(type->header.size);
entry_offset += dtohl(type->entriesStart);
- if (entry_offset > chunk_size - sizeof(ResTable_entry)) {
+ if (UNLIKELY(entry_offset > chunk_size - sizeof(ResTable_entry))) {
LOG(ERROR) << "Entry at offset " << entry_offset
<< " is too large. No room for ResTable_entry.";
- return false;
+ return base::unexpected(std::nullopt);
}
- const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
- reinterpret_cast<const uint8_t*>(type) + entry_offset);
+ auto entry = type.offset(entry_offset).convert<ResTable_entry>();
+ if (UNLIKELY(!entry)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
const size_t entry_size = dtohs(entry->size);
- if (entry_size < sizeof(*entry)) {
+ if (UNLIKELY(entry_size < sizeof(entry.value()))) {
LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
<< " is too small.";
- return false;
+ return base::unexpected(std::nullopt);
}
- if (entry_size > chunk_size || entry_offset > chunk_size - entry_size) {
+ if (UNLIKELY(entry_size > chunk_size || entry_offset > chunk_size - entry_size)) {
LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
<< " is too large.";
- return false;
+ return base::unexpected(std::nullopt);
}
if (entry_size < sizeof(ResTable_map_entry)) {
// There needs to be room for one Res_value struct.
- if (entry_offset + entry_size > chunk_size - sizeof(Res_value)) {
+ if (UNLIKELY(entry_offset + entry_size > chunk_size - sizeof(Res_value))) {
LOG(ERROR) << "No room for Res_value after ResTable_entry at offset " << entry_offset
<< " for type " << (int)type->id << ".";
- return false;
+ return base::unexpected(std::nullopt);
+ }
+
+ auto value = entry.offset(entry_size).convert<Res_value>();
+ if (UNLIKELY(!value)) {
+ return base::unexpected(IOError::PAGES_MISSING);
}
- const Res_value* value =
- reinterpret_cast<const Res_value*>(reinterpret_cast<const uint8_t*>(entry) + entry_size);
const size_t value_size = dtohs(value->size);
- if (value_size < sizeof(Res_value)) {
+ if (UNLIKELY(value_size < sizeof(Res_value))) {
LOG(ERROR) << "Res_value at offset " << entry_offset << " is too small.";
- return false;
+ return base::unexpected(std::nullopt);
}
- if (value_size > chunk_size || entry_offset + entry_size > chunk_size - value_size) {
+ if (UNLIKELY(value_size > chunk_size || entry_offset + entry_size > chunk_size - value_size)) {
LOG(ERROR) << "Res_value size " << value_size << " at offset " << entry_offset
<< " is too large.";
- return false;
+ return base::unexpected(std::nullopt);
}
} else {
- const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(entry);
+ auto map = entry.convert<ResTable_map_entry>();
+ if (UNLIKELY(!map)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
const size_t map_entry_count = dtohl(map->count);
size_t map_entries_start = entry_offset + entry_size;
- if (map_entries_start & 0x03) {
+ if (UNLIKELY(map_entries_start & 0x03U)) {
LOG(ERROR) << "Map entries at offset " << entry_offset << " start at unaligned offset.";
- return false;
+ return base::unexpected(std::nullopt);
}
// Each entry is sizeof(ResTable_map) big.
- if (map_entry_count > ((chunk_size - map_entries_start) / sizeof(ResTable_map))) {
+ if (UNLIKELY(map_entry_count > ((chunk_size - map_entries_start) / sizeof(ResTable_map)))) {
LOG(ERROR) << "Too many map entries in ResTable_map_entry at offset " << entry_offset << ".";
- return false;
+ return base::unexpected(std::nullopt);
}
}
- return true;
+ return {};
}
LoadedPackage::iterator::iterator(const LoadedPackage* lp, size_t ti, size_t ei)
@@ -233,99 +243,125 @@ uint32_t LoadedPackage::iterator::operator*() const {
entryIndex_);
}
-const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk,
- uint16_t entry_index) {
- uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index);
- if (entry_offset == ResTable_type::NO_ENTRY) {
- return nullptr;
+base::expected<incfs::map_ptr<ResTable_entry>, NullOrIOError> LoadedPackage::GetEntry(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index) {
+ base::expected<uint32_t, NullOrIOError> entry_offset = GetEntryOffset(type_chunk, entry_index);
+ if (UNLIKELY(!entry_offset.has_value())) {
+ return base::unexpected(entry_offset.error());
}
- return GetEntryFromOffset(type_chunk, entry_offset);
+ return GetEntryFromOffset(type_chunk, entry_offset.value());
}
-uint32_t LoadedPackage::GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index) {
+base::expected<uint32_t, NullOrIOError> LoadedPackage::GetEntryOffset(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index) {
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
const size_t entry_count = dtohl(type_chunk->entryCount);
const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
// Check if there is the desired entry in this type.
-
if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
// This is encoded as a sparse map, so perform a binary search.
- const ResTable_sparseTypeEntry* sparse_indices =
- reinterpret_cast<const ResTable_sparseTypeEntry*>(
- reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
- const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
- const ResTable_sparseTypeEntry* result =
- std::lower_bound(sparse_indices, sparse_indices_end, entry_index,
- [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
- return dtohs(entry.idx) < entry_idx;
- });
-
- if (result == sparse_indices_end || dtohs(result->idx) != entry_index) {
+ bool error = false;
+ auto sparse_indices = type_chunk.offset(offsets_offset)
+ .convert<ResTable_sparseTypeEntry>().iterator();
+ auto sparse_indices_end = sparse_indices + entry_count;
+ auto result = std::lower_bound(sparse_indices, sparse_indices_end, entry_index,
+ [&error](const incfs::map_ptr<ResTable_sparseTypeEntry>& entry,
+ uint16_t entry_idx) {
+ if (UNLIKELY(!entry)) {
+ return error = true;
+ }
+ return dtohs(entry->idx) < entry_idx;
+ });
+
+ if (result == sparse_indices_end) {
// No entry found.
- return ResTable_type::NO_ENTRY;
+ return base::unexpected(std::nullopt);
+ }
+
+ const incfs::verified_map_ptr<ResTable_sparseTypeEntry> entry = (*result).verified();
+ if (dtohs(entry->idx) != entry_index) {
+ if (error) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ return base::unexpected(std::nullopt);
}
// Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
// the real offset divided by 4.
- return uint32_t{dtohs(result->offset)} * 4u;
+ return uint32_t{dtohs(entry->offset)} * 4u;
}
// This type is encoded as a dense array.
if (entry_index >= entry_count) {
// This entry cannot be here.
- return ResTable_type::NO_ENTRY;
+ return base::unexpected(std::nullopt);
}
- const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
- reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
- return dtohl(entry_offsets[entry_index]);
+ const auto entry_offset_ptr = type_chunk.offset(offsets_offset).convert<uint32_t>() + entry_index;
+ if (UNLIKELY(!entry_offset_ptr)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ const uint32_t value = dtohl(entry_offset_ptr.value());
+ if (value == ResTable_type::NO_ENTRY) {
+ return base::unexpected(std::nullopt);
+ }
+
+ return value;
}
-const ResTable_entry* LoadedPackage::GetEntryFromOffset(const ResTable_type* type_chunk,
- uint32_t offset) {
- if (UNLIKELY(!VerifyResTableEntry(type_chunk, offset))) {
- return nullptr;
+base::expected<incfs::map_ptr<ResTable_entry>, NullOrIOError> LoadedPackage::GetEntryFromOffset(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint32_t offset) {
+ auto valid = VerifyResTableEntry(type_chunk, offset);
+ if (UNLIKELY(!valid.has_value())) {
+ return base::unexpected(valid.error());
}
- return reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type_chunk) +
- offset + dtohl(type_chunk->entriesStart));
+ return type_chunk.offset(offset + dtohl(type_chunk->entriesStart)).convert<ResTable_entry>();
}
-void LoadedPackage::CollectConfigurations(bool exclude_mipmap,
- std::set<ResTable_config>* out_configs) const {
- const static std::u16string kMipMap = u"mipmap";
+base::expected<std::monostate, IOError> LoadedPackage::CollectConfigurations(
+ bool exclude_mipmap, std::set<ResTable_config>* out_configs) const {
const size_t type_count = type_specs_.size();
for (size_t i = 0; i < type_count; i++) {
const TypeSpecPtr& type_spec = type_specs_[i];
- if (type_spec != nullptr) {
- if (exclude_mipmap) {
- const int type_idx = type_spec->type_spec->id - 1;
- size_t type_name_len;
- const char16_t* type_name16 = type_string_pool_.stringAt(type_idx, &type_name_len);
- if (type_name16 != nullptr) {
- if (kMipMap.compare(0, std::u16string::npos, type_name16, type_name_len) == 0) {
- // This is a mipmap type, skip collection.
- continue;
- }
- }
- const char* type_name = type_string_pool_.string8At(type_idx, &type_name_len);
- if (type_name != nullptr) {
- if (strncmp(type_name, "mipmap", type_name_len) == 0) {
- // This is a mipmap type, skip collection.
- continue;
- }
+ if (type_spec == nullptr) {
+ continue;
+ }
+ if (exclude_mipmap) {
+ const int type_idx = type_spec->type_spec->id - 1;
+ const auto type_name16 = type_string_pool_.stringAt(type_idx);
+ if (UNLIKELY(IsIOError(type_name16))) {
+ return base::unexpected(GetIOError(type_name16.error()));
+ }
+ if (type_name16.has_value()) {
+ if (strncmp16(type_name16->data(), u"mipmap", type_name16->size()) == 0) {
+ // This is a mipmap type, skip collection.
+ continue;
}
}
- const auto iter_end = type_spec->types + type_spec->type_count;
- for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- ResTable_config config;
- config.copyFromDtoH((*iter)->config);
- out_configs->insert(config);
+ const auto type_name = type_string_pool_.string8At(type_idx);
+ if (UNLIKELY(IsIOError(type_name))) {
+ return base::unexpected(GetIOError(type_name.error()));
}
+ if (type_name.has_value()) {
+ if (strncmp(type_name->data(), "mipmap", type_name->size()) == 0) {
+ // This is a mipmap type, skip collection.
+ continue;
+ }
+ }
+ }
+
+ const auto iter_end = type_spec->types + type_spec->type_count;
+ for (auto iter = type_spec->types; iter != iter_end; ++iter) {
+ ResTable_config config;
+ config.copyFromDtoH((*iter)->config);
+ out_configs->insert(config);
}
}
+ return {};
}
void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const {
@@ -348,43 +384,53 @@ void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out
}
}
-uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name,
- const std::u16string& entry_name) const {
- ssize_t type_idx = type_string_pool_.indexOfString(type_name.data(), type_name.size());
- if (type_idx < 0) {
- return 0u;
+base::expected<uint32_t, NullOrIOError> LoadedPackage::FindEntryByName(
+ const std::u16string& type_name, const std::u16string& entry_name) const {
+ const base::expected<size_t, NullOrIOError> type_idx = type_string_pool_.indexOfString(
+ type_name.data(), type_name.size());
+ if (!type_idx.has_value()) {
+ return base::unexpected(type_idx.error());
}
- ssize_t key_idx = key_string_pool_.indexOfString(entry_name.data(), entry_name.size());
- if (key_idx < 0) {
- return 0u;
+ const base::expected<size_t, NullOrIOError> key_idx = key_string_pool_.indexOfString(
+ entry_name.data(), entry_name.size());
+ if (!key_idx.has_value()) {
+ return base::unexpected(key_idx.error());
}
- const TypeSpec* type_spec = type_specs_[type_idx].get();
+ const TypeSpec* type_spec = type_specs_[*type_idx].get();
if (type_spec == nullptr) {
- return 0u;
+ return base::unexpected(std::nullopt);
}
const auto iter_end = type_spec->types + type_spec->type_count;
for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- const ResTable_type* type = *iter;
+ const incfs::verified_map_ptr<ResTable_type>& type = *iter;
+
size_t entry_count = dtohl(type->entryCount);
for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
- const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
- reinterpret_cast<const uint8_t*>(type) + dtohs(type->header.headerSize));
- const uint32_t offset = dtohl(entry_offsets[entry_idx]);
+ auto entry_offset_ptr = type.offset(dtohs(type->header.headerSize)).convert<uint32_t>() +
+ entry_idx;
+ if (!entry_offset_ptr) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ auto offset = dtohl(entry_offset_ptr.value());
if (offset != ResTable_type::NO_ENTRY) {
- const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
- reinterpret_cast<const uint8_t*>(type) + dtohl(type->entriesStart) + offset);
- if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) {
+ auto entry = type.offset(dtohl(type->entriesStart) + offset).convert<ResTable_entry>();
+ if (!entry) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ if (dtohl(entry->key.index) == static_cast<uint32_t>(*key_idx)) {
// The package ID will be overridden by the caller (due to runtime assignment of package
// IDs for shared libraries).
- return make_resid(0x00, type_idx + type_id_offset_ + 1, entry_idx);
+ return make_resid(0x00, *type_idx + type_id_offset_ + 1, entry_idx);
}
}
}
}
- return 0u;
+ return base::unexpected(std::nullopt);
}
const LoadedPackage* LoadedArsc::GetPackageById(uint8_t package_id) const {
@@ -405,8 +451,8 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
// was added.
constexpr size_t kMinPackageSize =
sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
- const ResTable_package* header = chunk.header<ResTable_package, kMinPackageSize>();
- if (header == nullptr) {
+ const incfs::map_ptr<ResTable_package> header = chunk.header<ResTable_package, kMinPackageSize>();
+ if (!header) {
LOG(ERROR) << "RES_TABLE_PACKAGE_TYPE too small.";
return {};
}
@@ -453,10 +499,13 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
const Chunk child_chunk = iter.Next();
switch (child_chunk.type()) {
case RES_STRING_POOL_TYPE: {
- const uintptr_t pool_address =
- reinterpret_cast<uintptr_t>(child_chunk.header<ResChunk_header>());
- const uintptr_t header_address = reinterpret_cast<uintptr_t>(header);
- if (pool_address == header_address + dtohl(header->typeStrings)) {
+ const auto pool_address = child_chunk.header<ResChunk_header>();
+ if (!pool_address) {
+ LOG(ERROR) << "RES_STRING_POOL_TYPE is incomplete due to incremental installation.";
+ return {};
+ }
+
+ if (pool_address == header.offset(dtohl(header->typeStrings)).convert<ResChunk_header>()) {
// This string pool is the type string pool.
status_t err = loaded_package->type_string_pool_.setTo(
child_chunk.header<ResStringPool_header>(), child_chunk.size());
@@ -464,7 +513,8 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
LOG(ERROR) << "RES_STRING_POOL_TYPE for types corrupt.";
return {};
}
- } else if (pool_address == header_address + dtohl(header->keyStrings)) {
+ } else if (pool_address == header.offset(dtohl(header->keyStrings))
+ .convert<ResChunk_header>()) {
// This string pool is the key string pool.
status_t err = loaded_package->key_string_pool_.setTo(
child_chunk.header<ResStringPool_header>(), child_chunk.size());
@@ -478,8 +528,8 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
} break;
case RES_TABLE_TYPE_SPEC_TYPE: {
- const ResTable_typeSpec* type_spec = child_chunk.header<ResTable_typeSpec>();
- if (type_spec == nullptr) {
+ const auto type_spec = child_chunk.header<ResTable_typeSpec>();
+ if (!type_spec) {
LOG(ERROR) << "RES_TABLE_TYPE_SPEC_TYPE too small.";
return {};
}
@@ -514,7 +564,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type_spec->id - 1];
if (builder_ptr == nullptr) {
- builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec);
+ builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec.verified());
loaded_package->resource_ids_.set(type_spec->id, entry_count);
} else {
LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
@@ -523,8 +573,8 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
} break;
case RES_TABLE_TYPE_TYPE: {
- const ResTable_type* type = child_chunk.header<ResTable_type, kResTableTypeMinSize>();
- if (type == nullptr) {
+ const auto type = child_chunk.header<ResTable_type, kResTableTypeMinSize>();
+ if (!type) {
LOG(ERROR) << "RES_TABLE_TYPE_TYPE too small.";
return {};
}
@@ -536,7 +586,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
// Type chunks must be preceded by their TypeSpec chunks.
std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type->id - 1];
if (builder_ptr != nullptr) {
- builder_ptr->AddType(type);
+ builder_ptr->AddType(type.verified());
} else {
LOG(ERROR) << StringPrintf(
"RES_TABLE_TYPE_TYPE with ID %02x found without preceding RES_TABLE_TYPE_SPEC_TYPE.",
@@ -546,8 +596,8 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
} break;
case RES_TABLE_LIBRARY_TYPE: {
- const ResTable_lib_header* lib = child_chunk.header<ResTable_lib_header>();
- if (lib == nullptr) {
+ const auto lib = child_chunk.header<ResTable_lib_header>();
+ if (!lib) {
LOG(ERROR) << "RES_TABLE_LIBRARY_TYPE too small.";
return {};
}
@@ -559,10 +609,13 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
loaded_package->dynamic_package_map_.reserve(dtohl(lib->count));
- const ResTable_lib_entry* const entry_begin =
- reinterpret_cast<const ResTable_lib_entry*>(child_chunk.data_ptr());
- const ResTable_lib_entry* const entry_end = entry_begin + dtohl(lib->count);
+ const auto entry_begin = child_chunk.data_ptr().convert<ResTable_lib_entry>();
+ const auto entry_end = entry_begin + dtohl(lib->count);
for (auto entry_iter = entry_begin; entry_iter != entry_end; ++entry_iter) {
+ if (!entry_iter) {
+ return {};
+ }
+
std::string package_name;
util::ReadUtf16StringFromDevice(entry_iter->packageName,
arraysize(entry_iter->packageName), &package_name);
@@ -580,17 +633,16 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
} break;
case RES_TABLE_OVERLAYABLE_TYPE: {
- const ResTable_overlayable_header* header =
- child_chunk.header<ResTable_overlayable_header>();
- if (header == nullptr) {
+ const auto overlayable = child_chunk.header<ResTable_overlayable_header>();
+ if (!overlayable) {
LOG(ERROR) << "RES_TABLE_OVERLAYABLE_TYPE too small.";
return {};
}
std::string name;
- util::ReadUtf16StringFromDevice(header->name, arraysize(header->name), &name);
+ util::ReadUtf16StringFromDevice(overlayable->name, arraysize(overlayable->name), &name);
std::string actor;
- util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor);
+ util::ReadUtf16StringFromDevice(overlayable->actor, arraysize(overlayable->actor), &actor);
if (loaded_package->overlayable_map_.find(name) !=
loaded_package->overlayable_map_.end()) {
@@ -606,9 +658,9 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
switch (overlayable_child_chunk.type()) {
case RES_TABLE_OVERLAYABLE_POLICY_TYPE: {
- const ResTable_overlayable_policy_header* policy_header =
+ const auto policy_header =
overlayable_child_chunk.header<ResTable_overlayable_policy_header>();
- if (policy_header == nullptr) {
+ if (!policy_header) {
LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small.";
return {};
}
@@ -621,10 +673,12 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
// Retrieve all the resource ids belonging to this policy chunk
std::unordered_set<uint32_t> ids;
- const auto ids_begin =
- reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr());
+ const auto ids_begin = overlayable_child_chunk.data_ptr().convert<ResTable_ref>();
const auto ids_end = ids_begin + dtohl(policy_header->entry_count);
for (auto id_iter = ids_begin; id_iter != ids_end; ++id_iter) {
+ if (!id_iter) {
+ return {};
+ }
ids.insert(dtohl(id_iter->ident));
}
@@ -633,7 +687,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
overlayable_info.name = name;
overlayable_info.actor = actor;
overlayable_info.policy_flags = policy_header->policy_flags;
- loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
+ loaded_package->overlayable_infos_.emplace_back(overlayable_info, ids);
loaded_package->defines_overlayable_ = true;
break;
}
@@ -683,8 +737,8 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
package_property_t property_flags) {
- const ResTable_header* header = chunk.header<ResTable_header>();
- if (header == nullptr) {
+ incfs::map_ptr<ResTable_header> header = chunk.header<ResTable_header>();
+ if (!header) {
LOG(ERROR) << "RES_TABLE_TYPE too small.";
return false;
}
@@ -747,7 +801,8 @@ bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
return true;
}
-std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const StringPiece& data,
+std::unique_ptr<const LoadedArsc> LoadedArsc::Load(incfs::map_ptr<void> data,
+ const size_t length,
const LoadedIdmap* loaded_idmap,
const package_property_t property_flags) {
ATRACE_NAME("LoadedArsc::Load");
@@ -755,7 +810,7 @@ std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const StringPiece& data,
// Not using make_unique because the constructor is private.
std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc());
- ChunkIterator iter(data.data(), data.size());
+ ChunkIterator iter(data, length);
while (iter.HasNext()) {
const Chunk chunk = iter.Next();
switch (chunk.type()) {
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index dfb4009b07e2..4010e4e10317 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -104,22 +104,26 @@ static void strcpy16_dtoh(char16_t* dst, const uint16_t* src, size_t avail)
*dst = 0;
}
-static status_t validate_chunk(const ResChunk_header* chunk,
+static status_t validate_chunk(const incfs::map_ptr<ResChunk_header>& chunk,
size_t minSize,
- const uint8_t* dataEnd,
+ const incfs::map_ptr<uint8_t> dataEnd,
const char* name)
{
+ if (!chunk) {
+ return BAD_TYPE;
+ }
+
const uint16_t headerSize = dtohs(chunk->headerSize);
const uint32_t size = dtohl(chunk->size);
if (headerSize >= minSize) {
if (headerSize <= size) {
if (((headerSize|size)&0x3) == 0) {
- if ((size_t)size <= (size_t)(dataEnd-((const uint8_t*)chunk))) {
+ if ((size_t)size <= (size_t)(dataEnd-chunk.convert<uint8_t>())) {
return NO_ERROR;
}
ALOGW("%s data size 0x%x extends beyond resource end %p.",
- name, size, (void*)(dataEnd-((const uint8_t*)chunk)));
+ name, size, (void*)(dataEnd-chunk.convert<uint8_t>()));
return BAD_TYPE;
}
ALOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.",
@@ -450,7 +454,7 @@ void ResStringPool::setToEmpty()
mHeader = (const ResStringPool_header*) header;
}
-status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
+status_t ResStringPool::setTo(incfs::map_ptr<void> data, size_t size, bool copyData)
{
if (!data || !size) {
return (mError=BAD_TYPE);
@@ -467,8 +471,8 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
// The data is at least as big as a ResChunk_header, so we can safely validate the other
// header fields.
// `data + size` is safe because the source of `size` comes from the kernel/filesystem.
- if (validate_chunk(reinterpret_cast<const ResChunk_header*>(data), sizeof(ResStringPool_header),
- reinterpret_cast<const uint8_t*>(data) + size,
+ const auto chunk_header = data.convert<ResChunk_header>();
+ if (validate_chunk(chunk_header, sizeof(ResStringPool_header), data.convert<uint8_t>() + size,
"ResStringPool_header") != NO_ERROR) {
ALOGW("Bad string block: malformed block dimensions");
return (mError=BAD_TYPE);
@@ -481,16 +485,25 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
if (mOwnedData == NULL) {
return (mError=NO_MEMORY);
}
- memcpy(mOwnedData, data, size);
+
+ if (!data.convert<uint8_t>().verify(size)) {
+ return (mError=NO_MEMORY);
+ }
+
+ memcpy(mOwnedData, data.unsafe_ptr(), size);
data = mOwnedData;
}
// The size has been checked, so it is safe to read the data in the ResStringPool_header
// data structure.
- mHeader = (const ResStringPool_header*)data;
+ const auto header = data.convert<ResStringPool_header>();
+ if (!header) {
+ return (mError=BAD_TYPE);
+ }
+ mHeader = header.verified();
if (notDeviceEndian) {
- ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader);
+ ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader.unsafe_ptr());
h->header.headerSize = dtohs(mHeader->header.headerSize);
h->header.type = dtohs(mHeader->header.type);
h->header.size = dtohl(mHeader->header.size);
@@ -508,8 +521,7 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
return (mError=BAD_TYPE);
}
mSize = mHeader->header.size;
- mEntries = (const uint32_t*)
- (((const uint8_t*)data)+mHeader->header.headerSize);
+ mEntries = data.offset(mHeader->header.headerSize).convert<uint32_t>();
if (mHeader->stringCount > 0) {
if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount) // uint32 overflow?
@@ -536,9 +548,7 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
return (mError=BAD_TYPE);
}
- mStrings = (const void*)
- (((const uint8_t*)data) + mHeader->stringsStart);
-
+ mStrings = data.offset(mHeader->stringsStart).convert<void>();
if (mHeader->styleCount == 0) {
mStringPoolSize = (mSize - mHeader->stringsStart) / charSize;
} else {
@@ -560,31 +570,37 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
// check invariant: stringCount > 0 requires a string pool to exist
if (mStringPoolSize == 0) {
- ALOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount);
+ ALOGW("Bad string block: stringCount is %d but pool size is 0\n",
+ (int)mHeader->stringCount);
return (mError=BAD_TYPE);
}
if (notDeviceEndian) {
size_t i;
- uint32_t* e = const_cast<uint32_t*>(mEntries);
+ auto e = const_cast<uint32_t*>(mEntries.unsafe_ptr());
for (i=0; i<mHeader->stringCount; i++) {
- e[i] = dtohl(mEntries[i]);
+ e[i] = dtohl(e[i]);
}
if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) {
- const uint16_t* strings = (const uint16_t*)mStrings;
- uint16_t* s = const_cast<uint16_t*>(strings);
+ uint16_t* s = const_cast<uint16_t*>(mStrings.convert<uint16_t>().unsafe_ptr());
for (i=0; i<mStringPoolSize; i++) {
- s[i] = dtohs(strings[i]);
+ s[i] = dtohs(s[i]);
}
}
}
- if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
- ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
- (!(mHeader->flags&ResStringPool_header::UTF8_FLAG) &&
- ((uint16_t*)mStrings)[mStringPoolSize-1] != 0)) {
- ALOGW("Bad string block: last string is not 0-terminated\n");
- return (mError=BAD_TYPE);
+ if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
+ auto end = mStrings.convert<uint8_t>() + (mStringPoolSize-1);
+ if (!end || end.value() != 0) {
+ ALOGW("Bad string block: last string is not 0-terminated\n");
+ return (mError=BAD_TYPE);
+ }
+ } else {
+ auto end = mStrings.convert<uint16_t>() + (mStringPoolSize-1);
+ if (!end || end.value() != 0) {
+ ALOGW("Bad string block: last string is not 0-terminated\n");
+ return (mError=BAD_TYPE);
+ }
}
} else {
mStrings = NULL;
@@ -599,14 +615,13 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
return (mError=BAD_TYPE);
}
- if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
+ if ((mEntryStyles.convert<uint8_t>() - mHeader.convert<uint8_t>()) > (int)size) {
ALOGW("Bad string block: entry of %d styles extends past data size %d\n",
- (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader),
+ (int)(mEntryStyles.convert<uint8_t>()-mHeader.convert<uint8_t>()),
(int)size);
return (mError=BAD_TYPE);
}
- mStyles = (const uint32_t*)
- (((const uint8_t*)data)+mHeader->stylesStart);
+ mStyles = data.offset(mHeader->stylesStart).convert<uint32_t>();
if (mHeader->stylesStart >= mHeader->header.size) {
ALOGW("Bad string block: style pool starts %d, after total size %d\n",
(int)mHeader->stylesStart, (int)mHeader->header.size);
@@ -617,13 +632,13 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
if (notDeviceEndian) {
size_t i;
- uint32_t* e = const_cast<uint32_t*>(mEntryStyles);
+ uint32_t* e = const_cast<uint32_t*>(mEntryStyles.unsafe_ptr());
for (i=0; i<mHeader->styleCount; i++) {
- e[i] = dtohl(mEntryStyles[i]);
+ e[i] = dtohl(e[i]);
}
- uint32_t* s = const_cast<uint32_t*>(mStyles);
+ uint32_t* s = const_cast<uint32_t*>(mStyles.unsafe_ptr());
for (i=0; i<mStylePoolSize; i++) {
- s[i] = dtohl(mStyles[i]);
+ s[i] = dtohl(s[i]);
}
}
@@ -631,8 +646,9 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
{ htodl(ResStringPool_span::END) },
htodl(ResStringPool_span::END), htodl(ResStringPool_span::END)
};
- if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
- &endSpan, sizeof(endSpan)) != 0) {
+
+ auto stylesEnd = mStyles + (mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t)));
+ if (!stylesEnd || memcmp(stylesEnd.unsafe_ptr(), &endSpan, sizeof(endSpan)) != 0) {
ALOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
return (mError=BAD_TYPE);
}
@@ -653,7 +669,7 @@ status_t ResStringPool::getError() const
void ResStringPool::uninit()
{
mError = NO_INIT;
- if (mHeader != NULL && mCache != NULL) {
+ if (mHeader && mCache != NULL) {
for (size_t x = 0; x < mHeader->stringCount; x++) {
if (mCache[x] != NULL) {
free(mCache[x]);
@@ -679,15 +695,21 @@ void ResStringPool::uninit()
* data encoded. In that case, drop the high bit of the first character and
* add it together with the next character.
*/
-static inline size_t
-decodeLength(const uint16_t** str)
+static inline base::expected<size_t, IOError> decodeLength(incfs::map_ptr<uint16_t>* str)
{
- size_t len = **str;
- if ((len & 0x8000) != 0) {
- (*str)++;
- len = ((len & 0x7FFF) << 16) | **str;
+ if (UNLIKELY(!*str)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ size_t len = str->value();
+ if ((len & 0x8000U) != 0) {
+ ++(*str);
+ if (UNLIKELY(!*str)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ len = ((len & 0x7FFFU) << 16U) | str->value();
}
- (*str)++;
+ ++(*str);
return len;
}
@@ -701,82 +723,119 @@ decodeLength(const uint16_t** str)
* data encoded. In that case, drop the high bit of the first character and
* add it together with the next character.
*/
-static inline size_t
-decodeLength(const uint8_t** str)
+static inline base::expected<size_t, IOError> decodeLength(incfs::map_ptr<uint8_t>* str)
{
- size_t len = **str;
- if ((len & 0x80) != 0) {
- (*str)++;
- len = ((len & 0x7F) << 8) | **str;
+ if (UNLIKELY(!*str)) {
+ return base::unexpected(IOError::PAGES_MISSING);
}
- (*str)++;
+
+ size_t len = str->value();
+ if ((len & 0x80U) != 0) {
+ ++(*str);
+ if (UNLIKELY(!*str)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ len = ((len & 0x7FU) << 8U) | str->value();
+ }
+ ++(*str);
return len;
}
-const char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
+base::expected<StringPiece16, NullOrIOError> ResStringPool::stringAt(size_t idx) const
{
if (mError == NO_ERROR && idx < mHeader->stringCount) {
const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
- const uint32_t off = mEntries[idx]/(isUTF8?sizeof(uint8_t):sizeof(uint16_t));
+ auto offPtr = mEntries + idx;
+ if (UNLIKELY(!offPtr)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ const uint32_t off = (offPtr.value())/(isUTF8?sizeof(uint8_t):sizeof(uint16_t));
if (off < (mStringPoolSize-1)) {
if (!isUTF8) {
- const uint16_t* strings = (uint16_t*)mStrings;
- const uint16_t* str = strings+off;
+ auto strings = mStrings.convert<uint16_t>();
+ auto str = strings+off;
+
+ const base::expected<size_t, IOError> u16len = decodeLength(&str);
+ if (UNLIKELY(!u16len.has_value())) {
+ return base::unexpected(u16len.error());
+ }
- *u16len = decodeLength(&str);
if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) {
// Reject malformed (non null-terminated) strings
- if (str[*u16len] != 0x0000) {
- ALOGW("Bad string block: string #%d is not null-terminated",
- (int)idx);
- return NULL;
+ const auto nullAddress = str + (*u16len);
+ if (UNLIKELY(!nullAddress)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ if (nullAddress.value() != 0x0000) {
+ ALOGW("Bad string block: string #%d is not null-terminated", (int)idx);
+ return base::unexpected(std::nullopt);
+ }
+
+ if (UNLIKELY(!str.verify(*u16len + 1U))) {
+ return base::unexpected(IOError::PAGES_MISSING);
}
- return reinterpret_cast<const char16_t*>(str);
+
+ return StringPiece16(reinterpret_cast<const char16_t*>(str.unsafe_ptr()),
+ *u16len);
} else {
ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
(int)idx, (int)(str+*u16len-strings), (int)mStringPoolSize);
}
} else {
- const uint8_t* strings = (uint8_t*)mStrings;
- const uint8_t* u8str = strings+off;
+ auto strings = mStrings.convert<uint8_t>();
+ auto u8str = strings+off;
- *u16len = decodeLength(&u8str);
- size_t u8len = decodeLength(&u8str);
+ base::expected<size_t, IOError> u16len = decodeLength(&u8str);
+ if (UNLIKELY(!u16len.has_value())) {
+ return base::unexpected(u16len.error());
+ }
+
+ const base::expected<size_t, IOError> u8len = decodeLength(&u8str);
+ if (UNLIKELY(!u8len.has_value())) {
+ return base::unexpected(u8len.error());
+ }
// encLen must be less than 0x7FFF due to encoding.
- if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) {
+ if ((uint32_t)(u8str+*u8len-strings) < mStringPoolSize) {
AutoMutex lock(mDecodeLock);
if (mCache != NULL && mCache[idx] != NULL) {
- return mCache[idx];
+ return StringPiece16(mCache[idx], *u16len);
}
// Retrieve the actual length of the utf8 string if the
// encoded length was truncated
- if (stringDecodeAt(idx, u8str, u8len, &u8len) == NULL) {
- return NULL;
+ auto decodedString = stringDecodeAt(idx, u8str, *u8len);
+ if (!decodedString.has_value()) {
+ return base::unexpected(decodedString.error());
}
// Since AAPT truncated lengths longer than 0x7FFF, check
// that the bits that remain after truncation at least match
// the bits of the actual length
- ssize_t actualLen = utf8_to_utf16_length(u8str, u8len);
- if (actualLen < 0 || ((size_t)actualLen & 0x7FFF) != *u16len) {
+ ssize_t actualLen = utf8_to_utf16_length(
+ reinterpret_cast<const uint8_t*>(decodedString->data()),
+ decodedString->size());
+
+ if (actualLen < 0 || ((size_t)actualLen & 0x7FFFU) != *u16len) {
ALOGW("Bad string block: string #%lld decoded length is not correct "
"%lld vs %llu\n",
(long long)idx, (long long)actualLen, (long long)*u16len);
- return NULL;
+ return base::unexpected(std::nullopt);
}
- *u16len = (size_t) actualLen;
- char16_t *u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
+ u16len = (size_t) actualLen;
+ auto u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
if (!u16str) {
ALOGW("No memory when trying to allocate decode cache for string #%d\n",
(int)idx);
- return NULL;
+ return base::unexpected(std::nullopt);
}
- utf8_to_utf16(u8str, u8len, u16str, *u16len + 1);
+ utf8_to_utf16(reinterpret_cast<const uint8_t*>(decodedString->data()),
+ decodedString->size(), u16str, *u16len + 1);
if (mCache == NULL) {
#ifndef __ANDROID__
@@ -793,19 +852,19 @@ const char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
if (mCache == NULL) {
ALOGW("No memory trying to allocate decode cache table of %d bytes\n",
(int)(mHeader->stringCount*sizeof(char16_t**)));
- return NULL;
+ return base::unexpected(std::nullopt);
}
}
if (kDebugStringPoolNoisy) {
- ALOGI("Caching UTF8 string: %s", u8str);
+ ALOGI("Caching UTF8 string: %s", u8str.unsafe_ptr());
}
mCache[idx] = u16str;
- return u16str;
+ return StringPiece16(u16str, *u16len);
} else {
ALOGW("Bad string block: string #%lld extends to %lld, past end at %lld\n",
- (long long)idx, (long long)(u8str+u8len-strings),
+ (long long)idx, (long long)(u8str+*u8len-strings),
(long long)mStringPoolSize);
}
}
@@ -815,33 +874,43 @@ const char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
(int)(mStringPoolSize*sizeof(uint16_t)));
}
}
- return NULL;
+ return base::unexpected(std::nullopt);
}
-const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
+base::expected<StringPiece, NullOrIOError> ResStringPool::string8At(size_t idx) const
{
if (mError == NO_ERROR && idx < mHeader->stringCount) {
if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) {
- return NULL;
+ return base::unexpected(std::nullopt);
}
- const uint32_t off = mEntries[idx]/sizeof(char);
+
+ auto offPtr = mEntries + idx;
+ if (UNLIKELY(!offPtr)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ const uint32_t off = (offPtr.value())/sizeof(char);
if (off < (mStringPoolSize-1)) {
- const uint8_t* strings = (uint8_t*)mStrings;
- const uint8_t* str = strings+off;
+ auto strings = mStrings.convert<uint8_t>();
+ auto str = strings+off;
// Decode the UTF-16 length. This is not used if we're not
// converting to UTF-16 from UTF-8.
- decodeLength(&str);
-
- const size_t encLen = decodeLength(&str);
- *outLen = encLen;
+ const base::expected<size_t, IOError> u16len = decodeLength(&str);
+ if (UNLIKELY(!u16len)) {
+ return base::unexpected(u16len.error());
+ }
- if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
- return stringDecodeAt(idx, str, encLen, outLen);
+ const base::expected<size_t, IOError> u8len = decodeLength(&str);
+ if (UNLIKELY(!u8len)) {
+ return base::unexpected(u8len.error());
+ }
+ if ((uint32_t)(str+*u8len-strings) < mStringPoolSize) {
+ return stringDecodeAt(idx, str, *u8len);
} else {
ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
- (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
+ (int)idx, (int)(str+*u8len-strings), (int)mStringPoolSize);
}
} else {
ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
@@ -849,7 +918,7 @@ const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
(int)(mStringPoolSize*sizeof(uint16_t)));
}
}
- return NULL;
+ return base::unexpected(std::nullopt);
}
/**
@@ -859,74 +928,93 @@ const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
* bits. Strings that exceed the maximum encode length are not placed into
* StringPools in AAPT2.
**/
-const char* ResStringPool::stringDecodeAt(size_t idx, const uint8_t* str,
- const size_t encLen, size_t* outLen) const {
- const uint8_t* strings = (uint8_t*)mStrings;
-
+base::expected<StringPiece, NullOrIOError> ResStringPool::stringDecodeAt(
+ size_t idx, incfs::map_ptr<uint8_t> str, size_t encLen) const
+{
+ const auto strings = mStrings.convert<uint8_t>();
size_t i = 0, end = encLen;
while ((uint32_t)(str+end-strings) < mStringPoolSize) {
- if (str[end] == 0x00) {
+ const auto nullAddress = str + end;
+ if (UNLIKELY(!nullAddress)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ if (nullAddress.value() == 0x00) {
if (i != 0) {
ALOGW("Bad string block: string #%d is truncated (actual length is %d)",
(int)idx, (int)end);
}
- *outLen = end;
- return (const char*)str;
+ if (UNLIKELY(!str.verify(end + 1U))) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ return StringPiece((const char*) str.unsafe_ptr(), end);
}
end = (++i << (sizeof(uint8_t) * 8 * 2 - 1)) | encLen;
}
// Reject malformed (non null-terminated) strings
- ALOGW("Bad string block: string #%d is not null-terminated",
- (int)idx);
- return NULL;
+ ALOGW("Bad string block: string #%d is not null-terminated", (int)idx);
+ return base::unexpected(std::nullopt);
}
-const String8 ResStringPool::string8ObjectAt(size_t idx) const
+base::expected<String8, IOError> ResStringPool::string8ObjectAt(size_t idx) const
{
- size_t len;
- const char *str = string8At(idx, &len);
- if (str != NULL) {
- return String8(str, len);
+ const base::expected<StringPiece, NullOrIOError> str = string8At(idx);
+ if (UNLIKELY(IsIOError(str))) {
+ return base::unexpected(GetIOError(str.error()));
+ }
+ if (str.has_value()) {
+ return String8(str->data(), str->size());
}
- const char16_t *str16 = stringAt(idx, &len);
- if (str16 != NULL) {
- return String8(str16, len);
+ const base::expected<StringPiece16, NullOrIOError> str16 = stringAt(idx);
+ if (UNLIKELY(IsIOError(str16))) {
+ return base::unexpected(GetIOError(str16.error()));
}
+ if (str16.has_value()) {
+ return String8(str16->data(), str16->size());
+ }
+
return String8();
}
-const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
+base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> ResStringPool::styleAt(
+ const ResStringPool_ref& ref) const
{
return styleAt(ref.index);
}
-const ResStringPool_span* ResStringPool::styleAt(size_t idx) const
+base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> ResStringPool::styleAt(
+ size_t idx) const
{
if (mError == NO_ERROR && idx < mHeader->styleCount) {
- const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t));
+ auto offPtr = mEntryStyles + idx;
+ if (UNLIKELY(!offPtr)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ const uint32_t off = ((offPtr.value())/sizeof(uint32_t));
if (off < mStylePoolSize) {
- return (const ResStringPool_span*)(mStyles+off);
+ return (mStyles+off).convert<ResStringPool_span>();
} else {
ALOGW("Bad string block: style #%d entry is at %d, past end at %d\n",
(int)idx, (int)(off*sizeof(uint32_t)),
(int)(mStylePoolSize*sizeof(uint32_t)));
}
}
- return NULL;
+ return base::unexpected(std::nullopt);
}
-ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
+base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_t* str,
+ size_t strLen) const
{
if (mError != NO_ERROR) {
- return mError;
+ return base::unexpected(std::nullopt);
}
- size_t len;
-
if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
if (kDebugStringPoolNoisy) {
ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string());
@@ -948,17 +1036,19 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
ssize_t mid;
while (l <= h) {
mid = l + (h - l)/2;
- const uint8_t* s = (const uint8_t*)string8At(mid, &len);
- int c;
- if (s != NULL) {
- char16_t* end = utf8_to_utf16(s, len, convBuffer, convBufferLen);
+ int c = -1;
+ const base::expected<StringPiece, NullOrIOError> s = string8At(mid);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
+ }
+ if (s.has_value()) {
+ char16_t* end = utf8_to_utf16(reinterpret_cast<const uint8_t*>(s->data()),
+ s->size(), convBuffer, convBufferLen);
c = strzcmp16(convBuffer, end-convBuffer, str, strLen);
- } else {
- c = -1;
}
if (kDebugStringPoolNoisy) {
ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
- (const char*)s, c, (int)l, (int)mid, (int)h);
+ s->data(), c, (int)l, (int)mid, (int)h);
}
if (c == 0) {
if (kDebugStringPoolNoisy) {
@@ -981,15 +1071,21 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
String8 str8(str, strLen);
const size_t str8Len = str8.size();
for (int i=mHeader->stringCount-1; i>=0; i--) {
- const char* s = string8At(i, &len);
- if (kDebugStringPoolNoisy) {
- ALOGI("Looking at %s, i=%d\n", String8(s).string(), i);
+ const base::expected<StringPiece, NullOrIOError> s = string8At(i);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
}
- if (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) {
+ if (s.has_value()) {
if (kDebugStringPoolNoisy) {
- ALOGI("MATCH!");
+ ALOGI("Looking at %s, i=%d\n", s->data(), i);
+ }
+ if (str8Len == s->size()
+ && memcmp(s->data(), str8.string(), str8Len) == 0) {
+ if (kDebugStringPoolNoisy) {
+ ALOGI("MATCH!");
+ }
+ return i;
}
- return i;
}
}
}
@@ -1007,11 +1103,14 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
ssize_t mid;
while (l <= h) {
mid = l + (h - l)/2;
- const char16_t* s = stringAt(mid, &len);
- int c = s ? strzcmp16(s, len, str, strLen) : -1;
+ const base::expected<StringPiece16, NullOrIOError> s = stringAt(mid);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
+ }
+ int c = s.has_value() ? strzcmp16(s->data(), s->size(), str, strLen) : -1;
if (kDebugStringPoolNoisy) {
ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
- String8(s).string(), c, (int)l, (int)mid, (int)h);
+ String8(s->data(), s->size()).string(), c, (int)l, (int)mid, (int)h);
}
if (c == 0) {
if (kDebugStringPoolNoisy) {
@@ -1030,11 +1129,15 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
// span tags; since those always appear at the end of the string
// block, start searching at the back.
for (int i=mHeader->stringCount-1; i>=0; i--) {
- const char16_t* s = stringAt(i, &len);
+ const base::expected<StringPiece16, NullOrIOError> s = stringAt(i);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
+ }
if (kDebugStringPoolNoisy) {
- ALOGI("Looking at %s, i=%d\n", String8(s).string(), i);
+ ALOGI("Looking at %s, i=%d\n", String8(s->data(), s->size()).string(), i);
}
- if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) {
+ if (s.has_value() && strLen == s->size() &&
+ strzcmp16(s->data(), s->size(), str, strLen) == 0) {
if (kDebugStringPoolNoisy) {
ALOGI("MATCH!");
}
@@ -1043,8 +1146,7 @@ ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
}
}
}
-
- return NAME_NOT_FOUND;
+ return base::unexpected(std::nullopt);
}
size_t ResStringPool::size() const
@@ -1062,9 +1164,10 @@ size_t ResStringPool::bytes() const
return (mError == NO_ERROR) ? mHeader->header.size : 0;
}
-const void* ResStringPool::data() const
+incfs::map_ptr<void> ResStringPool::data() const
{
- return mHeader;
+
+ return mHeader.unsafe_ptr();
}
bool ResStringPool::isSorted() const
@@ -1121,7 +1224,7 @@ int32_t ResXMLParser::getCommentID() const
const char16_t* ResXMLParser::getComment(size_t* outLen) const
{
int32_t id = getCommentID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
uint32_t ResXMLParser::getLineNumber() const
@@ -1140,7 +1243,7 @@ int32_t ResXMLParser::getTextID() const
const char16_t* ResXMLParser::getText(size_t* outLen) const
{
int32_t id = getTextID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
ssize_t ResXMLParser::getTextValue(Res_value* outValue) const
@@ -1164,7 +1267,7 @@ const char16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const
{
int32_t id = getNamespacePrefixID();
//printf("prefix=%d event=%p\n", id, mEventCode);
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
int32_t ResXMLParser::getNamespaceUriID() const
@@ -1179,7 +1282,7 @@ const char16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const
{
int32_t id = getNamespaceUriID();
//printf("uri=%d event=%p\n", id, mEventCode);
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
int32_t ResXMLParser::getElementNamespaceID() const
@@ -1196,7 +1299,7 @@ int32_t ResXMLParser::getElementNamespaceID() const
const char16_t* ResXMLParser::getElementNamespace(size_t* outLen) const
{
int32_t id = getElementNamespaceID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
int32_t ResXMLParser::getElementNameID() const
@@ -1213,7 +1316,7 @@ int32_t ResXMLParser::getElementNameID() const
const char16_t* ResXMLParser::getElementName(size_t* outLen) const
{
int32_t id = getElementNameID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
size_t ResXMLParser::getAttributeCount() const
@@ -1246,7 +1349,7 @@ const char16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen)
if (kDebugXMLNoisy) {
printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
}
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) const
@@ -1256,7 +1359,7 @@ const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) con
if (kDebugXMLNoisy) {
printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
}
- return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.string8At(id), outLen) : NULL;
}
int32_t ResXMLParser::getAttributeNameID(size_t idx) const
@@ -1281,7 +1384,7 @@ const char16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
if (kDebugXMLNoisy) {
printf("getAttributeName 0x%zx=0x%x\n", idx, id);
}
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const
@@ -1291,7 +1394,7 @@ const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const
if (kDebugXMLNoisy) {
printf("getAttributeName 0x%zx=0x%x\n", idx, id);
}
- return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.string8At(id), outLen) : NULL;
}
uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
@@ -1328,7 +1431,7 @@ const char16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen
if (kDebugXMLNoisy) {
printf("getAttributeValue 0x%zx=0x%x\n", idx, id);
}
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
int32_t ResXMLParser::getAttributeDataType(size_t idx) const
@@ -3596,9 +3699,10 @@ struct ResTable::PackageGroup
ssize_t findType16(const char16_t* type, size_t len) const {
const size_t N = packages.size();
for (size_t i = 0; i < N; i++) {
- ssize_t index = packages[i]->typeStrings.indexOfString(type, len);
- if (index >= 0) {
- return index + packages[i]->typeIdOffset;
+ const base::expected<size_t, NullOrIOError> index =
+ packages[i]->typeStrings.indexOfString(type, len);
+ if (index.has_value()) {
+ return *index + packages[i]->typeIdOffset;
}
}
return -1;
@@ -4304,21 +4408,21 @@ bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* ou
outName->package = grp->name.string();
outName->packageLen = grp->name.size();
if (allowUtf8) {
- outName->type8 = entry.typeStr.string8(&outName->typeLen);
- outName->name8 = entry.keyStr.string8(&outName->nameLen);
+ outName->type8 = UnpackOptionalString(entry.typeStr.string8(), &outName->typeLen);
+ outName->name8 = UnpackOptionalString(entry.keyStr.string8(), &outName->nameLen);
} else {
outName->type8 = NULL;
outName->name8 = NULL;
}
if (outName->type8 == NULL) {
- outName->type = entry.typeStr.string16(&outName->typeLen);
+ outName->type = UnpackOptionalString(entry.typeStr.string16(), &outName->typeLen);
// If we have a bad index for some reason, we should abort.
if (outName->type == NULL) {
return false;
}
}
if (outName->name8 == NULL) {
- outName->name = entry.keyStr.string16(&outName->nameLen);
+ outName->name = UnpackOptionalString(entry.keyStr.string16(), &outName->nameLen);
// If we have a bad index for some reason, we should abort.
if (outName->name == NULL) {
return false;
@@ -4406,7 +4510,8 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
entry.package->header->index,
outValue->dataType,
outValue->dataType == Res_value::TYPE_STRING ?
- String8(entry.package->header->values.stringAt(outValue->data, &len)).string() :
+ String8(UnpackOptionalString(
+ entry.package->header->values.stringAt(outValue->data), &len)).string() :
"",
outValue->data);
}
@@ -4462,7 +4567,8 @@ const char16_t* ResTable::valueToString(
return NULL;
}
if (value->dataType == value->TYPE_STRING) {
- return getTableStringBlock(stringBlock)->stringAt(value->data, outLen);
+ return UnpackOptionalString(getTableStringBlock(stringBlock)->stringAt(value->data),
+ outLen);
}
// XXX do int to string conversions.
return NULL;
@@ -4978,15 +5084,13 @@ nope:
size_t targetTypeLen = typeLen;
do {
- ssize_t ti = group->packages[pi]->typeStrings.indexOfString(
- targetType, targetTypeLen);
- if (ti < 0) {
+ auto ti = group->packages[pi]->typeStrings.indexOfString(targetType, targetTypeLen);
+ if (!ti.has_value()) {
continue;
}
- ti += group->packages[pi]->typeIdOffset;
-
- const uint32_t identifier = findEntry(group, ti, name, nameLen,
+ *ti += group->packages[pi]->typeIdOffset;
+ const uint32_t identifier = findEntry(group, *ti, name, nameLen,
outTypeSpecFlags);
if (identifier != 0) {
if (fakePublic && outTypeSpecFlags) {
@@ -5009,8 +5113,9 @@ uint32_t ResTable::findEntry(const PackageGroup* group, ssize_t typeIndex, const
const size_t typeCount = typeList.size();
for (size_t i = 0; i < typeCount; i++) {
const Type* t = typeList[i];
- const ssize_t ei = t->package->keyStrings.indexOfString(name, nameLen);
- if (ei < 0) {
+ const base::expected<size_t, NullOrIOError> ei =
+ t->package->keyStrings.indexOfString(name, nameLen);
+ if (!ei.has_value()) {
continue;
}
@@ -5025,7 +5130,7 @@ uint32_t ResTable::findEntry(const PackageGroup* group, ssize_t typeIndex, const
continue;
}
- if (dtohl(entry->key.index) == (size_t) ei) {
+ if (dtohl(entry->key.index) == (size_t) *ei) {
uint32_t resId = Res_MAKEID(group->id - 1, typeIndex, iter.index());
if (outTypeSpecFlags) {
Entry result;
@@ -6187,8 +6292,9 @@ void ResTable::forEachConfiguration(bool ignoreMipmap, bool ignoreAndroidPackage
for (size_t k = 0; k < numTypes; k++) {
const Type* type = typeList[k];
const ResStringPool& typeStrings = type->package->typeStrings;
- if (ignoreMipmap && typeStrings.string8ObjectAt(
- type->typeSpec->id - 1) == "mipmap") {
+ const base::expected<String8, NullOrIOError> typeStr = typeStrings.string8ObjectAt(
+ type->typeSpec->id - 1);
+ if (ignoreMipmap && typeStr.has_value() && *typeStr == "mipmap") {
continue;
}
@@ -6244,24 +6350,18 @@ void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales,
StringPoolRef::StringPoolRef(const ResStringPool* pool, uint32_t index)
: mPool(pool), mIndex(index) {}
-const char* StringPoolRef::string8(size_t* outLen) const {
- if (mPool != NULL) {
- return mPool->string8At(mIndex, outLen);
+base::expected<StringPiece, NullOrIOError> StringPoolRef::string8() const {
+ if (LIKELY(mPool != NULL)) {
+ return mPool->string8At(mIndex);
}
- if (outLen != NULL) {
- *outLen = 0;
- }
- return NULL;
+ return base::unexpected(std::nullopt);
}
-const char16_t* StringPoolRef::string16(size_t* outLen) const {
- if (mPool != NULL) {
- return mPool->stringAt(mIndex, outLen);
+base::expected<StringPiece16, NullOrIOError> StringPoolRef::string16() const {
+ if (LIKELY(mPool != NULL)) {
+ return mPool->stringAt(mIndex);
}
- if (outLen != NULL) {
- *outLen = 0;
- }
- return NULL;
+ return base::unexpected(std::nullopt);
}
bool ResTable::getResourceFlags(uint32_t resID, uint32_t* outFlags) const {
@@ -7380,13 +7480,13 @@ void ResTable::print_value(const Package* pkg, const Res_value& value) const
printf("(dynamic attribute) 0x%08x\n", value.data);
} else if (value.dataType == Res_value::TYPE_STRING) {
size_t len;
- const char* str8 = pkg->header->values.string8At(
- value.data, &len);
+ const char* str8 = UnpackOptionalString(pkg->header->values.string8At(
+ value.data), &len);
if (str8 != NULL) {
printf("(string8) \"%s\"\n", normalizeForOutput(str8).string());
} else {
- const char16_t* str16 = pkg->header->values.stringAt(
- value.data, &len);
+ const char16_t* str16 = UnpackOptionalString(pkg->header->values.stringAt(
+ value.data), &len);
if (str16 != NULL) {
printf("(string16) \"%s\"\n",
normalizeForOutput(String8(str16, len).string()).string());
diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp
index c63dff8f9104..a34aa7239250 100644
--- a/libs/androidfw/ResourceUtils.cpp
+++ b/libs/androidfw/ResourceUtils.cpp
@@ -48,61 +48,76 @@ bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, Strin
!(has_type_separator && out_type->empty());
}
-bool ToResourceName(const StringPoolRef& type_string_ref,
- const StringPoolRef& entry_string_ref,
- const StringPiece& package_name,
- AssetManager2::ResourceName* out_name) {
- out_name->package = package_name.data();
- out_name->package_len = package_name.size();
-
- out_name->type = type_string_ref.string8(&out_name->type_len);
- out_name->type16 = nullptr;
- if (out_name->type == nullptr) {
- out_name->type16 = type_string_ref.string16(&out_name->type_len);
- if (out_name->type16 == nullptr) {
- return false;
+base::expected<AssetManager2::ResourceName, NullOrIOError> ToResourceName(
+ const StringPoolRef& type_string_ref, const StringPoolRef& entry_string_ref,
+ const StringPiece& package_name) {
+ AssetManager2::ResourceName name{
+ .package = package_name.data(),
+ .package_len = package_name.size(),
+ };
+
+ if (base::expected<StringPiece, NullOrIOError> type_str = type_string_ref.string8()) {
+ name.type = type_str->data();
+ name.type_len = type_str->size();
+ } else if (UNLIKELY(IsIOError(type_str))) {
+ return base::unexpected(type_str.error());
+ }
+
+ if (name.type == nullptr) {
+ if (base::expected<StringPiece16, NullOrIOError> type16_str = type_string_ref.string16()) {
+ name.type16 = type16_str->data();
+ name.type_len = type16_str->size();
+ } else if (!type16_str.has_value()) {
+ return base::unexpected(type16_str.error());
}
}
- out_name->entry = entry_string_ref.string8(&out_name->entry_len);
- out_name->entry16 = nullptr;
- if (out_name->entry == nullptr) {
- out_name->entry16 = entry_string_ref.string16(&out_name->entry_len);
- if (out_name->entry16 == nullptr) {
- return false;
+ if (base::expected<StringPiece, NullOrIOError> entry_str = entry_string_ref.string8()) {
+ name.entry = entry_str->data();
+ name.entry_len = entry_str->size();
+ } else if (UNLIKELY(IsIOError(entry_str))) {
+ return base::unexpected(entry_str.error());
+ }
+
+ if (name.entry == nullptr) {
+ if (base::expected<StringPiece16, NullOrIOError> entry16_str = entry_string_ref.string16()) {
+ name.entry16 = entry16_str->data();
+ name.entry_len = entry16_str->size();
+ } else if (!entry16_str.has_value()) {
+ return base::unexpected(entry16_str.error());
}
}
- return true;
+ return name;
}
-std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name) {
+std::string ToFormattedResourceString(const AssetManager2::ResourceName& resource_name) {
std::string result;
- if (resource_name->package != nullptr) {
- result.append(resource_name->package, resource_name->package_len);
+ if (resource_name.package != nullptr) {
+ result.append(resource_name.package, resource_name.package_len);
}
- if (resource_name->type != nullptr || resource_name->type16 != nullptr) {
+ if (resource_name.type != nullptr || resource_name.type16 != nullptr) {
if (!result.empty()) {
result += ":";
}
- if (resource_name->type != nullptr) {
- result.append(resource_name->type, resource_name->type_len);
+ if (resource_name.type != nullptr) {
+ result.append(resource_name.type, resource_name.type_len);
} else {
- result += util::Utf16ToUtf8(StringPiece16(resource_name->type16, resource_name->type_len));
+ result += util::Utf16ToUtf8(StringPiece16(resource_name.type16, resource_name.type_len));
}
}
- if (resource_name->entry != nullptr || resource_name->entry16 != nullptr) {
+ if (resource_name.entry != nullptr || resource_name.entry16 != nullptr) {
if (!result.empty()) {
result += "/";
}
- if (resource_name->entry != nullptr) {
- result.append(resource_name->entry, resource_name->entry_len);
+ if (resource_name.entry != nullptr) {
+ result.append(resource_name.entry, resource_name.entry_len);
} else {
- result += util::Utf16ToUtf8(StringPiece16(resource_name->entry16, resource_name->entry_len));
+ result += util::Utf16ToUtf8(StringPiece16(resource_name.entry16, resource_name.entry_len));
}
}
diff --git a/libs/androidfw/StreamingZipInflater.cpp b/libs/androidfw/StreamingZipInflater.cpp
index b39b5f0b8b36..1c5e5d44c845 100644
--- a/libs/androidfw/StreamingZipInflater.cpp
+++ b/libs/androidfw/StreamingZipInflater.cpp
@@ -70,13 +70,13 @@ StreamingZipInflater::StreamingZipInflater(int fd, off64_t compDataStart,
/*
* Streaming access to compressed data held in an mmapped region of memory
*/
-StreamingZipInflater::StreamingZipInflater(FileMap* dataMap, size_t uncompSize) {
+StreamingZipInflater::StreamingZipInflater(const incfs::IncFsFileMap* dataMap, size_t uncompSize) {
mFd = -1;
mDataMap = dataMap;
mOutTotalSize = uncompSize;
- mInTotalSize = dataMap->getDataLength();
+ mInTotalSize = dataMap->length();
- mInBuf = (uint8_t*) dataMap->getDataPtr();
+ mInBuf = (uint8_t*) dataMap->unsafe_data(); // IncFs safety handled in zlib.
mInBufSize = mInTotalSize;
mOutBufSize = StreamingZipInflater::OUTPUT_CHUNK_SIZE;
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index e77ac3df474c..52e7a70521a1 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -233,6 +233,29 @@ FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const
}
/*
+ * Create a new incfs::IncFsFileMap object that spans the data in "entry".
+ */
+std::optional<incfs::IncFsFileMap> ZipFileRO::createEntryIncFsFileMap(ZipEntryRO entry) const
+{
+ const _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry);
+ const ZipEntry& ze = zipEntry->entry;
+ int fd = GetFileDescriptor(mHandle);
+ size_t actualLen = 0;
+
+ if (ze.method == kCompressStored) {
+ actualLen = ze.uncompressed_length;
+ } else {
+ actualLen = ze.compressed_length;
+ }
+
+ incfs::IncFsFileMap newMap;
+ if (!newMap.Create(fd, ze.offset, actualLen, mFileName)) {
+ return std::nullopt;
+ }
+ return std::move(newMap);
+}
+
+/*
* Uncompress an entry, in its entirety, into the provided output buffer.
*
* This doesn't verify the data's CRC, which might be useful for
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
index 568e3b63d67f..58fc5bbbab5e 100644
--- a/libs/androidfw/ZipUtils.cpp
+++ b/libs/androidfw/ZipUtils.cpp
@@ -40,7 +40,7 @@ class FileReader : public zip_archive::Reader {
explicit FileReader(FILE* fp) : Reader(), mFp(fp), mCurrentOffset(0) {
}
- bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const {
+ bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const override {
// Data is usually requested sequentially, so this helps avoid pointless
// fseeks every time we perform a read. There's an impedence mismatch
// here because the original API was designed around pread and pwrite.
@@ -71,7 +71,7 @@ class FdReader : public zip_archive::Reader {
explicit FdReader(int fd) : mFd(fd) {
}
- bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const {
+ bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const override {
return android::base::ReadFullyAtOffset(mFd, buf, len, offset);
}
@@ -81,22 +81,27 @@ class FdReader : public zip_archive::Reader {
class BufferReader : public zip_archive::Reader {
public:
- BufferReader(const void* input, size_t inputSize) : Reader(),
- mInput(reinterpret_cast<const uint8_t*>(input)),
+ BufferReader(incfs::map_ptr<void> input, size_t inputSize) : Reader(),
+ mInput(input.convert<uint8_t>()),
mInputSize(inputSize) {
}
- bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const {
+ bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const override {
if (mInputSize < len || offset > mInputSize - len) {
return false;
}
- memcpy(buf, mInput + offset, len);
+ const incfs::map_ptr<uint8_t> pos = mInput.offset(offset);
+ if (!pos.verify(len)) {
+ return false;
+ }
+
+ memcpy(buf, pos.unsafe_ptr(), len);
return true;
}
private:
- const uint8_t* mInput;
+ const incfs::map_ptr<uint8_t> mInput;
const size_t mInputSize;
};
@@ -138,7 +143,7 @@ class BufferWriter : public zip_archive::Writer {
return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0);
}
-/*static*/ bool ZipUtils::inflateToBuffer(const void* in, void* buf,
+/*static*/ bool ZipUtils::inflateToBuffer(incfs::map_ptr<void> in, void* buf,
long uncompressedLen, long compressedLen)
{
BufferReader reader(in, compressedLen);
diff --git a/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp b/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
index 2dac47b0dac6..b36ff0968ba3 100644
--- a/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
+++ b/libs/androidfw/fuzz/cursorwindow_fuzzer/Android.bp
@@ -27,5 +27,9 @@ cc_fuzz {
"libutils",
],
},
+ darwin: {
+ // libbinder is not supported on mac
+ enabled: false,
+ },
},
}
diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp b/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp
index 96d44ab8e45c..5309ab2b6e20 100644
--- a/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp
+++ b/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp
@@ -31,9 +31,6 @@ using android::LoadedArsc;
using android::StringPiece;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-
- std::unique_ptr<const LoadedArsc> loaded_arsc =
- LoadedArsc::Load(StringPiece(reinterpret_cast<const char*>(data), size));
-
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(data, size);
return 0;
} \ No newline at end of file
diff --git a/libs/androidfw/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h
index 298509eb37a1..80bae20f3419 100644
--- a/libs/androidfw/include/androidfw/Asset.h
+++ b/libs/androidfw/include/androidfw/Asset.h
@@ -23,18 +23,18 @@
#include <stdio.h>
#include <sys/types.h>
-
#include <memory>
+#include <optional>
#include <android-base/unique_fd.h>
+#include <util/map_ptr.h>
+
#include <utils/Compat.h>
#include <utils/Errors.h>
#include <utils/String8.h>
namespace android {
-class FileMap;
-
/*
* Instances of this class provide read-only operations on a byte stream.
*
@@ -49,6 +49,8 @@ class FileMap;
class Asset {
public:
virtual ~Asset(void) = default;
+ Asset(const Asset& src) = delete;
+ Asset& operator=(const Asset& src) = delete;
static int32_t getGlobalCount();
static String8 getAssetAllocations();
@@ -87,8 +89,19 @@ public:
/*
* Get a pointer to a buffer with the entire contents of the file.
+ * If `aligned` is true, the buffer data will be aligned to a 4-byte boundary.
+ *
+ * Use this function if the asset can never reside on IncFs.
*/
- virtual const void* getBuffer(bool wordAligned) = 0;
+ virtual const void* getBuffer(bool aligned) = 0;
+
+ /*
+ * Get a incfs::map_ptr<void> to a buffer with the entire contents of the file.
+ * If `aligned` is true, the buffer data will be aligned to a 4-byte boundary.
+ *
+ * Use this function if the asset can potentially reside on IncFs.
+ */
+ virtual incfs::map_ptr<void> getIncFsBuffer(bool aligned) = 0;
/*
* Get the total amount of data that can be read.
@@ -152,10 +165,6 @@ protected:
AccessMode getAccessMode(void) const { return mAccessMode; }
private:
- /* these operations are not implemented */
- Asset(const Asset& src);
- Asset& operator=(const Asset& src);
-
/* AssetManager needs access to our "create" functions */
friend class AssetManager;
friend class ApkAssets;
@@ -169,8 +178,7 @@ private:
/*
* Create the asset from a named, compressed file on disk (e.g. ".gz").
*/
- static Asset* createFromCompressedFile(const char* fileName,
- AccessMode mode);
+ static Asset* createFromCompressedFile(const char* fileName, AccessMode mode);
#if 0
/*
@@ -200,31 +208,21 @@ private:
/*
* Create the asset from a memory-mapped file segment.
*
- * The asset takes ownership of the FileMap.
- */
- static Asset* createFromUncompressedMap(FileMap* dataMap, AccessMode mode);
-
- /*
- * Create the asset from a memory-mapped file segment.
- *
- * The asset takes ownership of the FileMap and the file descriptor "fd". The file descriptor is
- * used to request new file descriptors using "openFileDescriptor".
+ * The asset takes ownership of the incfs::IncFsFileMap and the file descriptor "fd". The
+ * file descriptor is used to request new file descriptors using "openFileDescriptor".
*/
- static std::unique_ptr<Asset> createFromUncompressedMap(std::unique_ptr<FileMap> dataMap,
- base::unique_fd fd, AccessMode mode);
+ static std::unique_ptr<Asset> createFromUncompressedMap(incfs::IncFsFileMap&& dataMap,
+ AccessMode mode,
+ base::unique_fd fd = {});
/*
* Create the asset from a memory-mapped file segment with compressed
* data.
*
- * The asset takes ownership of the FileMap.
+ * The asset takes ownership of the incfs::IncFsFileMap.
*/
- static Asset* createFromCompressedMap(FileMap* dataMap,
- size_t uncompressedLen, AccessMode mode);
-
- static std::unique_ptr<Asset> createFromCompressedMap(std::unique_ptr<FileMap> dataMap,
- size_t uncompressedLen, AccessMode mode);
-
+ static std::unique_ptr<Asset> createFromCompressedMap(incfs::IncFsFileMap&& dataMap,
+ size_t uncompressedLen, AccessMode mode);
/*
* Create from a reference-counted chunk of shared memory.
@@ -252,7 +250,7 @@ private:
class _FileAsset : public Asset {
public:
_FileAsset(void);
- virtual ~_FileAsset(void);
+ ~_FileAsset(void) override;
/*
* Use a piece of an already-open file.
@@ -266,21 +264,24 @@ public:
*
* On success, the object takes ownership of "dataMap" and "fd".
*/
- status_t openChunk(FileMap* dataMap, base::unique_fd fd);
+ status_t openChunk(incfs::IncFsFileMap&& dataMap, base::unique_fd fd);
/*
* Standard Asset interfaces.
*/
- virtual ssize_t read(void* buf, size_t count);
- virtual off64_t seek(off64_t offset, int whence);
- virtual void close(void);
- virtual const void* getBuffer(bool wordAligned);
- virtual off64_t getLength(void) const { return mLength; }
- virtual off64_t getRemainingLength(void) const { return mLength-mOffset; }
- virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const;
- virtual bool isAllocated(void) const { return mBuf != NULL; }
+ ssize_t read(void* buf, size_t count) override;
+ off64_t seek(off64_t offset, int whence) override;
+ void close(void) override;
+ const void* getBuffer(bool aligned) override;
+ incfs::map_ptr<void> getIncFsBuffer(bool aligned) override;
+ off64_t getLength(void) const override { return mLength; }
+ off64_t getRemainingLength(void) const override { return mLength-mOffset; }
+ int openFileDescriptor(off64_t* outStart, off64_t* outLength) const override;
+ bool isAllocated(void) const override { return mBuf != NULL; }
private:
+ incfs::map_ptr<void> ensureAlignment(const incfs::IncFsFileMap& map);
+
off64_t mStart; // absolute file offset of start of chunk
off64_t mLength; // length of the chunk
off64_t mOffset; // current local offset, 0 == mStart
@@ -295,10 +296,8 @@ private:
*/
enum { kReadVsMapThreshold = 4096 };
- FileMap* mMap; // for memory map
- unsigned char* mBuf; // for read
-
- const void* ensureAlignment(FileMap* map);
+ unsigned char* mBuf; // for read
+ std::optional<incfs::IncFsFileMap> mMap; // for memory map
};
@@ -323,7 +322,7 @@ public:
*
* On success, the object takes ownership of "fd".
*/
- status_t openChunk(FileMap* dataMap, size_t uncompressedLen);
+ status_t openChunk(incfs::IncFsFileMap&& dataMap, size_t uncompressedLen);
/*
* Standard Asset interfaces.
@@ -331,24 +330,23 @@ public:
virtual ssize_t read(void* buf, size_t count);
virtual off64_t seek(off64_t offset, int whence);
virtual void close(void);
- virtual const void* getBuffer(bool wordAligned);
+ virtual const void* getBuffer(bool aligned);
+ virtual incfs::map_ptr<void> getIncFsBuffer(bool aligned);
virtual off64_t getLength(void) const { return mUncompressedLen; }
virtual off64_t getRemainingLength(void) const { return mUncompressedLen-mOffset; }
virtual int openFileDescriptor(off64_t* /* outStart */, off64_t* /* outLength */) const { return -1; }
virtual bool isAllocated(void) const { return mBuf != NULL; }
private:
- off64_t mStart; // offset to start of compressed data
- off64_t mCompressedLen; // length of the compressed data
- off64_t mUncompressedLen; // length of the uncompressed data
- off64_t mOffset; // current offset, 0 == start of uncomp data
-
- FileMap* mMap; // for memory-mapped input
- int mFd; // for file input
-
- class StreamingZipInflater* mZipInflater; // for streaming large compressed assets
-
- unsigned char* mBuf; // for getBuffer()
+ off64_t mStart; // offset to start of compressed data
+ off64_t mCompressedLen; // length of the compressed data
+ off64_t mUncompressedLen; // length of the uncompressed data
+ off64_t mOffset; // current offset, 0 == start of uncomp data
+ int mFd; // for file input
+
+ class StreamingZipInflater* mZipInflater; // for streaming large compressed assets
+ unsigned char* mBuf; // for getBuffer()
+ std::optional<incfs::IncFsFileMap> mMap; // for memory-mapped input
};
// need: shared mmap version?
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 30ef25c6a516..a92694c94b9f 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -131,8 +131,8 @@ class AssetManager2 {
bool GetOverlayablesToString(const android::StringPiece& package_name,
std::string* out) const;
- const std::unordered_map<std::string, std::string>*
- GetOverlayableMapForPackage(uint32_t package_id) const;
+ const std::unordered_map<std::string, std::string>* GetOverlayableMapForPackage(
+ uint32_t package_id) const;
// Returns whether the resources.arsc of any loaded apk assets is allocated in RAM (not mmapped).
bool ContainsAllocatedTable() const;
@@ -145,14 +145,16 @@ class AssetManager2 {
return configuration_;
}
- // Returns all configurations for which there are resources defined. This includes resource
- // configurations in all the ApkAssets set for this AssetManager.
+ // Returns all configurations for which there are resources defined, or an I/O error if reading
+ // resource data failed.
+ //
+ // This includes resource configurations in all the ApkAssets set for this AssetManager.
// If `exclude_system` is set to true, resource configurations from system APKs
// ('android' package, other libraries) will be excluded from the list.
// If `exclude_mipmap` is set to true, resource configurations defined for resource type 'mipmap'
// will be excluded from the list.
- std::set<ResTable_config> GetResourceConfigurations(bool exclude_system = false,
- bool exclude_mipmap = false) const;
+ base::expected<std::set<ResTable_config>, IOError> GetResourceConfigurations(
+ bool exclude_system = false, bool exclude_mipmap = false) const;
// Returns all the locales for which there are resources defined. This includes resource
// locales in all the ApkAssets set for this AssetManager.
@@ -194,77 +196,119 @@ class AssetManager2 {
std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie,
Asset::AccessMode mode) const;
- // Populates the `out_name` parameter with resource name information.
- // Utf8 strings are preferred, and only if they are unavailable are
- // the Utf16 variants populated.
- // Returns false if the resource was not found or the name was missing/corrupt.
- bool GetResourceName(uint32_t resid, ResourceName* out_name) const;
-
- // Populates `out_flags` with the bitmask of configuration axis that this resource varies with.
- // See ResTable_config for the list of configuration axis.
- // Returns false if the resource was not found.
- bool GetResourceFlags(uint32_t resid, uint32_t* out_flags) const;
+ // Returns the resource name of the specified resource ID.
+ //
+ // Utf8 strings are preferred, and only if they are unavailable are the Utf16 variants populated.
+ //
+ // Returns a null error if the name is missing/corrupt, or an I/O error if reading resource data
+ // failed.
+ base::expected<ResourceName, NullOrIOError> GetResourceName(uint32_t resid) const;
// Finds the resource ID assigned to `resource_name`.
+ //
// `resource_name` must be of the form '[package:][type/]entry'.
// If no package is specified in `resource_name`, then `fallback_package` is used as the package.
// If no type is specified in `resource_name`, then `fallback_type` is used as the type.
- // Returns 0x0 if no resource by that name was found.
- uint32_t GetResourceId(const std::string& resource_name, const std::string& fallback_type = {},
- const std::string& fallback_package = {}) const;
-
- // Retrieves the best matching resource with ID `resid`. The resource value is filled into
- // `out_value` and the configuration for the selected value is populated in `out_selected_config`.
- // `out_flags` holds the same flags as retrieved with GetResourceFlags().
- // If `density_override` is non-zero, the configuration to match against is overridden with that
- // density.
//
- // Returns a valid cookie if the resource was found. If the resource was not found, or if the
- // resource was a map/bag type, then kInvalidCookie is returned. If `may_be_bag` is false,
- // this function logs if the resource was a map/bag type before returning kInvalidCookie.
- ApkAssetsCookie GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override,
- Res_value* out_value, ResTable_config* out_selected_config,
- uint32_t* out_flags) const;
-
- // Resolves the resource reference in `in_out_value` if the data type is
- // Res_value::TYPE_REFERENCE.
- // `cookie` is the ApkAssetsCookie of the reference in `in_out_value`.
- // `in_out_value` is the reference to resolve. The result is placed back into this object.
- // `in_out_flags` is the type spec flags returned from calls to GetResource() or
- // GetResourceFlags(). Configuration flags of the values pointed to by the reference
- // are OR'd together with `in_out_flags`.
- // `in_out_config` is populated with the configuration for which the resolved value was defined.
- // `out_last_reference` is populated with the last reference ID before resolving to an actual
- // value. This is only initialized if the passed in `in_out_value` is a reference.
- // Returns the cookie of the APK the resolved resource was defined in, or kInvalidCookie if
- // it was not found.
- ApkAssetsCookie ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
- ResTable_config* in_out_selected_config, uint32_t* in_out_flags,
- uint32_t* out_last_reference) const;
+ // Returns a null error if no resource by that name was found, or an I/O error if reading resource
+ // data failed.
+ base::expected<uint32_t, NullOrIOError> GetResourceId(
+ const std::string& resource_name, const std::string& fallback_type = {},
+ const std::string& fallback_package = {}) const;
+
+ struct SelectedValue {
+ friend AssetManager2;
+ friend Theme;
+ SelectedValue() = default;
+ SelectedValue(const ResolvedBag* bag, const ResolvedBag::Entry& entry) :
+ cookie(entry.cookie), data(entry.value.data), type(entry.value.dataType),
+ flags(bag->type_spec_flags), resid(0U), config({}) {};
+
+ // The cookie representing the ApkAssets in which the value resides.
+ ApkAssetsCookie cookie = kInvalidCookie;
- // Resets the resource resolution structures in preparation for the next resource retrieval.
- void ResetResourceResolution() const;
+ // The data for this value, as interpreted according to `type`.
+ Res_value::data_type data;
- // Enables or disables resource resolution logging. Clears stored steps when disabled.
- void SetResourceResolutionLoggingEnabled(bool enabled);
+ // Type of the data value.
+ uint8_t type;
- // Returns formatted log of last resource resolution path, or empty if no resource has been
- // resolved yet.
- std::string GetLastResourceResolution() const;
+ // The bitmask of configuration axis that this resource varies with.
+ // See ResTable_config::CONFIG_*.
+ uint32_t flags;
+
+ // The resource ID from which this value was resolved.
+ uint32_t resid;
- const std::vector<uint32_t> GetBagResIdStack(uint32_t resid);
+ // The configuration for which the resolved value was defined.
+ ResTable_config config;
+
+ private:
+ SelectedValue(uint8_t value_type, Res_value::data_type value_data, ApkAssetsCookie cookie,
+ uint32_t type_flags, uint32_t resid, const ResTable_config& config) :
+ cookie(cookie), data(value_data), type(value_type), flags(type_flags),
+ resid(resid), config(config) {};
+ };
+
+ // Retrieves the best matching resource value with ID `resid`.
+ //
+ // If `may_be_bag` is false, this function logs if the resource was a map/bag type and returns a
+ // null result. If `density_override` is non-zero, the configuration to match against is
+ // overridden with that density.
+ //
+ // Returns a null error if a best match could not be found, or an I/O error if reading resource
+ // data failed.
+ base::expected<SelectedValue, NullOrIOError> GetResource(uint32_t resid, bool may_be_bag = false,
+ uint16_t density_override = 0U) const;
+
+ // Resolves the resource referenced in `value` if the type is Res_value::TYPE_REFERENCE.
+ //
+ // If the data type is not Res_value::TYPE_REFERENCE, no work is done. Configuration flags of the
+ // values pointed to by the reference are OR'd into `value.flags`. If `cache_value` is true, then
+ // the resolved value will be cached and used when attempting to resolve the resource id specified
+ // in `value`.
+ //
+ // Returns a null error if the resource could not be resolved, or an I/O error if reading
+ // resource data failed.
+ base::expected<std::monostate, NullOrIOError> ResolveReference(SelectedValue& value,
+ bool cache_value = false) const;
// Retrieves the best matching bag/map resource with ID `resid`.
+ //
// This method will resolve all parent references for this bag and merge keys with the child.
// To iterate over the keys, use the following idiom:
//
- // const AssetManager2::ResolvedBag* bag = asset_manager->GetBag(id);
- // if (bag != nullptr) {
- // for (auto iter = begin(bag); iter != end(bag); ++iter) {
+ // base::expected<const ResolvedBag*, NullOrIOError> bag = asset_manager->GetBag(id);
+ // if (bag.has_value()) {
+ // for (auto iter = begin(*bag); iter != end(*bag); ++iter) {
// ...
// }
// }
- const ResolvedBag* GetBag(uint32_t resid);
+ //
+ // Returns a null error if a best match could not be found, or an I/O error if reading resource
+ // data failed.
+ base::expected<const ResolvedBag*, NullOrIOError> GetBag(uint32_t resid) const;
+
+ // Retrieves the best matching bag/map resource of the resource referenced in `value`.
+ //
+ // If `value.type` is not Res_value::TYPE_REFERENCE, a null result is returned.
+ // Configuration flags of the bag pointed to by the reference are OR'd into `value.flags`.
+ //
+ // Returns a null error if a best match could not be found, or an I/O error if reading resource
+ // data failed.
+ base::expected<const ResolvedBag*, NullOrIOError> ResolveBag(SelectedValue& value) const;
+
+ const std::vector<uint32_t> GetBagResIdStack(uint32_t resid) const;
+
+ // Resets the resource resolution structures in preparation for the next resource retrieval.
+ void ResetResourceResolution() const;
+
+ // Enables or disables resource resolution logging. Clears stored steps when disabled.
+ void SetResourceResolutionLoggingEnabled(bool enabled);
+
+ // Returns formatted log of last resource resolution path, or empty if no resource has been
+ // resolved yet.
+ std::string GetLastResourceResolution() const;
// Creates a new Theme from this AssetManager.
std::unique_ptr<Theme> NewTheme();
@@ -286,11 +330,15 @@ class AssetManager2 {
private:
DISALLOW_COPY_AND_ASSIGN(AssetManager2);
+ struct TypeConfig {
+ incfs::verified_map_ptr<ResTable_type> type;
+ ResTable_config config;
+ };
+
// A collection of configurations and their associated ResTable_type that match the current
// AssetManager configuration.
struct FilteredConfigGroup {
- std::vector<ResTable_config> configurations;
- std::vector<const ResTable_type*> types;
+ std::vector<TypeConfig> type_configs;
};
// Represents an single package.
@@ -331,9 +379,7 @@ class AssetManager2 {
};
// Finds the best entry for `resid` from the set of ApkAssets. The entry can be a simple
- // Res_value, or a complex map/bag type. If successful, it is available in `out_entry`.
- // Returns kInvalidCookie on failure. Otherwise, the return value is the cookie associated with
- // the ApkAssets in which the entry was found.
+ // Res_value, or a complex map/bag type. Returns a null result if a best entry cannot be found.
//
// `density_override` overrides the density of the current configuration when doing a search.
//
@@ -347,13 +393,15 @@ class AssetManager2 {
//
// NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
// bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
- ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
- bool ignore_configuration, FindEntryResult* out_entry) const;
+ base::expected<FindEntryResult, NullOrIOError> FindEntry(uint32_t resid,
+ uint16_t density_override,
+ bool stop_at_first_match,
+ bool ignore_configuration) const;
- ApkAssetsCookie FindEntryInternal(const PackageGroup& package_group, uint8_t type_idx,
- uint16_t entry_idx, const ResTable_config& desired_config,
- bool /*stop_at_first_match*/,
- bool ignore_configuration, FindEntryResult* out_entry) const;
+ base::expected<FindEntryResult, NullOrIOError> FindEntryInternal(
+ const PackageGroup& package_group, uint8_t type_idx, uint16_t entry_idx,
+ const ResTable_config& desired_config, bool stop_at_first_match,
+ bool ignore_configuration) const;
// Assigns package IDs to all shared library ApkAssets.
// Should be called whenever the ApkAssets are changed.
@@ -372,7 +420,8 @@ class AssetManager2 {
// AssetManager2::GetBag(resid) wraps this function to track which resource ids have already
// been seen while traversing bag parents.
- const ResolvedBag* GetBag(uint32_t resid, std::vector<uint32_t>& child_resids);
+ base::expected<const ResolvedBag*, NullOrIOError> GetBag(
+ uint32_t resid, std::vector<uint32_t>& child_resids) const;
// The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
// have a longer lifetime.
@@ -394,19 +443,20 @@ class AssetManager2 {
// Cached set of bags. These are cached because they can inherit keys from parent bags,
// which involves some calculation.
- std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
+ mutable std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
// Cached set of bag resid stacks for each bag. These are cached because they might be requested
// a number of times for each view during View inspection.
- std::unordered_map<uint32_t, std::vector<uint32_t>> cached_bag_resid_stacks_;
+ mutable std::unordered_map<uint32_t, std::vector<uint32_t>> cached_bag_resid_stacks_;
+
+ // Cached set of resolved resource values.
+ mutable std::unordered_map<uint32_t, SelectedValue> cached_resolved_values_;
// Whether or not to save resource resolution steps
bool resource_resolution_logging_enabled_ = false;
struct Resolution {
-
struct Step {
-
enum class Type {
INITIAL,
BETTER_MATCH,
@@ -455,55 +505,53 @@ class Theme {
public:
~Theme();
- // Applies the style identified by `resid` to this theme. This can be called
- // multiple times with different styles. By default, any theme attributes that
- // are already defined before this call are not overridden. If `force` is set
- // to true, this behavior is changed and all theme attributes from the style at
- // `resid` are applied.
- // Returns false if the style failed to apply.
- bool ApplyStyle(uint32_t resid, bool force = false);
+ // Applies the style identified by `resid` to this theme.
+ //
+ // This can be called multiple times with different styles. By default, any theme attributes that
+ // are already defined before this call are not overridden. If `force` is set to true, this
+ // behavior is changed and all theme attributes from the style at `resid` are applied.
+ //
+ // Returns a null error if the style could not be applied, or an I/O error if reading resource
+ // data failed.
+ base::expected<std::monostate, NullOrIOError> ApplyStyle(uint32_t resid, bool force = false);
- // Sets this Theme to be a copy of `o` if `o` has the same AssetManager as this Theme.
- // If `o` does not have the same AssetManager as this theme, only attributes from ApkAssets loaded
- // into both AssetManagers will be copied to this theme.
- void SetTo(const Theme& o);
+ // Sets this Theme to be a copy of `other` if `other` has the same AssetManager as this Theme.
+ //
+ // If `other` does not have the same AssetManager as this theme, only attributes from ApkAssets
+ // loaded into both AssetManagers will be copied to this theme.
+ //
+ // Returns an I/O error if reading resource data failed.
+ base::expected<std::monostate, IOError> SetTo(const Theme& other);
void Clear();
- void Dump() const;
+ // Retrieves the value of attribute ID `resid` in the theme.
+ //
+ // NOTE: This function does not do reference traversal. If you want to follow references to other
+ // resources to get the "real" value to use, you need to call ResolveReference() after this
+ // function.
+ std::optional<AssetManager2::SelectedValue> GetAttribute(uint32_t resid) const;
- inline const AssetManager2* GetAssetManager() const {
+ // This is like AssetManager2::ResolveReference(), but also takes care of resolving attribute
+ // references to the theme.
+ base::expected<std::monostate, NullOrIOError> ResolveAttributeReference(
+ AssetManager2::SelectedValue& value) const;
+
+ AssetManager2* GetAssetManager() {
return asset_manager_;
}
- inline AssetManager2* GetAssetManager() {
+ const AssetManager2* GetAssetManager() const {
return asset_manager_;
}
// Returns a bit mask of configuration changes that will impact this
// theme (and thus require completely reloading it).
- inline uint32_t GetChangingConfigurations() const {
+ uint32_t GetChangingConfigurations() const {
return type_spec_flags_;
}
- // Retrieve a value in the theme. If the theme defines this value, returns an asset cookie
- // indicating which ApkAssets it came from and populates `out_value` with the value.
- // `out_flags` is populated with a bitmask of the configuration axis with which the resource
- // varies.
- //
- // If the attribute is not found, returns kInvalidCookie.
- //
- // NOTE: This function does not do reference traversal. If you want to follow references to other
- // resources to get the "real" value to use, you need to call ResolveReference() after this
- // function.
- ApkAssetsCookie GetAttribute(uint32_t resid, Res_value* out_value, uint32_t* out_flags) const;
-
- // This is like AssetManager2::ResolveReference(), but also takes
- // care of resolving attribute references to the theme.
- ApkAssetsCookie ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
- ResTable_config* in_out_selected_config = nullptr,
- uint32_t* in_out_type_spec_flags = nullptr,
- uint32_t* out_last_ref = nullptr) const;
+ void Dump() const;
private:
DISALLOW_COPY_AND_ASSIGN(Theme);
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index d71aad29d917..1a69a309d365 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -45,20 +45,28 @@ enum {
// `out_values` must NOT be nullptr.
// `out_indices` may be nullptr.
-bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_resid,
- uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
- size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
+base::expected<std::monostate, IOError> ResolveAttrs(Theme* theme, uint32_t def_style_attr,
+ uint32_t def_style_resid, uint32_t* src_values,
+ size_t src_values_length, uint32_t* attrs,
+ size_t attrs_length, uint32_t* out_values,
+ uint32_t* out_indices);
// `out_values` must NOT be nullptr.
// `out_indices` is NOT optional and must NOT be nullptr.
-void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
- uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
- uint32_t* out_values, uint32_t* out_indices);
+base::expected<std::monostate, IOError> ApplyStyle(Theme* theme, ResXMLParser* xml_parser,
+ uint32_t def_style_attr,
+ uint32_t def_style_resid,
+ const uint32_t* attrs, size_t attrs_length,
+ uint32_t* out_values, uint32_t* out_indices);
// `out_values` must NOT be nullptr.
// `out_indices` may be nullptr.
-bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
- size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
+base::expected<std::monostate, IOError> RetrieveAttributes(AssetManager2* assetmanager,
+ ResXMLParser* xml_parser,
+ uint32_t* attrs,
+ size_t attrs_length,
+ uint32_t* out_values,
+ uint32_t* out_indices);
} // namespace android
diff --git a/libs/androidfw/include/androidfw/Chunk.h b/libs/androidfw/include/androidfw/Chunk.h
index a0f23433c676..f1c43b298e53 100644
--- a/libs/androidfw/include/androidfw/Chunk.h
+++ b/libs/androidfw/include/androidfw/Chunk.h
@@ -36,7 +36,7 @@ namespace android {
// of the chunk.
class Chunk {
public:
- explicit Chunk(const ResChunk_header* chunk) : device_chunk_(chunk) {}
+ explicit Chunk(incfs::verified_map_ptr<ResChunk_header> chunk) : device_chunk_(chunk) {}
// Returns the type of the chunk. Caller need not worry about endianness.
inline int type() const { return dtohs(device_chunk_->type); }
@@ -49,21 +49,18 @@ class Chunk {
inline size_t header_size() const { return dtohs(device_chunk_->headerSize); }
template <typename T, size_t MinSize = sizeof(T)>
- inline const T* header() const {
- if (header_size() >= MinSize) {
- return reinterpret_cast<const T*>(device_chunk_);
- }
- return nullptr;
+ inline incfs::map_ptr<T> header() const {
+ return (header_size() >= MinSize) ? device_chunk_.convert<T>() : nullptr;
}
- inline const void* data_ptr() const {
- return reinterpret_cast<const uint8_t*>(device_chunk_) + header_size();
+ inline incfs::map_ptr<void> data_ptr() const {
+ return device_chunk_.offset(header_size());
}
inline size_t data_size() const { return size() - header_size(); }
private:
- const ResChunk_header* device_chunk_;
+ const incfs::verified_map_ptr<ResChunk_header> device_chunk_;
};
// Provides a Java style iterator over an array of ResChunk_header's.
@@ -84,11 +81,11 @@ class Chunk {
//
class ChunkIterator {
public:
- ChunkIterator(const void* data, size_t len)
- : next_chunk_(reinterpret_cast<const ResChunk_header*>(data)),
+ ChunkIterator(incfs::map_ptr<void> data, size_t len)
+ : next_chunk_(data.convert<ResChunk_header>()),
len_(len),
last_error_(nullptr) {
- CHECK(next_chunk_ != nullptr) << "data can't be nullptr";
+ CHECK((bool) next_chunk_) << "data can't be null";
if (len_ != 0) {
VerifyNextChunk();
}
@@ -113,7 +110,7 @@ class ChunkIterator {
// Returns false if there was an error. For legacy purposes.
bool VerifyNextChunkNonFatal();
- const ResChunk_header* next_chunk_;
+ incfs::map_ptr<ResChunk_header> next_chunk_;
size_t len_;
const char* last_error_;
bool last_error_was_fatal_ = true;
diff --git a/libs/androidfw/include/androidfw/Errors.h b/libs/androidfw/include/androidfw/Errors.h
new file mode 100644
index 000000000000..948162d10480
--- /dev/null
+++ b/libs/androidfw/include/androidfw/Errors.h
@@ -0,0 +1,47 @@
+/*
+ * 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 ANDROIDFW_ERRORS_H_
+#define ANDROIDFW_ERRORS_H_
+
+#include <optional>
+#include <variant>
+
+#include <android-base/result.h>
+
+namespace android {
+
+enum class IOError {
+ // Used when reading a file residing on an IncFs file-system times out.
+ PAGES_MISSING = -1,
+};
+
+// Represents an absent result or an I/O error.
+using NullOrIOError = std::variant<std::nullopt_t, IOError>;
+
+// Checks whether the result holds an unexpected I/O error.
+template <typename T>
+static inline bool IsIOError(const base::expected<T, NullOrIOError> result) {
+ return !result.has_value() && std::holds_alternative<IOError>(result.error());
+}
+
+static inline IOError GetIOError(const NullOrIOError& error) {
+ return std::get<IOError>(error);
+}
+
+} // namespace android
+
+#endif //ANDROIDFW_ERRORS_H_
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index ab0f47f025d2..fdab03ba2de4 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -40,8 +40,8 @@ class IdmapResMap;
class OverlayStringPool : public ResStringPool {
public:
virtual ~OverlayStringPool();
- const char16_t* stringAt(size_t idx, size_t* outLen) const override;
- const char* string8At(size_t idx, size_t* outLen) const override;
+ base::expected<StringPiece16, NullOrIOError> stringAt(size_t idx) const override;
+ base::expected<StringPiece, NullOrIOError> string8At(size_t idx) const override;
size_t size() const override;
explicit OverlayStringPool(const LoadedIdmap* loaded_idmap);
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 89ff9f52125d..17d97a2a2e73 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -23,7 +23,8 @@
#include <unordered_map>
#include <unordered_set>
-#include "android-base/macros.h"
+#include <android-base/macros.h>
+#include <android-base/result.h>
#include "androidfw/ByteBucketArray.h"
#include "androidfw/Chunk.h"
@@ -49,7 +50,7 @@ struct TypeSpec {
// Pointer to the mmapped data where flags are kept.
// Flags denote whether the resource entry is public
// and under which configurations it varies.
- const ResTable_typeSpec* type_spec;
+ incfs::verified_map_ptr<ResTable_typeSpec> type_spec;
// The number of types that follow this struct.
// There is a type for each configuration that entries are defined for.
@@ -57,15 +58,17 @@ struct TypeSpec {
// Trick to easily access a variable number of Type structs
// proceeding this struct, and to ensure their alignment.
- const ResTable_type* types[0];
+ incfs::verified_map_ptr<ResTable_type> types[0];
- inline uint32_t GetFlagsForEntryIndex(uint16_t entry_index) const {
+ base::expected<uint32_t, NullOrIOError> GetFlagsForEntryIndex(uint16_t entry_index) const {
if (entry_index >= dtohl(type_spec->entryCount)) {
- return 0u;
+ return 0U;
}
-
- const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec + 1);
- return flags[entry_index];
+ const auto entry_flags_ptr = ((type_spec + 1).convert<uint32_t>() + entry_index);
+ if (!entry_flags_ptr) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ return entry_flags_ptr.value();
}
};
@@ -161,13 +164,17 @@ class LoadedPackage {
// the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
// Returns a partial resource ID, with the package ID left as 0x00. The caller is responsible
// for patching the correct package ID to the resource ID.
- uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const;
+ base::expected<uint32_t, NullOrIOError> FindEntryByName(const std::u16string& type_name,
+ const std::u16string& entry_name) const;
- static const ResTable_entry* GetEntry(const ResTable_type* type_chunk, uint16_t entry_index);
+ static base::expected<incfs::map_ptr<ResTable_entry>, NullOrIOError> GetEntry(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index);
- static uint32_t GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index);
+ static base::expected<uint32_t, NullOrIOError> GetEntryOffset(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index);
- static const ResTable_entry* GetEntryFromOffset(const ResTable_type* type_chunk, uint32_t offset);
+ static base::expected<incfs::map_ptr<ResTable_entry>, NullOrIOError> GetEntryFromOffset(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint32_t offset);
// Returns the string pool where type names are stored.
inline const ResStringPool* GetTypeStringPool() const {
@@ -220,7 +227,8 @@ class LoadedPackage {
// Populates a set of ResTable_config structs, possibly excluding configurations defined for
// the mipmap type.
- void CollectConfigurations(bool exclude_mipmap, std::set<ResTable_config>* out_configs) const;
+ base::expected<std::monostate, IOError> CollectConfigurations(
+ bool exclude_mipmap, std::set<ResTable_config>* out_configs) const;
// Populates a set of strings representing locales.
// If `canonicalize` is set to true, each locale is transformed into its canonical format
@@ -300,7 +308,8 @@ class LoadedArsc {
// If `load_as_shared_library` is set to true, the application package (0x7f) is treated
// as a shared library (0x00). When loaded into an AssetManager, the package will be assigned an
// ID.
- static std::unique_ptr<const LoadedArsc> Load(const StringPiece& data,
+ static std::unique_ptr<const LoadedArsc> Load(incfs::map_ptr<void> data,
+ size_t length,
const LoadedIdmap* loaded_idmap = nullptr,
package_property_t property_flags = 0U);
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 04ba78b6705d..fb5f86473189 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -20,7 +20,10 @@
#ifndef _LIBS_UTILS_RESOURCE_TYPES_H
#define _LIBS_UTILS_RESOURCE_TYPES_H
+#include <android-base/expected.h>
+
#include <androidfw/Asset.h>
+#include <androidfw/Errors.h>
#include <androidfw/LocaleData.h>
#include <androidfw/StringPiece.h>
#include <utils/Errors.h>
@@ -497,7 +500,7 @@ public:
virtual ~ResStringPool();
void setToEmpty();
- status_t setTo(const void* data, size_t size, bool copyData=false);
+ status_t setTo(incfs::map_ptr<void> data, size_t size, bool copyData=false);
status_t getError() const;
@@ -505,48 +508,49 @@ public:
// Return string entry as UTF16; if the pool is UTF8, the string will
// be converted before returning.
- inline const char16_t* stringAt(const ResStringPool_ref& ref, size_t* outLen) const {
- return stringAt(ref.index, outLen);
+ inline base::expected<StringPiece16, NullOrIOError> stringAt(
+ const ResStringPool_ref& ref) const {
+ return stringAt(ref.index);
}
- virtual const char16_t* stringAt(size_t idx, size_t* outLen) const;
+ virtual base::expected<StringPiece16, NullOrIOError> stringAt(size_t idx) const;
// Note: returns null if the string pool is not UTF8.
- virtual const char* string8At(size_t idx, size_t* outLen) const;
+ virtual base::expected<StringPiece, NullOrIOError> string8At(size_t idx) const;
// Return string whether the pool is UTF8 or UTF16. Does not allow you
// to distinguish null.
- const String8 string8ObjectAt(size_t idx) const;
+ base::expected<String8, IOError> string8ObjectAt(size_t idx) const;
- const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const;
- const ResStringPool_span* styleAt(size_t idx) const;
+ base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> styleAt(
+ const ResStringPool_ref& ref) const;
+ base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> styleAt(size_t idx) const;
- ssize_t indexOfString(const char16_t* str, size_t strLen) const;
+ base::expected<size_t, NullOrIOError> indexOfString(const char16_t* str, size_t strLen) const;
virtual size_t size() const;
size_t styleCount() const;
size_t bytes() const;
- const void* data() const;
-
+ incfs::map_ptr<void> data() const;
bool isSorted() const;
bool isUTF8() const;
private:
- status_t mError;
- void* mOwnedData;
- const ResStringPool_header* mHeader;
- size_t mSize;
- mutable Mutex mDecodeLock;
- const uint32_t* mEntries;
- const uint32_t* mEntryStyles;
- const void* mStrings;
- char16_t mutable** mCache;
- uint32_t mStringPoolSize; // number of uint16_t
- const uint32_t* mStyles;
- uint32_t mStylePoolSize; // number of uint32_t
-
- const char* stringDecodeAt(size_t idx, const uint8_t* str, const size_t encLen,
- size_t* outLen) const;
+ status_t mError;
+ void* mOwnedData;
+ incfs::verified_map_ptr<ResStringPool_header> mHeader;
+ size_t mSize;
+ mutable Mutex mDecodeLock;
+ incfs::map_ptr<uint32_t> mEntries;
+ incfs::map_ptr<uint32_t> mEntryStyles;
+ incfs::map_ptr<void> mStrings;
+ char16_t mutable** mCache;
+ uint32_t mStringPoolSize; // number of uint16_t
+ incfs::map_ptr<uint32_t> mStyles;
+ uint32_t mStylePoolSize; // number of uint32_t
+
+ base::expected<StringPiece, NullOrIOError> stringDecodeAt(
+ size_t idx, incfs::map_ptr<uint8_t> str, size_t encLen) const;
};
/**
@@ -558,8 +562,8 @@ public:
StringPoolRef() = default;
StringPoolRef(const ResStringPool* pool, uint32_t index);
- const char* string8(size_t* outLen) const;
- const char16_t* string16(size_t* outLen) const;
+ base::expected<StringPiece, NullOrIOError> string8() const;
+ base::expected<StringPiece16, NullOrIOError> string16() const;
private:
const ResStringPool* mPool = nullptr;
@@ -1797,6 +1801,16 @@ private:
bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue);
+template<typename TChar, typename E>
+static const TChar* UnpackOptionalString(base::expected<BasicStringPiece<TChar>, E>&& result,
+ size_t* outLen) {
+ if (result.has_value()) {
+ *outLen = result->size();
+ return result->data();
+ }
+ return NULL;
+}
+
/**
* Convenience class for accessing data in a ResTable resource.
*/
diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h
index e649940cdde1..bd1c44033b88 100644
--- a/libs/androidfw/include/androidfw/ResourceUtils.h
+++ b/libs/androidfw/include/androidfw/ResourceUtils.h
@@ -30,13 +30,12 @@ bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, Strin
// Convert a type_string_ref, entry_string_ref, and package to AssetManager2::ResourceName.
// Useful for getting resource name without re-running AssetManager2::FindEntry searches.
-bool ToResourceName(const StringPoolRef& type_string_ref,
- const StringPoolRef& entry_string_ref,
- const StringPiece& package_name,
- AssetManager2::ResourceName* out_name);
+base::expected<AssetManager2::ResourceName, NullOrIOError> ToResourceName(
+ const StringPoolRef& type_string_ref, const StringPoolRef& entry_string_ref,
+ const StringPiece& package_name);
// Formats a ResourceName to "package:type/entry_name".
-std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name);
+std::string ToFormattedResourceString(const AssetManager2::ResourceName& resource_name);
inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
return (resid & 0x00ffffffu) | (static_cast<uint32_t>(package_id) << 24);
diff --git a/libs/androidfw/include/androidfw/StreamingZipInflater.h b/libs/androidfw/include/androidfw/StreamingZipInflater.h
index 3ace5d5a83cf..472b794b911c 100644
--- a/libs/androidfw/include/androidfw/StreamingZipInflater.h
+++ b/libs/androidfw/include/androidfw/StreamingZipInflater.h
@@ -19,6 +19,8 @@
#include <unistd.h>
#include <inttypes.h>
+
+#include <util/map_ptr.h>
#include <zlib.h>
#include <utils/Compat.h>
@@ -34,7 +36,7 @@ public:
StreamingZipInflater(int fd, off64_t compDataStart, size_t uncompSize, size_t compSize);
// Flavor that gets the compressed data from an in-memory buffer
- StreamingZipInflater(class FileMap* dataMap, size_t uncompSize);
+ StreamingZipInflater(const incfs::IncFsFileMap* dataMap, size_t uncompSize);
~StreamingZipInflater();
@@ -54,7 +56,7 @@ private:
// where to find the uncompressed data
int mFd;
off64_t mInFileStart; // where the compressed data lives in the file
- class FileMap* mDataMap;
+ const incfs::IncFsFileMap* mDataMap;
z_stream mInflateState;
bool mStreamNeedsInit;
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
index 9a3646b49db8..aceeeccccb61 100644
--- a/libs/androidfw/include/androidfw/Util.h
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -22,7 +22,8 @@
#include <sstream>
#include <vector>
-#include "android-base/macros.h"
+#include <android-base/macros.h>
+#include <util/map_ptr.h>
#include "androidfw/StringPiece.h"
@@ -126,6 +127,11 @@ std::string Utf16ToUtf8(const StringPiece16& utf16);
std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
+template <typename T>
+bool IsFourByteAligned(const incfs::map_ptr<T>& data) {
+ return ((size_t)data.unsafe_ptr() & 0x3U) == 0;
+}
+
} // namespace util
} // namespace android
diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h
index c221e3b7aeae..10f6d0655bf4 100644
--- a/libs/androidfw/include/androidfw/ZipFileRO.h
+++ b/libs/androidfw/include/androidfw/ZipFileRO.h
@@ -30,17 +30,20 @@
#ifndef __LIBS_ZIPFILERO_H
#define __LIBS_ZIPFILERO_H
-#include <utils/Compat.h>
-#include <utils/Errors.h>
-#include <utils/FileMap.h>
-#include <utils/threads.h>
-
+#include <optional>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
+#include <util/map_ptr.h>
+
+#include <utils/Compat.h>
+#include <utils/Errors.h>
+#include <utils/FileMap.h>
+#include <utils/threads.h>
+
struct ZipArchive;
typedef ZipArchive* ZipArchiveHandle;
@@ -136,14 +139,26 @@ public:
uint32_t* pCrc32) const;
/*
- * Create a new FileMap object that maps a subset of the archive. For
+ * Create a new FileMap object that maps a subset of the archive. For
* an uncompressed entry this effectively provides a pointer to the
* actual data, for a compressed entry this provides the input buffer
* for inflate().
+ *
+ * Use this function if the archive can never reside on IncFs.
*/
FileMap* createEntryFileMap(ZipEntryRO entry) const;
/*
+ * Create a new incfs::IncFsFileMap object that maps a subset of the archive. For
+ * an uncompressed entry this effectively provides a pointer to the
+ * actual data, for a compressed entry this provides the input buffer
+ * for inflate().
+ *
+ * Use this function if the archive can potentially reside on IncFs.
+ */
+ std::optional<incfs::IncFsFileMap> createEntryIncFsFileMap(ZipEntryRO entry) const;
+
+ /*
* Uncompress the data into a buffer. Depending on the compression
* format, this is either an "inflate" operation or a memcpy.
*
diff --git a/libs/androidfw/include/androidfw/ZipUtils.h b/libs/androidfw/include/androidfw/ZipUtils.h
index 4d35e992cc89..dbfec34fda89 100644
--- a/libs/androidfw/include/androidfw/ZipUtils.h
+++ b/libs/androidfw/include/androidfw/ZipUtils.h
@@ -25,6 +25,8 @@
#include <stdio.h>
#include <time.h>
+#include "util/map_ptr.h"
+
namespace android {
/*
@@ -40,8 +42,8 @@ public:
long compressedLen);
static bool inflateToBuffer(int fd, void* buf, long uncompressedLen,
long compressedLen);
- static bool inflateToBuffer(const void *in, void* buf, long uncompressedLen,
- long compressedLen);
+ static bool inflateToBuffer(incfs::map_ptr<void> in, void* buf,
+ long uncompressedLen, long compressedLen);
/*
* Someday we might want to make this generic and handle bzip2 ".bz2"
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index 437e14772964..c7ae618991b9 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -139,9 +139,13 @@ static void BM_AssetManagerGetBag(benchmark::State& state) {
assets.SetApkAssets({apk.get()});
while (state.KeepRunning()) {
- const ResolvedBag* bag = assets.GetBag(app::R::style::StyleTwo);
- const auto bag_end = end(bag);
- for (auto iter = begin(bag); iter != bag_end; ++iter) {
+ auto bag = assets.GetBag(app::R::style::StyleTwo);
+ if (!bag.has_value()) {
+ state.SkipWithError("Failed to load get bag");
+ return;
+ }
+ const auto bag_end = end(*bag);
+ for (auto iter = begin(*bag); iter != bag_end; ++iter) {
uint32_t key = iter->key;
Res_value value = iter->value;
benchmark::DoNotOptimize(key);
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 8c255d16fe1f..3638ce1f92d7 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -108,24 +108,18 @@ TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
assetmanager.SetConfiguration(desired_config);
assetmanager.SetApkAssets({basic_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
// Came from our ApkAssets.
- EXPECT_EQ(0, cookie);
+ EXPECT_EQ(0, value->cookie);
// It is the default config.
- EXPECT_EQ(0, selected_config.language[0]);
- EXPECT_EQ(0, selected_config.language[1]);
+ EXPECT_EQ(0, value->config.language[0]);
+ EXPECT_EQ(0, value->config.language[1]);
// It is a string.
- EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
}
TEST_F(AssetManager2Test, FindsResourceFromMultipleApkAssets) {
@@ -138,24 +132,18 @@ TEST_F(AssetManager2Test, FindsResourceFromMultipleApkAssets) {
assetmanager.SetConfiguration(desired_config);
assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
// Came from our de_fr ApkAssets.
- EXPECT_EQ(1, cookie);
+ EXPECT_EQ(1, value->cookie);
// The configuration is German.
- EXPECT_EQ('d', selected_config.language[0]);
- EXPECT_EQ('e', selected_config.language[1]);
+ EXPECT_EQ('d', value->config.language[0]);
+ EXPECT_EQ('e', value->config.language[1]);
// It is a string.
- EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
}
TEST_F(AssetManager2Test, FindsResourceFromSharedLibrary) {
@@ -166,44 +154,35 @@ TEST_F(AssetManager2Test, FindsResourceFromSharedLibrary) {
assetmanager.SetApkAssets(
{lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(libclient::R::string::foo_one, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(libclient::R::string::foo_one);
+ ASSERT_TRUE(value.has_value());
// Reference comes from libclient.
- EXPECT_EQ(2, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
+ EXPECT_EQ(2, value->cookie);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
// Lookup the reference.
- cookie = assetmanager.GetResource(value.data, false /* may_be_bag */, 0 /* density_override*/,
- &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(1, cookie);
- EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+ value = assetmanager.GetResource(value->data);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(1, value->cookie);
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
EXPECT_EQ(std::string("Foo from lib_one"),
- GetStringFromPool(assetmanager.GetStringPoolForCookie(cookie), value.data));
+ GetStringFromPool(assetmanager.GetStringPoolForCookie(value->cookie), value->data));
- cookie = assetmanager.GetResource(libclient::R::string::foo_two, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ value = assetmanager.GetResource(libclient::R::string::foo_two);
+ ASSERT_TRUE(value.has_value());
// Reference comes from libclient.
- EXPECT_EQ(2, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
+ EXPECT_EQ(2, value->cookie);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
// Lookup the reference.
- cookie = assetmanager.GetResource(value.data, false /* may_be_bag */, 0 /* density_override*/,
- &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(0, cookie);
- EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+ value = assetmanager.GetResource(value->data);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(0, value->cookie);
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
EXPECT_EQ(std::string("Foo from lib_two"),
- GetStringFromPool(assetmanager.GetStringPoolForCookie(cookie), value.data));
+ GetStringFromPool(assetmanager.GetStringPoolForCookie(value->cookie), value->data));
}
TEST_F(AssetManager2Test, FindsResourceFromAppLoadedAsSharedLibrary) {
@@ -211,16 +190,10 @@ TEST_F(AssetManager2Test, FindsResourceFromAppLoadedAsSharedLibrary) {
assetmanager.SetApkAssets({appaslib_assets_.get()});
// The appaslib package will have been assigned the package ID 0x02.
-
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- ApkAssetsCookie cookie = assetmanager.GetResource(
- fix_package_id(appaslib::R::integer::number1, 0x02), false /*may_be_bag*/,
- 0u /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(fix_package_id(appaslib::R::array::integerArray1, 0x02), value.data);
+ auto value = assetmanager.GetResource(fix_package_id(appaslib::R::integer::number1, 0x02));
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(fix_package_id(appaslib::R::array::integerArray1, 0x02), value->data);
}
TEST_F(AssetManager2Test, AssignsOverlayPackageIdLast) {
@@ -238,40 +211,40 @@ TEST_F(AssetManager2Test, AssignsOverlayPackageIdLast) {
return assetmanager.GetAssignedPackageId(apkAssets->GetLoadedArsc()->GetPackages()[0].get());
};
- ASSERT_EQ(get_first_package_id(overlayable_assets_.get()), 0x7f);
- ASSERT_EQ(get_first_package_id(overlay_assets_.get()), 0x03);
- ASSERT_EQ(get_first_package_id(lib_one_assets_.get()), 0x02);
+ ASSERT_EQ(0x7f, get_first_package_id(overlayable_assets_.get()));
+ ASSERT_EQ(0x03, get_first_package_id(overlay_assets_.get()));
+ ASSERT_EQ(0x02, get_first_package_id(lib_one_assets_.get()));
}
TEST_F(AssetManager2Test, GetSharedLibraryResourceName) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({lib_one_assets_.get()});
- AssetManager2::ResourceName name;
- ASSERT_TRUE(assetmanager.GetResourceName(lib_one::R::string::foo, &name));
- std::string formatted_name = ToFormattedResourceString(&name);
- ASSERT_EQ(formatted_name, "com.android.lib_one:string/foo");
+ auto name = assetmanager.GetResourceName(lib_one::R::string::foo);
+ ASSERT_TRUE(name.has_value());
+ ASSERT_EQ("com.android.lib_one:string/foo", ToFormattedResourceString(*name));
}
TEST_F(AssetManager2Test, FindsBagResourceFromSingleApkAssets) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
- const ResolvedBag* bag = assetmanager.GetBag(basic::R::array::integerArray1);
- ASSERT_NE(nullptr, bag);
- ASSERT_EQ(3u, bag->entry_count);
+ auto bag = assetmanager.GetBag(basic::R::array::integerArray1);
+ ASSERT_TRUE(bag.has_value());
+
+ ASSERT_EQ(3u, (*bag)->entry_count);
- EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[0].value.dataType);
- EXPECT_EQ(1u, bag->entries[0].value.data);
- EXPECT_EQ(0, bag->entries[0].cookie);
+ EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), (*bag)->entries[0].value.dataType);
+ EXPECT_EQ(1u, (*bag)->entries[0].value.data);
+ EXPECT_EQ(0, (*bag)->entries[0].cookie);
- EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[1].value.dataType);
- EXPECT_EQ(2u, bag->entries[1].value.data);
- EXPECT_EQ(0, bag->entries[1].cookie);
+ EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), (*bag)->entries[1].value.dataType);
+ EXPECT_EQ(2u, (*bag)->entries[1].value.data);
+ EXPECT_EQ(0, (*bag)->entries[1].cookie);
- EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[2].value.dataType);
- EXPECT_EQ(3u, bag->entries[2].value.data);
- EXPECT_EQ(0, bag->entries[2].cookie);
+ EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), (*bag)->entries[2].value.dataType);
+ EXPECT_EQ(3u, (*bag)->entries[2].value.data);
+ EXPECT_EQ(0, (*bag)->entries[2].cookie);
}
TEST_F(AssetManager2Test, FindsBagResourceFromMultipleApkAssets) {}
@@ -284,15 +257,16 @@ TEST_F(AssetManager2Test, FindsBagResourceFromSharedLibrary) {
assetmanager.SetApkAssets(
{lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
- const ResolvedBag* bag = assetmanager.GetBag(fix_package_id(lib_one::R::style::Theme, 0x03));
- ASSERT_NE(nullptr, bag);
- ASSERT_GE(bag->entry_count, 2u);
+ auto bag = assetmanager.GetBag(fix_package_id(lib_one::R::style::Theme, 0x03));
+ ASSERT_TRUE(bag.has_value());
+
+ ASSERT_GE((*bag)->entry_count, 2u);
// First two attributes come from lib_one.
- EXPECT_EQ(1, bag->entries[0].cookie);
- EXPECT_EQ(0x03, get_package_id(bag->entries[0].key));
- EXPECT_EQ(1, bag->entries[1].cookie);
- EXPECT_EQ(0x03, get_package_id(bag->entries[1].key));
+ EXPECT_EQ(1, (*bag)->entries[0].cookie);
+ EXPECT_EQ(0x03, get_package_id((*bag)->entries[0].key));
+ EXPECT_EQ(1, (*bag)->entries[1].cookie);
+ EXPECT_EQ(0x03, get_package_id((*bag)->entries[1].key));
}
TEST_F(AssetManager2Test, FindsBagResourceFromMultipleSharedLibraries) {
@@ -303,17 +277,17 @@ TEST_F(AssetManager2Test, FindsBagResourceFromMultipleSharedLibraries) {
assetmanager.SetApkAssets(
{lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
- const ResolvedBag* bag = assetmanager.GetBag(libclient::R::style::ThemeMultiLib);
- ASSERT_NE(nullptr, bag);
- ASSERT_EQ(bag->entry_count, 2u);
+ auto bag = assetmanager.GetBag(libclient::R::style::ThemeMultiLib);
+ ASSERT_TRUE(bag.has_value());
+ ASSERT_EQ((*bag)->entry_count, 2u);
// First attribute comes from lib_two.
- EXPECT_EQ(2, bag->entries[0].cookie);
- EXPECT_EQ(0x02, get_package_id(bag->entries[0].key));
+ EXPECT_EQ(2, (*bag)->entries[0].cookie);
+ EXPECT_EQ(0x02, get_package_id((*bag)->entries[0].key));
// The next two attributes come from lib_one.
- EXPECT_EQ(2, bag->entries[1].cookie);
- EXPECT_EQ(0x03, get_package_id(bag->entries[1].key));
+ EXPECT_EQ(2, (*bag)->entries[1].cookie);
+ EXPECT_EQ(0x03, get_package_id((*bag)->entries[1].key));
}
TEST_F(AssetManager2Test, FindsStyleResourceWithParentFromSharedLibrary) {
@@ -324,79 +298,79 @@ TEST_F(AssetManager2Test, FindsStyleResourceWithParentFromSharedLibrary) {
assetmanager.SetApkAssets(
{lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
- const ResolvedBag* bag = assetmanager.GetBag(libclient::R::style::Theme);
- ASSERT_NE(nullptr, bag);
- ASSERT_GE(bag->entry_count, 2u);
+ auto bag = assetmanager.GetBag(libclient::R::style::Theme);
+ ASSERT_TRUE(bag.has_value());
+ ASSERT_GE((*bag)->entry_count, 2u);
// First two attributes come from lib_one.
- EXPECT_EQ(1, bag->entries[0].cookie);
- EXPECT_EQ(0x03, get_package_id(bag->entries[0].key));
- EXPECT_EQ(1, bag->entries[1].cookie);
- EXPECT_EQ(0x03, get_package_id(bag->entries[1].key));
+ EXPECT_EQ(1, (*bag)->entries[0].cookie);
+ EXPECT_EQ(0x03, get_package_id((*bag)->entries[0].key));
+ EXPECT_EQ(1, (*bag)->entries[1].cookie);
+ EXPECT_EQ(0x03, get_package_id((*bag)->entries[1].key));
}
TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({style_assets_.get()});
- const ResolvedBag* bag_one = assetmanager.GetBag(app::R::style::StyleOne);
- ASSERT_NE(nullptr, bag_one);
- ASSERT_EQ(2u, bag_one->entry_count);
+ auto bag_one = assetmanager.GetBag(app::R::style::StyleOne);
+ ASSERT_TRUE(bag_one.has_value());
+ ASSERT_EQ(2u, (*bag_one)->entry_count);
- EXPECT_EQ(app::R::attr::attr_one, bag_one->entries[0].key);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_one->entries[0].value.dataType);
- EXPECT_EQ(1u, bag_one->entries[0].value.data);
- EXPECT_EQ(0, bag_one->entries[0].cookie);
+ EXPECT_EQ(app::R::attr::attr_one, (*bag_one)->entries[0].key);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, (*bag_one)->entries[0].value.dataType);
+ EXPECT_EQ(1u, (*bag_one)->entries[0].value.data);
+ EXPECT_EQ(0, (*bag_one)->entries[0].cookie);
- EXPECT_EQ(app::R::attr::attr_two, bag_one->entries[1].key);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_one->entries[1].value.dataType);
- EXPECT_EQ(2u, bag_one->entries[1].value.data);
- EXPECT_EQ(0, bag_one->entries[1].cookie);
+ EXPECT_EQ(app::R::attr::attr_two, (*bag_one)->entries[1].key);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, (*bag_one)->entries[1].value.dataType);
+ EXPECT_EQ(2u, (*bag_one)->entries[1].value.data);
+ EXPECT_EQ(0, (*bag_one)->entries[1].cookie);
- const ResolvedBag* bag_two = assetmanager.GetBag(app::R::style::StyleTwo);
- ASSERT_NE(nullptr, bag_two);
- ASSERT_EQ(6u, bag_two->entry_count);
+ auto bag_two = assetmanager.GetBag(app::R::style::StyleTwo);
+ ASSERT_TRUE(bag_two.has_value());
+ ASSERT_EQ(6u, (*bag_two)->entry_count);
// attr_one is inherited from StyleOne.
- EXPECT_EQ(app::R::attr::attr_one, bag_two->entries[0].key);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[0].value.dataType);
- EXPECT_EQ(1u, bag_two->entries[0].value.data);
- EXPECT_EQ(0, bag_two->entries[0].cookie);
- EXPECT_EQ(app::R::style::StyleOne, bag_two->entries[0].style);
+ EXPECT_EQ(app::R::attr::attr_one, (*bag_two)->entries[0].key);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, (*bag_two)->entries[0].value.dataType);
+ EXPECT_EQ(1u, (*bag_two)->entries[0].value.data);
+ EXPECT_EQ(0, (*bag_two)->entries[0].cookie);
+ EXPECT_EQ(app::R::style::StyleOne, (*bag_two)->entries[0].style);
// attr_two should be overridden from StyleOne by StyleTwo.
- EXPECT_EQ(app::R::attr::attr_two, bag_two->entries[1].key);
- EXPECT_EQ(Res_value::TYPE_STRING, bag_two->entries[1].value.dataType);
- EXPECT_EQ(0, bag_two->entries[1].cookie);
- EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[1].style);
+ EXPECT_EQ(app::R::attr::attr_two, (*bag_two)->entries[1].key);
+ EXPECT_EQ(Res_value::TYPE_STRING, (*bag_two)->entries[1].value.dataType);
+ EXPECT_EQ(0, (*bag_two)->entries[1].cookie);
+ EXPECT_EQ(app::R::style::StyleTwo, (*bag_two)->entries[1].style);
EXPECT_EQ(std::string("string"), GetStringFromPool(assetmanager.GetStringPoolForCookie(0),
- bag_two->entries[1].value.data));
+ (*bag_two)->entries[1].value.data));
// The rest are new attributes.
- EXPECT_EQ(app::R::attr::attr_three, bag_two->entries[2].key);
- EXPECT_EQ(Res_value::TYPE_ATTRIBUTE, bag_two->entries[2].value.dataType);
- EXPECT_EQ(app::R::attr::attr_indirect, bag_two->entries[2].value.data);
- EXPECT_EQ(0, bag_two->entries[2].cookie);
- EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[2].style);
-
- EXPECT_EQ(app::R::attr::attr_five, bag_two->entries[3].key);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, bag_two->entries[3].value.dataType);
- EXPECT_EQ(app::R::string::string_one, bag_two->entries[3].value.data);
- EXPECT_EQ(0, bag_two->entries[3].cookie);
- EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[3].style);
-
- EXPECT_EQ(app::R::attr::attr_indirect, bag_two->entries[4].key);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[4].value.dataType);
- EXPECT_EQ(3u, bag_two->entries[4].value.data);
- EXPECT_EQ(0, bag_two->entries[4].cookie);
- EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[4].style);
-
- EXPECT_EQ(app::R::attr::attr_empty, bag_two->entries[5].key);
- EXPECT_EQ(Res_value::TYPE_NULL, bag_two->entries[5].value.dataType);
- EXPECT_EQ(Res_value::DATA_NULL_EMPTY, bag_two->entries[5].value.data);
- EXPECT_EQ(0, bag_two->entries[5].cookie);
- EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[5].style);
+ EXPECT_EQ(app::R::attr::attr_three, (*bag_two)->entries[2].key);
+ EXPECT_EQ(Res_value::TYPE_ATTRIBUTE, (*bag_two)->entries[2].value.dataType);
+ EXPECT_EQ(app::R::attr::attr_indirect, (*bag_two)->entries[2].value.data);
+ EXPECT_EQ(0, (*bag_two)->entries[2].cookie);
+ EXPECT_EQ(app::R::style::StyleTwo, (*bag_two)->entries[2].style);
+
+ EXPECT_EQ(app::R::attr::attr_five, (*bag_two)->entries[3].key);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, (*bag_two)->entries[3].value.dataType);
+ EXPECT_EQ(app::R::string::string_one, (*bag_two)->entries[3].value.data);
+ EXPECT_EQ(0, (*bag_two)->entries[3].cookie);
+ EXPECT_EQ(app::R::style::StyleTwo, (*bag_two)->entries[3].style);
+
+ EXPECT_EQ(app::R::attr::attr_indirect, (*bag_two)->entries[4].key);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, (*bag_two)->entries[4].value.dataType);
+ EXPECT_EQ(3u, (*bag_two)->entries[4].value.data);
+ EXPECT_EQ(0, (*bag_two)->entries[4].cookie);
+ EXPECT_EQ(app::R::style::StyleTwo, (*bag_two)->entries[4].style);
+
+ EXPECT_EQ(app::R::attr::attr_empty, (*bag_two)->entries[5].key);
+ EXPECT_EQ(Res_value::TYPE_NULL, (*bag_two)->entries[5].value.dataType);
+ EXPECT_EQ(Res_value::DATA_NULL_EMPTY, (*bag_two)->entries[5].value.data);
+ EXPECT_EQ(0, (*bag_two)->entries[5].cookie);
+ EXPECT_EQ(app::R::style::StyleTwo, (*bag_two)->entries[5].style);
}
TEST_F(AssetManager2Test, MergeStylesCircularDependency) {
@@ -405,55 +379,41 @@ TEST_F(AssetManager2Test, MergeStylesCircularDependency) {
// GetBag should stop traversing the parents of styles when a circular
// dependency is detected
- const ResolvedBag* bag_one = assetmanager.GetBag(app::R::style::StyleFour);
- ASSERT_NE(nullptr, bag_one);
- ASSERT_EQ(3u, bag_one->entry_count);
+ auto bag = assetmanager.GetBag(app::R::style::StyleFour);
+ ASSERT_TRUE(bag.has_value());
+ ASSERT_EQ(3u, (*bag)->entry_count);
}
TEST_F(AssetManager2Test, ResolveReferenceToResource) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::integer::ref1, false /*may_be_bag*/,
- 0u /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
-
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(basic::R::integer::ref2, value.data);
-
- uint32_t last_ref = 0u;
- cookie = assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_ref);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(12000u, value.data);
- EXPECT_EQ(basic::R::integer::ref2, last_ref);
+ auto value = assetmanager.GetResource(basic::R::integer::ref1);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(basic::R::integer::ref2, value->data);
+
+ auto result = assetmanager.ResolveReference(*value);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(12000u, value->data);
+ EXPECT_EQ(basic::R::integer::ref2, value->resid);
}
TEST_F(AssetManager2Test, ResolveReferenceToBag) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::integer::number2, true /*may_be_bag*/,
- 0u /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
-
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(basic::R::array::integerArray1, value.data);
-
- uint32_t last_ref = 0u;
- cookie = assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_ref);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(basic::R::array::integerArray1, value.data);
- EXPECT_EQ(basic::R::array::integerArray1, last_ref);
+ auto value = assetmanager.GetResource(basic::R::integer::number2, true /*may_be_bag*/);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(basic::R::array::integerArray1, value->data);
+
+ auto result = assetmanager.ResolveReference(*value);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(basic::R::array::integerArray1, value->data);
+ EXPECT_EQ(basic::R::array::integerArray1, value->resid);
}
TEST_F(AssetManager2Test, ResolveDeepIdReference) {
@@ -461,31 +421,25 @@ TEST_F(AssetManager2Test, ResolveDeepIdReference) {
assetmanager.SetApkAssets({basic_assets_.get()});
// Set up the resource ids
- const uint32_t high_ref = assetmanager
- .GetResourceId("@id/high_ref", "values", "com.android.basic");
- ASSERT_NE(high_ref, 0u);
- const uint32_t middle_ref = assetmanager
- .GetResourceId("@id/middle_ref", "values", "com.android.basic");
- ASSERT_NE(middle_ref, 0u);
- const uint32_t low_ref = assetmanager
- .GetResourceId("@id/low_ref", "values", "com.android.basic");
- ASSERT_NE(low_ref, 0u);
+ auto high_ref = assetmanager.GetResourceId("@id/high_ref", "values", "com.android.basic");
+ ASSERT_TRUE(high_ref.has_value());
+
+ auto middle_ref = assetmanager.GetResourceId("@id/middle_ref", "values", "com.android.basic");
+ ASSERT_TRUE(middle_ref.has_value());
+
+ auto low_ref = assetmanager.GetResourceId("@id/low_ref", "values", "com.android.basic");
+ ASSERT_TRUE(low_ref.has_value());
// Retrieve the most shallow resource
- Res_value value;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = assetmanager.GetResource(high_ref, false /*may_be_bag*/,
- 0 /*density_override*/,
- &value, &config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(middle_ref, value.data);
+ auto value = assetmanager.GetResource(*high_ref);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(*middle_ref, value->data);;
// Check that resolving the reference resolves to the deepest id
- uint32_t last_ref = high_ref;
- assetmanager.ResolveReference(cookie, &value, &config, &flags, &last_ref);
- EXPECT_EQ(last_ref, low_ref);
+ auto result = assetmanager.ResolveReference(*value);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(*low_ref, value->resid);
}
TEST_F(AssetManager2Test, KeepLastReferenceIdUnmodifiedIfNoReferenceIsResolved) {
@@ -495,16 +449,16 @@ TEST_F(AssetManager2Test, KeepLastReferenceIdUnmodifiedIfNoReferenceIsResolved)
ResTable_config selected_config;
memset(&selected_config, 0, sizeof(selected_config));
- uint32_t flags = 0u;
+ // Create some kind of value that is NOT a reference.
+ AssetManager2::SelectedValue value{};
+ value.cookie = 1;
+ value.type = Res_value::TYPE_STRING;
+ value.resid = basic::R::string::test1;
- // Create some kind of Res_value that is NOT a reference.
- Res_value value;
- value.dataType = Res_value::TYPE_STRING;
- value.data = 0;
-
- uint32_t last_ref = basic::R::string::test1;
- EXPECT_EQ(1, assetmanager.ResolveReference(1, &value, &selected_config, &flags, &last_ref));
- EXPECT_EQ(basic::R::string::test1, last_ref);
+ auto result = assetmanager.ResolveReference(value);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(1, value.cookie);
+ EXPECT_EQ(basic::R::string::test1, value.resid);
}
static bool IsConfigurationPresent(const std::set<ResTable_config>& configurations,
@@ -516,43 +470,45 @@ TEST_F(AssetManager2Test, GetResourceConfigurations) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({system_assets_.get(), basic_de_fr_assets_.get()});
- std::set<ResTable_config> configurations = assetmanager.GetResourceConfigurations();
+ auto configurations = assetmanager.GetResourceConfigurations();
+ ASSERT_TRUE(configurations.has_value());
// We expect the locale sv from the system assets, and de and fr from basic_de_fr assets.
// And one extra for the default configuration.
- EXPECT_EQ(4u, configurations.size());
+ EXPECT_EQ(4u, configurations->size());
ResTable_config expected_config;
memset(&expected_config, 0, sizeof(expected_config));
expected_config.language[0] = 's';
expected_config.language[1] = 'v';
- EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_TRUE(IsConfigurationPresent(*configurations, expected_config));
expected_config.language[0] = 'd';
expected_config.language[1] = 'e';
- EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_TRUE(IsConfigurationPresent(*configurations, expected_config));
expected_config.language[0] = 'f';
expected_config.language[1] = 'r';
- EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_TRUE(IsConfigurationPresent(*configurations, expected_config));
// Take out the system assets.
configurations = assetmanager.GetResourceConfigurations(true /* exclude_system */);
+ ASSERT_TRUE(configurations.has_value());
// We expect de and fr from basic_de_fr assets.
- EXPECT_EQ(2u, configurations.size());
+ EXPECT_EQ(2u, configurations->size());
expected_config.language[0] = 's';
expected_config.language[1] = 'v';
- EXPECT_FALSE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_FALSE(IsConfigurationPresent(*configurations, expected_config));
expected_config.language[0] = 'd';
expected_config.language[1] = 'e';
- EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_TRUE(IsConfigurationPresent(*configurations, expected_config));
expected_config.language[0] = 'f';
expected_config.language[1] = 'r';
- EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_TRUE(IsConfigurationPresent(*configurations, expected_config));
}
TEST_F(AssetManager2Test, GetResourceLocales) {
@@ -578,12 +534,17 @@ TEST_F(AssetManager2Test, GetResourceId) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
- EXPECT_EQ(basic::R::layout::main,
- assetmanager.GetResourceId("com.android.basic:layout/main", "", ""));
- EXPECT_EQ(basic::R::layout::main,
- assetmanager.GetResourceId("layout/main", "", "com.android.basic"));
- EXPECT_EQ(basic::R::layout::main,
- assetmanager.GetResourceId("main", "layout", "com.android.basic"));
+ auto resid = assetmanager.GetResourceId("com.android.basic:layout/main", "", "");
+ ASSERT_TRUE(resid.has_value());
+ EXPECT_EQ(basic::R::layout::main, *resid);
+
+ resid = assetmanager.GetResourceId("layout/main", "", "com.android.basic");
+ ASSERT_TRUE(resid.has_value());
+ EXPECT_EQ(basic::R::layout::main, *resid);
+
+ resid = assetmanager.GetResourceId("main", "layout", "com.android.basic");
+ ASSERT_TRUE(resid.has_value());
+ EXPECT_EQ(basic::R::layout::main, *resid);
}
TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {
@@ -658,14 +619,8 @@ TEST_F(AssetManager2Test, GetLastPathWithoutEnablingReturnsEmpty) {
assetmanager.SetApkAssets({basic_assets_.get()});
assetmanager.SetResourceResolutionLoggingEnabled(false);
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
auto result = assetmanager.GetLastResourceResolution();
EXPECT_EQ("", result);
@@ -693,17 +648,12 @@ TEST_F(AssetManager2Test, GetLastPathWithSingleApkAssets) {
assetmanager.SetConfiguration(desired_config);
assetmanager.SetApkAssets({basic_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
auto result = assetmanager.GetLastResourceResolution();
- EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic", result);
+ EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n"
+ "\tFor config -de\n\tFound initial: com.android.basic", result);
}
TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) {
@@ -717,17 +667,14 @@ TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) {
assetmanager.SetConfiguration(desired_config);
assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()});
- Res_value value = Res_value();
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
auto result = assetmanager.GetLastResourceResolution();
- EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic\n\tFound better: com.android.basic -de", result);
+ EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n"
+ "\tFor config -de\n"
+ "\tFound initial: com.android.basic\n"
+ "\tFound better: com.android.basic -de", result);
}
TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {
@@ -739,14 +686,8 @@ TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {
assetmanager.SetConfiguration(desired_config);
assetmanager.SetApkAssets({basic_assets_.get()});
- Res_value value = Res_value();
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
auto resultEnabled = assetmanager.GetLastResourceResolution();
ASSERT_NE("", resultEnabled);
diff --git a/libs/androidfw/tests/AttributeResolution_bench.cpp b/libs/androidfw/tests/AttributeResolution_bench.cpp
index fa300c50218a..ddd8ab820cb1 100644
--- a/libs/androidfw/tests/AttributeResolution_bench.cpp
+++ b/libs/androidfw/tests/AttributeResolution_bench.cpp
@@ -108,27 +108,20 @@ static void BM_ApplyStyleFramework(benchmark::State& state) {
device_config.screenHeightDp = 1024;
device_config.sdkVersion = 27;
- Res_value value;
- ResTable_config config;
- uint32_t flags = 0u;
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::layout::layoutt, false /*may_be_bag*/,
- 0u /*density_override*/, &value, &config, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = assetmanager.GetResource(basic::R::layout::layoutt);
+ if (!value.has_value()) {
state.SkipWithError("failed to find R.layout.layout");
return;
}
- size_t len = 0u;
- const char* layout_path =
- assetmanager.GetStringPoolForCookie(cookie)->string8At(value.data, &len);
- if (layout_path == nullptr || len == 0u) {
+ auto layout_path = assetmanager.GetStringPoolForCookie(value->cookie)->string8At(value->data);
+ if (!layout_path.has_value()) {
state.SkipWithError("failed to lookup layout path");
return;
}
- std::unique_ptr<Asset> asset = assetmanager.OpenNonAsset(
- StringPiece(layout_path, len).to_string(), cookie, Asset::ACCESS_BUFFER);
+ std::unique_ptr<Asset> asset = assetmanager.OpenNonAsset(layout_path->to_string(), value->cookie,
+ Asset::ACCESS_BUFFER);
if (asset == nullptr) {
state.SkipWithError("failed to load layout");
return;
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index 24361b5817f4..bb9129ad01c8 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -77,9 +77,9 @@ TEST(AttributeResolutionLibraryTest, ApplyStyleWithDefaultStyleResId) {
{fix_package_id(R::attr::attr_one, 0x02), fix_package_id(R::attr::attr_two, 0x02)}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
std::array<uint32_t, attrs.size() + 1> indices;
- ApplyStyle(theme.get(), nullptr /*xml_parser*/, 0u /*def_style_attr*/,
- fix_package_id(R::style::StyleOne, 0x02), attrs.data(), attrs.size(), values.data(),
- indices.data());
+ ASSERT_TRUE(ApplyStyle(theme.get(), nullptr /*xml_parser*/, 0u /*def_style_attr*/,
+ fix_package_id(R::style::StyleOne, 0x02), attrs.data(), attrs.size(),
+ values.data(), indices.data()).has_value());
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
@@ -102,7 +102,7 @@ TEST(AttributeResolutionLibraryTest, ApplyStyleWithDefaultStyleResId) {
TEST_F(AttributeResolutionTest, Theme) {
std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
+ ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo).has_value());
std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
R::attr::attr_four, R::attr::attr_empty}};
@@ -110,7 +110,7 @@ TEST_F(AttributeResolutionTest, Theme) {
ASSERT_TRUE(ResolveAttrs(theme.get(), 0u /*def_style_attr*/, 0u /*def_style_res*/,
nullptr /*src_values*/, 0 /*src_values_length*/, attrs.data(),
- attrs.size(), values.data(), nullptr /*out_indices*/));
+ attrs.size(), values.data(), nullptr /*out_indices*/).has_value());
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
@@ -162,7 +162,7 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) {
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
ASSERT_TRUE(RetrieveAttributes(&assetmanager_, &xml_parser_, attrs.data(), attrs.size(),
- values.data(), nullptr /*out_indices*/));
+ values.data(), nullptr /*out_indices*/).has_value());
uint32_t* values_cursor = values.data();
EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
@@ -207,15 +207,15 @@ TEST_F(AttributeResolutionXmlTest, XmlParser) {
TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) {
std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
+ ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo).has_value());
std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
std::array<uint32_t, attrs.size() + 1> indices;
- ApplyStyle(theme.get(), &xml_parser_, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
- attrs.size(), values.data(), indices.data());
+ ASSERT_TRUE(ApplyStyle(theme.get(), &xml_parser_, 0u /*def_style_attr*/, 0u /*def_style_res*/,
+ attrs.data(), attrs.size(), values.data(), indices.data()).has_value());
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
diff --git a/libs/androidfw/tests/BenchmarkHelpers.cpp b/libs/androidfw/tests/BenchmarkHelpers.cpp
index faddfe599af4..0fa0573bcbb8 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.cpp
+++ b/libs/androidfw/tests/BenchmarkHelpers.cpp
@@ -71,15 +71,9 @@ void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_
assetmanager.SetConfiguration(*config);
}
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t last_id = 0u;
-
while (state.KeepRunning()) {
- ApkAssetsCookie cookie = assetmanager.GetResource(
- resid, false /* may_be_bag */, 0u /* density_override */, &value, &selected_config, &flags);
- assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_id);
+ auto value = assetmanager.GetResource(resid);
+ assetmanager.ResolveReference(*value);
}
}
diff --git a/libs/androidfw/tests/CommonHelpers.cpp b/libs/androidfw/tests/CommonHelpers.cpp
index faa5350f9ecc..3396729536a4 100644
--- a/libs/androidfw/tests/CommonHelpers.cpp
+++ b/libs/androidfw/tests/CommonHelpers.cpp
@@ -58,8 +58,9 @@ const std::string& GetTestDataPath() {
}
std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx) {
- String8 str = pool->string8ObjectAt(idx);
- return std::string(str.string(), str.length());
+ auto str = pool->string8ObjectAt(idx);
+ CHECK(str.has_value()) << "failed to find string entry";
+ return std::string(str->string(), str->length());
}
} // namespace android
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index 7aa0dbbafab3..3f0c7cbc8ffc 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -62,10 +62,10 @@ class IdmapTest : public ::testing::Test {
std::unique_ptr<const ApkAssets> overlayable_assets_;
};
-std::string GetStringFromApkAssets(const AssetManager2& asset_manager, const Res_value& value,
- ApkAssetsCookie cookie) {
+std::string GetStringFromApkAssets(const AssetManager2& asset_manager,
+ const AssetManager2::SelectedValue& value) {
auto assets = asset_manager.GetApkAssets();
- const ResStringPool* string_pool = assets[cookie]->GetLoadedArsc()->GetStringPool();
+ const ResStringPool* string_pool = assets[value.cookie]->GetLoadedArsc()->GetStringPool();
return GetStringFromPool(string_pool, value.data);
}
@@ -75,117 +75,88 @@ TEST_F(IdmapTest, OverlayOverridesResourceValue) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable5,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_STRING);
- ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "Overlay One");
+
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable5);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_STRING);
+ ASSERT_EQ("Overlay One", GetStringFromApkAssets(asset_manager, *value));
}
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingDifferentPackage) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable10,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 0U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_STRING);
- ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "yes");
+
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable10);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 0U);
+ ASSERT_EQ(value->type, Res_value::TYPE_STRING);
+ ASSERT_EQ("yes", GetStringFromApkAssets(asset_manager, *value));
}
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInternalResource) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable8,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_REFERENCE);
- ASSERT_EQ(val.data, (overlay::R::string::internal & 0x00ffffff) | (0x02 << 24));
+
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable8);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_REFERENCE);
+ ASSERT_EQ(value->data, (overlay::R::string::internal & 0x00ffffffU) | (0x02U << 24));
}
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineInteger) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::integer::config_integer,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_INT_DEC);
- ASSERT_EQ(val.data, 42);
+
+ auto value = asset_manager.GetResource(overlayable::R::integer::config_integer);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_INT_DEC);
+ ASSERT_EQ(value->data, 42);
}
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineString) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
-
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable11,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_STRING);
- ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "Hardcoded string");
+
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable11);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_STRING);
+ ASSERT_EQ("Hardcoded string", GetStringFromApkAssets(asset_manager, *value));
}
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingOverlayingResource) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable9,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_REFERENCE);
- ASSERT_EQ(val.data, overlayable::R::string::overlayable7);
+
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable9);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_REFERENCE);
+ ASSERT_EQ(value->data, overlayable::R::string::overlayable7);
}
TEST_F(IdmapTest, OverlayOverridesXmlParser) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::layout::hello_view,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_STRING);
- ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "res/layout/hello_view.xml");
-
- auto asset = asset_manager.OpenNonAsset("res/layout/hello_view.xml", cookie,
+
+ auto value = asset_manager.GetResource(overlayable::R::layout::hello_view);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_STRING);
+ ASSERT_EQ("res/layout/hello_view.xml", GetStringFromApkAssets(asset_manager, *value));
+
+ auto asset = asset_manager.OpenNonAsset("res/layout/hello_view.xml", value->cookie,
Asset::ACCESS_RANDOM);
- auto dynamic_ref_table = asset_manager.GetDynamicRefTableForCookie(cookie);
+ auto dynamic_ref_table = asset_manager.GetDynamicRefTableForCookie(value->cookie);
auto xml_tree = util::make_unique<ResXMLTree>(std::move(dynamic_ref_table));
status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), false);
ASSERT_EQ(err, NO_ERROR);
@@ -216,32 +187,24 @@ TEST_F(IdmapTest, OverlaidResourceHasSameName) {
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- AssetManager2::ResourceName name;
- ASSERT_TRUE(asset_manager.GetResourceName(overlayable::R::string::overlayable9, &name));
- ASSERT_EQ(std::string(name.package), "com.android.overlayable");
- ASSERT_EQ(String16(name.type16), u"string");
- ASSERT_EQ(std::string(name.entry), "overlayable9");
+ auto name = asset_manager.GetResourceName(overlayable::R::string::overlayable9);
+ ASSERT_TRUE(name.has_value());
+ ASSERT_EQ("com.android.overlayable", std::string(name->package));
+ ASSERT_EQ(std::u16string(u"string"), std::u16string(name->type16));
+ ASSERT_EQ("overlayable9", std::string(name->entry));
}
TEST_F(IdmapTest, OverlayLoaderInterop) {
- std::string contents;
auto loader_assets = ApkAssets::LoadTable("loader/resources.arsc", PROPERTY_LOADER);
-
AssetManager2 asset_manager;
asset_manager.SetApkAssets({overlayable_assets_.get(), loader_assets.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable11,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- std::cout << asset_manager.GetLastResourceResolution();
- ASSERT_EQ(cookie, 1U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_STRING);
- ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "loader");
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable11);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(1U, value->cookie);
+ ASSERT_EQ(Res_value::TYPE_STRING, value->type);
+ ASSERT_EQ("loader", GetStringFromApkAssets(asset_manager, *value));
}
TEST_F(IdmapTest, OverlayAssetsIsUpToDate) {
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 2d69dfe4f429..63574110a817 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -50,7 +50,8 @@ TEST(LoadedArscTest, LoadSinglePackageArsc) {
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk", "resources.arsc",
&contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ auto loaded_arsc = LoadedArsc::Load(reinterpret_cast<const void*>(contents.data()),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
@@ -66,9 +67,8 @@ TEST(LoadedArscTest, LoadSinglePackageArsc) {
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- const ResTable_type* type = type_spec->types[0];
- ASSERT_THAT(type, NotNull());
- ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+ auto type = type_spec->types[0];
+ ASSERT_TRUE(LoadedPackage::GetEntry(type, entry_index).has_value());
}
TEST(LoadedArscTest, LoadSparseEntryApp) {
@@ -76,7 +76,8 @@ TEST(LoadedArscTest, LoadSparseEntryApp) {
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc",
&contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
@@ -90,9 +91,8 @@ TEST(LoadedArscTest, LoadSparseEntryApp) {
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- const ResTable_type* type = type_spec->types[0];
- ASSERT_THAT(type, NotNull());
- ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+ auto type = type_spec->types[0];
+ ASSERT_TRUE(LoadedPackage::GetEntry(type, entry_index).has_value());
}
TEST(LoadedArscTest, LoadSharedLibrary) {
@@ -100,7 +100,8 @@ TEST(LoadedArscTest, LoadSharedLibrary) {
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc",
&contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const auto& packages = loaded_arsc->GetPackages();
@@ -120,7 +121,8 @@ TEST(LoadedArscTest, LoadAppLinkedAgainstSharedLibrary) {
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/libclient/libclient.apk",
"resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const auto& packages = loaded_arsc->GetPackages();
@@ -145,8 +147,10 @@ TEST(LoadedArscTest, LoadAppAsSharedLibrary) {
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/appaslib/appaslib.apk",
"resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc =
- LoadedArsc::Load(StringPiece(contents), nullptr /* loaded_idmap */, PROPERTY_DYNAMIC);
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length(),
+ nullptr /* loaded_idmap */,
+ PROPERTY_DYNAMIC);
ASSERT_THAT(loaded_arsc, NotNull());
const auto& packages = loaded_arsc->GetPackages();
@@ -159,7 +163,8 @@ TEST(LoadedArscTest, LoadFeatureSplit) {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc",
&contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
@@ -172,15 +177,12 @@ TEST(LoadedArscTest, LoadFeatureSplit) {
const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- ASSERT_THAT(type_spec->types[0], NotNull());
- size_t len;
- const char16_t* type_name16 =
- package->GetTypeStringPool()->stringAt(type_spec->type_spec->id - 1, &len);
- ASSERT_THAT(type_name16, NotNull());
- EXPECT_THAT(util::Utf16ToUtf8(StringPiece16(type_name16, len)), StrEq("string"));
+ auto type_name16 = package->GetTypeStringPool()->stringAt(type_spec->type_spec->id - 1);
+ ASSERT_TRUE(type_name16.has_value());
+ EXPECT_THAT(util::Utf16ToUtf8(*type_name16), StrEq("string"));
- ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], entry_index), NotNull());
+ ASSERT_TRUE(LoadedPackage::GetEntry(type_spec->types[0], entry_index).has_value());
}
// AAPT(2) generates resource tables with chunks in a certain order. The rule is that
@@ -205,7 +207,8 @@ TEST(LoadedArscTest, LoadOutOfOrderTypeSpecs) {
ReadFileFromZipToString(GetTestDataPath() + "/out_of_order_types/out_of_order_types.apk",
"resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
@@ -215,12 +218,10 @@ TEST(LoadedArscTest, LoadOutOfOrderTypeSpecs) {
const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0);
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- ASSERT_THAT(type_spec->types[0], NotNull());
type_spec = package->GetTypeSpecByTypeIndex(1);
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- ASSERT_THAT(type_spec->types[0], NotNull());
}
TEST(LoadedArscTest, LoadOverlayable) {
@@ -228,7 +229,8 @@ TEST(LoadedArscTest, LoadOverlayable) {
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk",
"resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package = loaded_arsc->GetPackageById(
@@ -272,7 +274,8 @@ TEST(LoadedArscTest, ResourceIdentifierIterator) {
ASSERT_TRUE(
ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_NE(nullptr, loaded_arsc);
const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
@@ -320,7 +323,8 @@ TEST(LoadedArscTest, GetOverlayableMap) {
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk",
"resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_NE(nullptr, loaded_arsc);
const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
@@ -345,7 +349,7 @@ TEST(LoadedArscTest, LoadCustomLoader) {
asset->getLength());
std::unique_ptr<const LoadedArsc> loaded_arsc =
- LoadedArsc::Load(data, nullptr, PROPERTY_LOADER);
+ LoadedArsc::Load(data.data(), data.length(), nullptr, PROPERTY_LOADER);
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
@@ -361,9 +365,8 @@ TEST(LoadedArscTest, LoadCustomLoader) {
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- const ResTable_type* type = type_spec->types[0];
- ASSERT_THAT(type, NotNull());
- ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+ auto type = type_spec->types[0];
+ ASSERT_TRUE(LoadedPackage::GetEntry(type, entry_index).has_value());
}
// structs with size fields (like Res_value, ResTable_entry) should be
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 326474e16e5d..9aeb00c47e63 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -442,22 +442,22 @@ TEST(ResTableTest, TruncatedEncodeLength) {
ASSERT_LT(val.data, pool->size());
// Make sure a string with a truncated length is read to its correct length
- size_t str_len;
- const char* target_str8 = pool->string8At(val.data, &str_len);
- ASSERT_TRUE(target_str8 != NULL);
- ASSERT_EQ(size_t(40076), String8(target_str8, str_len).size());
- ASSERT_EQ(target_str8[40075], ']');
+ auto target_str8 = pool->string8At(val.data);
+ ASSERT_TRUE(target_str8.has_value());
+ ASSERT_EQ(size_t(40076), String8(target_str8->data(), target_str8->size()).size());
+ ASSERT_EQ(target_str8->data()[40075], ']');
- const char16_t* target_str16 = pool->stringAt(val.data, &str_len);
- ASSERT_TRUE(target_str16 != NULL);
- ASSERT_EQ(size_t(40076), String16(target_str16, str_len).size());
- ASSERT_EQ(target_str8[40075], (char16_t) ']');
+ auto target_str16 = pool->stringAt(val.data);
+ ASSERT_TRUE(target_str16.has_value());
+ ASSERT_EQ(size_t(40076), String16(target_str16->data(), target_str16->size()).size());
+ ASSERT_EQ(target_str8->data()[40075], (char16_t) ']');
// Load an edited apk with the null terminator removed from the end of the
// string
std::string invalid_contents;
- ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/length_decode/length_decode_invalid.apk",
- "resources.arsc", &invalid_contents));
+ ASSERT_TRUE(ReadFileFromZipToString(
+ GetTestDataPath() + "/length_decode/length_decode_invalid.apk", "resources.arsc",
+ &invalid_contents));
ResTable invalid_table;
ASSERT_EQ(NO_ERROR, invalid_table.add(invalid_contents.data(), invalid_contents.size()));
@@ -472,8 +472,8 @@ TEST(ResTableTest, TruncatedEncodeLength) {
// Make sure a string with a truncated length that is not null terminated errors
// and does not return the string
- ASSERT_TRUE(invalid_pool->string8At(invalid_val.data, &str_len) == NULL);
- ASSERT_TRUE(invalid_pool->stringAt(invalid_val.data, &str_len) == NULL);
+ ASSERT_FALSE(invalid_pool->string8At(invalid_val.data).has_value());
+ ASSERT_FALSE(invalid_pool->stringAt(invalid_val.data).has_value());
}
} // namespace android
diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp
index a81bb6ffab06..10c0a4fc8316 100644
--- a/libs/androidfw/tests/TestHelpers.cpp
+++ b/libs/androidfw/tests/TestHelpers.cpp
@@ -73,11 +73,15 @@ AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
return AssertionFailure() << "table has no string pool for block " << block;
}
- const String8 actual_str = pool->string8ObjectAt(val.data);
- if (String8(expected_str) != actual_str) {
- return AssertionFailure() << actual_str.string();
+ auto actual_str = pool->string8ObjectAt(val.data);
+ if (!actual_str.has_value()) {
+ return AssertionFailure() << "could not find string entry";
}
- return AssertionSuccess() << actual_str.string();
+
+ if (String8(expected_str) != *actual_str) {
+ return AssertionFailure() << actual_str->string();
+ }
+ return AssertionSuccess() << actual_str->string();
}
} // namespace android
diff --git a/libs/androidfw/tests/Theme_bench.cpp b/libs/androidfw/tests/Theme_bench.cpp
index 594c39eb682f..f3d60bbe4f15 100644
--- a/libs/androidfw/tests/Theme_bench.cpp
+++ b/libs/androidfw/tests/Theme_bench.cpp
@@ -70,11 +70,8 @@ static void BM_ThemeGetAttribute(benchmark::State& state) {
auto theme = assets.NewTheme();
theme->ApplyStyle(kStyleId, false /* force */);
- Res_value value;
- uint32_t flags;
-
while (state.KeepRunning()) {
- theme->GetAttribute(kAttrId, &value, &flags);
+ theme->GetAttribute(kAttrId);
}
}
BENCHMARK(BM_ThemeGetAttribute);
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 16b9c75982fb..f658735da515 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -67,10 +67,7 @@ TEST_F(ThemeTest, EmptyTheme) {
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
EXPECT_EQ(0u, theme->GetChangingConfigurations());
EXPECT_EQ(&assetmanager, theme->GetAssetManager());
-
- Res_value value;
- uint32_t flags;
- EXPECT_EQ(kInvalidCookie, theme->GetAttribute(app::R::attr::attr_one, &value, &flags));
+ EXPECT_FALSE(theme->GetAttribute(app::R::attr::attr_one).has_value());
}
TEST_F(ThemeTest, SingleThemeNoParent) {
@@ -78,23 +75,19 @@ TEST_F(ThemeTest, SingleThemeNoParent) {
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleOne));
-
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
-
- cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(1u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
-
- cookie = theme->GetAttribute(app::R::attr::attr_two, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(2u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleOne).has_value());
+
+ auto value = theme->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(1u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
+
+ value = theme->GetAttribute(app::R::attr::attr_two);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(2u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
}
TEST_F(ThemeTest, SingleThemeWithParent) {
@@ -102,32 +95,28 @@ TEST_F(ThemeTest, SingleThemeWithParent) {
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
-
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
-
- cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(1u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
-
- cookie = theme->GetAttribute(app::R::attr::attr_two, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
- EXPECT_EQ(0, cookie);
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
+
+ auto value = theme->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(1u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
+
+ value = theme->GetAttribute(app::R::attr::attr_two);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
+ EXPECT_EQ(0, value->cookie);
EXPECT_EQ(std::string("string"),
- GetStringFromPool(assetmanager.GetStringPoolForCookie(0), value.data));
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ GetStringFromPool(assetmanager.GetStringPoolForCookie(0), value->data));
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// This attribute should point to an attr_indirect, so the result should be 3.
- cookie = theme->GetAttribute(app::R::attr::attr_three, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(3u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme->GetAttribute(app::R::attr::attr_three);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(3u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
}
TEST_F(ThemeTest, TryToUseBadResourceId) {
@@ -135,11 +124,8 @@ TEST_F(ThemeTest, TryToUseBadResourceId) {
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
-
- Res_value value;
- uint32_t flags;
- ASSERT_EQ(kInvalidCookie, theme->GetAttribute(0x7f000001, &value, &flags));
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
+ ASSERT_FALSE(theme->GetAttribute(0x7f000001));
}
TEST_F(ThemeTest, MultipleThemesOverlaidNotForce) {
@@ -147,33 +133,29 @@ TEST_F(ThemeTest, MultipleThemesOverlaidNotForce) {
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree));
-
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree).has_value());
// attr_one is still here from the base.
- cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(1u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ auto value = theme->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(1u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// check for the new attr_six
- cookie = theme->GetAttribute(app::R::attr::attr_six, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(6u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme->GetAttribute(app::R::attr::attr_six);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(6u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// check for the old attr_five (force=true was not used).
- cookie = theme->GetAttribute(app::R::attr::attr_five, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(app::R::string::string_one, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme->GetAttribute(app::R::attr::attr_five);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(app::R::string::string_one, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
}
TEST_F(ThemeTest, MultipleThemesOverlaidForced) {
@@ -181,33 +163,29 @@ TEST_F(ThemeTest, MultipleThemesOverlaidForced) {
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree, true /* force */));
-
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree, true /* force */).has_value());
// attr_one is still here from the base.
- cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(1u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ auto value = theme->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(1u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// check for the new attr_six
- cookie = theme->GetAttribute(app::R::attr::attr_six, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(6u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme->GetAttribute(app::R::attr::attr_six);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(6u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// check for the new attr_five (force=true was used).
- cookie = theme->GetAttribute(app::R::attr::attr_five, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(5u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme->GetAttribute(app::R::attr::attr_five);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(5u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
}
TEST_F(ThemeTest, ResolveDynamicAttributesAndReferencesToSharedLibrary) {
@@ -216,28 +194,24 @@ TEST_F(ThemeTest, ResolveDynamicAttributesAndReferencesToSharedLibrary) {
{lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(libclient::R::style::Theme, false /*force*/));
-
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
+ ASSERT_TRUE(theme->ApplyStyle(libclient::R::style::Theme, false /*force*/).has_value());
// The attribute should be resolved to the final value.
- cookie = theme->GetAttribute(libclient::R::attr::foo, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(700u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ auto value = theme->GetAttribute(libclient::R::attr::foo);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(700u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// The reference should be resolved to a TYPE_REFERENCE.
- cookie = theme->GetAttribute(libclient::R::attr::bar, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
+ value = theme->GetAttribute(libclient::R::attr::bar);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
// lib_one is assigned package ID 0x03.
- EXPECT_EQ(3u, get_package_id(value.data));
- EXPECT_EQ(get_type_id(lib_one::R::string::foo), get_type_id(value.data));
- EXPECT_EQ(get_entry_id(lib_one::R::string::foo), get_entry_id(value.data));
+ EXPECT_EQ(3u, get_package_id(value->data));
+ EXPECT_EQ(get_type_id(lib_one::R::string::foo), get_type_id(value->data));
+ EXPECT_EQ(get_entry_id(lib_one::R::string::foo), get_entry_id(value->data));
}
TEST_F(ThemeTest, CopyThemeSameAssetManager) {
@@ -245,24 +219,20 @@ TEST_F(ThemeTest, CopyThemeSameAssetManager) {
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme_one = assetmanager.NewTheme();
- ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
-
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
+ ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne).has_value());
// attr_one is still here from the base.
- cookie = theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(1u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ auto value = theme_one->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(1u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// attr_six is not here.
- EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_six, &value, &flags));
+ ASSERT_FALSE(theme_one->GetAttribute(app::R::attr::attr_six).has_value());
std::unique_ptr<Theme> theme_two = assetmanager.NewTheme();
- ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleThree));
+ ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleThree).has_value());
// Copy the theme to theme_one.
theme_one->SetTo(*theme_two);
@@ -271,14 +241,14 @@ TEST_F(ThemeTest, CopyThemeSameAssetManager) {
theme_two->Clear();
// attr_one is now not here.
- EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
+ ASSERT_FALSE(theme_one->GetAttribute(app::R::attr::attr_one).has_value());
// attr_six is now here because it was copied.
- cookie = theme_one->GetAttribute(app::R::attr::attr_six, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(6u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme_one->GetAttribute(app::R::attr::attr_six);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(6u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
}
TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) {
@@ -291,39 +261,43 @@ TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) {
style_assets_.get()});
auto theme_dst = assetmanager_dst.NewTheme();
- ASSERT_TRUE(theme_dst->ApplyStyle(app::R::style::StyleOne));
+ ASSERT_TRUE(theme_dst->ApplyStyle(app::R::style::StyleOne).has_value());
auto theme_src = assetmanager_src.NewTheme();
- ASSERT_TRUE(theme_src->ApplyStyle(R::style::Theme_One));
- ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleTwo));
+ ASSERT_TRUE(theme_src->ApplyStyle(R::style::Theme_One).has_value());
+ ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleTwo).has_value());
ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03),
- false /*force*/));
+ false /*force*/).has_value());
ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02),
- false /*force*/));
+ false /*force*/).has_value());
theme_dst->SetTo(*theme_src);
- Res_value value;
- uint32_t flags;
-
// System resources (present in destination asset manager).
- EXPECT_EQ(0, theme_dst->GetAttribute(R::attr::foreground, &value, &flags));
+ auto value = theme_dst->GetAttribute(R::attr::foreground);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(0, value->cookie);
// The cookie of the style asset is 3 in the source and 2 in the destination.
// Check that the cookie has been rewritten to the destination values.
- EXPECT_EQ(2, theme_dst->GetAttribute(app::R::attr::attr_one, &value, &flags));
+ value = theme_dst->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(2, value->cookie);
// The cookie of the lib_one asset is 2 in the source and 1 in the destination.
// The package id of the lib_one package is 0x03 in the source and 0x02 in the destination
// Check that the cookie and packages have been rewritten to the destination values.
- EXPECT_EQ(1, theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02), &value,
- &flags));
- EXPECT_EQ(1, theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02), &value,
- &flags));
+ value = theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02));
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(1, value->cookie);
+
+ value = theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02));
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(1, value->cookie);
// attr2 references an attribute in lib_one. Check that the resolution of the attribute value is
// correct after the value of attr2 had its package id rewritten to the destination package id.
- EXPECT_EQ(700, value.data);
+ EXPECT_EQ(700, value->data);
}
TEST_F(ThemeTest, CopyNonReferencesWhenPackagesDiffer) {
@@ -335,28 +309,32 @@ TEST_F(ThemeTest, CopyNonReferencesWhenPackagesDiffer) {
auto theme_dst = assetmanager_dst.NewTheme();
auto theme_src = assetmanager_src.NewTheme();
- ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleSeven));
+ ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleSeven).has_value());
theme_dst->SetTo(*theme_src);
- Res_value value;
- uint32_t flags;
-
// Allow inline resource values to be copied even if the source apk asset is not present in the
// destination.
- EXPECT_EQ(0, theme_dst->GetAttribute(0x0101021b /* android:versionCode */, &value, &flags));
+ auto value = theme_dst->GetAttribute(0x0101021b /* android:versionCode */);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(0, value->cookie);
// Do not copy strings since the data is an index into the values string pool of the source apk
// asset.
- EXPECT_EQ(-1, theme_dst->GetAttribute(0x01010001 /* android:label */, &value, &flags));
+ EXPECT_FALSE(theme_dst->GetAttribute(0x01010001 /* android:label */).has_value());
// Do not copy values that reference another resource if the resource is not present in the
// destination.
- EXPECT_EQ(-1, theme_dst->GetAttribute(0x01010002 /* android:icon */, &value, &flags));
- EXPECT_EQ(-1, theme_dst->GetAttribute(0x010100d1 /* android:tag */, &value, &flags));
+ EXPECT_FALSE(theme_dst->GetAttribute(0x01010002 /* android:icon */).has_value());
+ EXPECT_FALSE(theme_dst->GetAttribute(0x010100d1 /* android:tag */).has_value());
// Allow @empty to and @null to be copied.
- EXPECT_EQ(0, theme_dst->GetAttribute(0x010100d0 /* android:id */, &value, &flags));
- EXPECT_EQ(0, theme_dst->GetAttribute(0x01010000 /* android:theme */, &value, &flags));
+ value = theme_dst->GetAttribute(0x010100d0 /* android:id */);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(0, value->cookie);
+
+ value = theme_dst->GetAttribute(0x01010000 /* android:theme */);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(0, value->cookie);
}
} // namespace android
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 155bb6ba8f75..4ed5457a2a7f 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -429,6 +429,8 @@ cc_defaults {
whole_static_libs: ["libskia"],
srcs: [
+ "canvas/CanvasOpBuffer.cpp",
+ "canvas/CanvasOpRasterizer.cpp",
"pipeline/skia/SkiaDisplayList.cpp",
"pipeline/skia/SkiaRecordingCanvas.cpp",
"pipeline/skia/RenderNodeDrawable.cpp",
@@ -604,6 +606,7 @@ cc_test {
"tests/unit/ABitmapTests.cpp",
"tests/unit/CacheManagerTests.cpp",
"tests/unit/CanvasContextTests.cpp",
+ "tests/unit/CanvasOpTests.cpp",
"tests/unit/CommonPoolTests.cpp",
"tests/unit/DamageAccumulatorTests.cpp",
"tests/unit/DeferredLayerUpdaterTests.cpp",
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index b2c39c90071a..ccce403ecfac 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -183,7 +183,6 @@ void JankTracker::finishFrame(const FrameInfo& frame) {
ALOGI("%s", ss.str().c_str());
// Just so we have something that counts up, the value is largely irrelevant
ATRACE_INT(ss.str().c_str(), ++sDaveyCount);
- android::util::stats_write(android::util::DAVEY_OCCURRED, getuid(), ns2ms(totalDuration));
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponentModule.java b/libs/hwui/canvas/CanvasOpBuffer.cpp
index 4de316693c10..7054e47eac89 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponentModule.java
+++ b/libs/hwui/canvas/CanvasOpBuffer.cpp
@@ -14,15 +14,12 @@
* limitations under the License.
*/
-package com.android.systemui;
+#include "CanvasOpBuffer.h"
-import dagger.Module;
+#include "CanvasOps.h"
-/**
- * Dagger module for including the CarSysUIComponent.
- *
- * TODO(b/162923491): Remove or otherwise refactor this module. This is a stop gap.
- */
-@Module(subcomponents = {CarSysUIComponent.class})
-public abstract class CarSysUIComponentModule {
-}
+namespace android::uirenderer {
+
+template class OpBuffer<CanvasOpType, CanvasOpContainer>;
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/canvas/CanvasOpBuffer.h b/libs/hwui/canvas/CanvasOpBuffer.h
new file mode 100644
index 000000000000..07e079a7d57f
--- /dev/null
+++ b/libs/hwui/canvas/CanvasOpBuffer.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <SkMatrix.h>
+
+#include "CanvasOpTypes.h"
+#include "OpBuffer.h"
+
+namespace android::uirenderer {
+
+template <CanvasOpType T>
+struct CanvasOp;
+
+template <CanvasOpType T>
+class CanvasOpContainer {
+private:
+ BE_OPBUFFERS_FRIEND();
+
+ OpBufferItemHeader<CanvasOpType> header;
+ // TODO: Figure out some magic to make this not be here when it's identity (or not used)
+ SkMatrix mTransform;
+ CanvasOp<T> mImpl;
+
+public:
+ CanvasOpContainer(CanvasOp<T>&& impl, const SkMatrix& transform = SkMatrix::I())
+ : mTransform(transform), mImpl(std::move(impl)) {}
+
+ uint32_t size() const { return header.size; }
+ CanvasOpType type() const { return header.type; }
+
+ const SkMatrix& transform() const { return mTransform; }
+
+ CanvasOp<T>* operator->() noexcept { return &mImpl; }
+ const CanvasOp<T>* operator->() const noexcept { return &mImpl; }
+
+ CanvasOp<T>& op() noexcept { return mImpl; }
+ const CanvasOp<T>& op() const noexcept { return mImpl; }
+};
+
+extern template class OpBuffer<CanvasOpType, CanvasOpContainer>;
+class CanvasOpBuffer final : public OpBuffer<CanvasOpType, CanvasOpContainer> {
+public:
+ template <CanvasOpType T>
+ void push(CanvasOp<T>&& op) {
+ push_container(CanvasOpContainer<T>(std::move(op)));
+ }
+};
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/canvas/CanvasOpRasterizer.cpp b/libs/hwui/canvas/CanvasOpRasterizer.cpp
new file mode 100644
index 000000000000..25129f641c00
--- /dev/null
+++ b/libs/hwui/canvas/CanvasOpRasterizer.cpp
@@ -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.
+ */
+
+#include "CanvasOpRasterizer.h"
+
+#include <SkCanvas.h>
+#include <log/log.h>
+
+#include <vector>
+
+#include "CanvasOpBuffer.h"
+#include "CanvasOps.h"
+
+namespace android::uirenderer {
+
+void rasterizeCanvasBuffer(const CanvasOpBuffer& source, SkCanvas* destination) {
+ // Tracks the global transform from the current display list back toward the display space
+ // Push on beginning a RenderNode draw, pop on ending one
+ std::vector<SkMatrix> globalMatrixStack;
+ SkMatrix& currentGlobalTransform = globalMatrixStack.emplace_back(SkMatrix::I());
+
+ source.for_each([&]<CanvasOpType T>(const CanvasOpContainer<T> * op) {
+ if constexpr (T == CanvasOpType::BeginZ || T == CanvasOpType::EndZ) {
+ // Do beginZ or endZ
+ LOG_ALWAYS_FATAL("TODO");
+ return;
+ } else {
+ // Generic OP
+ // First apply the current transformation
+ destination->setMatrix(SkMatrix::Concat(currentGlobalTransform, op->transform()));
+ // Now draw it
+ (*op)->draw(destination);
+ }
+ });
+}
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/canvas/CanvasOpRasterizer.h b/libs/hwui/canvas/CanvasOpRasterizer.h
new file mode 100644
index 000000000000..c2235ab84d56
--- /dev/null
+++ b/libs/hwui/canvas/CanvasOpRasterizer.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <hwui/Bitmap.h>
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+
+#include "CanvasOps.h"
+
+#include <experimental/type_traits>
+#include <variant>
+
+namespace android::uirenderer {
+
+class CanvasOpBuffer;
+
+void rasterizeCanvasBuffer(const CanvasOpBuffer& source, SkCanvas* destination);
+
+class ImmediateModeRasterizer {
+public:
+ explicit ImmediateModeRasterizer(std::unique_ptr<SkCanvas>&& canvas) {
+ mCanvas = canvas.get();
+ mOwnership = std::move(canvas);
+ }
+
+ explicit ImmediateModeRasterizer(std::shared_ptr<SkCanvas> canvas) {
+ mCanvas = canvas.get();
+ mOwnership = std::move(canvas);
+ }
+
+ explicit ImmediateModeRasterizer(Bitmap& bitmap) {
+ mCanvas = &(mOwnership.emplace<SkCanvas>(bitmap.getSkBitmap()));
+ }
+
+ template <CanvasOpType T>
+ void draw(const CanvasOp<T>& op) {
+ if constexpr (CanvasOpTraits::can_draw<CanvasOp<T>>) {
+ op.draw(mCanvas);
+ }
+ }
+
+private:
+ SkCanvas* mCanvas;
+ // Just here to keep mCanvas alive. Thankfully we never need to actually look inside this...
+ std::variant<SkCanvas, std::shared_ptr<SkCanvas>, std::unique_ptr<SkCanvas>> mOwnership;
+};
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/canvas/CanvasOpTypes.h b/libs/hwui/canvas/CanvasOpTypes.h
new file mode 100644
index 000000000000..f9df2f7aa5ba
--- /dev/null
+++ b/libs/hwui/canvas/CanvasOpTypes.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+
+namespace android::uirenderer {
+
+enum class CanvasOpType : int8_t {
+ // State ops
+ // TODO: Eliminate the end ops by having the start include the end-at position
+ Save,
+ SaveLayer,
+ SaveBehind,
+ Restore,
+ BeginZ,
+ EndZ,
+
+ // Clip ops
+ ClipRect,
+ ClipPath,
+
+ // Drawing ops
+ DrawColor,
+ DrawRect,
+ DrawRegion,
+ DrawRoundRect,
+ DrawRoundRectProperty,
+ DrawDoubleRoundRect,
+ DrawCircleProperty,
+ DrawCircle,
+ DrawOval,
+ DrawArc,
+ DrawPaint,
+ DrawPoint,
+ DrawPath,
+ DrawLine,
+ DrawVertices,
+ DrawImage,
+ DrawImageRect,
+ // DrawImageLattice also used to draw 9 patches
+ DrawImageLattice,
+ DrawPicture,
+
+ // TODO: Rest
+
+ COUNT // must be last
+};
+
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h
new file mode 100644
index 000000000000..8c7113d5d075
--- /dev/null
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -0,0 +1,370 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <SkAndroidFrameworkUtils.h>
+#include <SkCanvas.h>
+#include <SkPath.h>
+#include <SkRegion.h>
+#include <SkVertices.h>
+#include <SkImage.h>
+#include <SkPicture.h>
+#include <hwui/Bitmap.h>
+#include <log/log.h>
+#include "CanvasProperty.h"
+
+#include "CanvasOpTypes.h"
+
+#include <experimental/type_traits>
+#include <utility>
+
+namespace android::uirenderer {
+
+template <CanvasOpType T>
+struct CanvasOp;
+
+struct CanvasOpTraits {
+ CanvasOpTraits() = delete;
+
+ template<class T>
+ using draw_t = decltype(std::integral_constant<void (T::*)(SkCanvas*) const, &T::draw>{});
+
+ template <class T>
+ static constexpr bool can_draw = std::experimental::is_detected_v<draw_t, T>;
+};
+
+#define ASSERT_DRAWABLE() private: constexpr void _check_drawable() \
+ { static_assert(CanvasOpTraits::can_draw<std::decay_t<decltype(*this)>>); }
+
+// ----------------------------------------------
+// State Ops
+// ---------------------------------------------
+
+template <>
+struct CanvasOp<CanvasOpType::Save> {
+ void draw(SkCanvas* canvas) const { canvas->save(); }
+ ASSERT_DRAWABLE()
+};
+
+template <>
+struct CanvasOp<CanvasOpType::SaveLayer> {
+ SkCanvas::SaveLayerRec saveLayerRec;
+ void draw(SkCanvas* canvas) const { canvas->saveLayer(saveLayerRec); }
+ ASSERT_DRAWABLE()
+};
+
+template <>
+struct CanvasOp<CanvasOpType::SaveBehind> {
+ SkRect bounds;
+ void draw(SkCanvas* canvas) const { SkAndroidFrameworkUtils::SaveBehind(canvas, &bounds); }
+ ASSERT_DRAWABLE()
+};
+
+template <>
+struct CanvasOp<CanvasOpType::Restore> {
+ void draw(SkCanvas* canvas) const { canvas->restore(); }
+ ASSERT_DRAWABLE()
+};
+
+template <>
+struct CanvasOp<CanvasOpType::BeginZ> {
+};
+template <>
+struct CanvasOp<CanvasOpType::EndZ> {};
+
+// ----------------------------------------------
+// Clip Ops
+// ---------------------------------------------
+
+template <>
+struct CanvasOp<CanvasOpType::ClipRect> {
+ SkRect rect;
+ SkClipOp clipOp;
+ void draw(SkCanvas* canvas) const { canvas->clipRect(rect, clipOp); }
+ ASSERT_DRAWABLE()
+};
+
+template <>
+struct CanvasOp<CanvasOpType::ClipPath> {
+ SkPath path;
+ SkClipOp op;
+ void draw(SkCanvas* canvas) const { canvas->clipPath(path, op, true); }
+ ASSERT_DRAWABLE()
+};
+
+// ----------------------------------------------
+// Drawing Ops
+// ---------------------------------------------
+
+template<>
+struct CanvasOp<CanvasOpType::DrawRoundRectProperty> {
+ sp<uirenderer::CanvasPropertyPrimitive> left;
+ sp<uirenderer::CanvasPropertyPrimitive> top;
+ sp<uirenderer::CanvasPropertyPrimitive> right;
+ sp<uirenderer::CanvasPropertyPrimitive> bottom;
+ sp<uirenderer::CanvasPropertyPrimitive> rx;
+ sp<uirenderer::CanvasPropertyPrimitive> ry;
+ sp<uirenderer::CanvasPropertyPaint> paint;
+
+ void draw(SkCanvas* canvas) const {
+ SkRect rect = SkRect::MakeLTRB(left->value, top->value, right->value, bottom->value);
+ canvas->drawRoundRect(rect, rx->value, ry->value, paint->value);
+ }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawCircleProperty> {
+ sp<uirenderer::CanvasPropertyPrimitive> x;
+ sp<uirenderer::CanvasPropertyPrimitive> y;
+ sp<uirenderer::CanvasPropertyPrimitive> radius;
+ sp<uirenderer::CanvasPropertyPaint> paint;
+
+ void draw(SkCanvas* canvas) const {
+ canvas->drawCircle(x->value, y->value, radius->value, paint->value);
+ }
+ ASSERT_DRAWABLE()
+};
+
+template <>
+struct CanvasOp<CanvasOpType::DrawColor> {
+ SkColor4f color;
+ SkBlendMode mode;
+ void draw(SkCanvas* canvas) const { canvas->drawColor(color, mode); }
+ ASSERT_DRAWABLE()
+};
+
+template <>
+struct CanvasOp<CanvasOpType::DrawPaint> {
+ SkPaint paint;
+ void draw(SkCanvas* canvas) const { canvas->drawPaint(paint); }
+ ASSERT_DRAWABLE()
+};
+
+template <>
+struct CanvasOp<CanvasOpType::DrawPoint> {
+ float x;
+ float y;
+ SkPaint paint;
+ void draw(SkCanvas* canvas) const { canvas->drawPoint(x, y, paint); }
+ ASSERT_DRAWABLE()
+};
+
+template <>
+struct CanvasOp<CanvasOpType::DrawRect> {
+ SkRect rect;
+ SkPaint paint;
+ void draw(SkCanvas* canvas) const { canvas->drawRect(rect, paint); }
+ ASSERT_DRAWABLE()
+};
+
+template <>
+struct CanvasOp<CanvasOpType::DrawRegion> {
+ SkRegion region;
+ SkPaint paint;
+ void draw(SkCanvas* canvas) const { canvas->drawRegion(region, paint); }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawRoundRect> {
+ SkRect rect;
+ SkScalar rx;
+ SkScalar ry;
+ SkPaint paint;
+ void draw(SkCanvas* canvas) const {
+ canvas->drawRoundRect(rect, rx, ry, paint);
+ }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawDoubleRoundRect> {
+ SkRRect outer;
+ SkRRect inner;
+ SkPaint paint;
+ void draw(SkCanvas* canvas) const {
+ canvas->drawDRRect(outer, inner, paint);
+ }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawCircle> {
+ SkScalar cx;
+ SkScalar cy;
+ SkScalar radius;
+ SkPaint paint;
+ void draw(SkCanvas* canvas) const {
+ canvas->drawCircle(cx, cy, radius, paint);
+ }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawOval> {
+ SkRect oval;
+ SkPaint paint;
+ void draw(SkCanvas* canvas) const {
+ canvas->drawOval(oval, paint);
+ }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawArc> {
+ SkRect oval;
+ SkScalar startAngle;
+ SkScalar sweepAngle;
+ bool useCenter;
+ SkPaint paint;
+
+ void draw(SkCanvas* canvas) const {
+ canvas->drawArc(oval, startAngle, sweepAngle, useCenter, paint);
+ }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawPath> {
+ SkPath path;
+ SkPaint paint;
+
+ void draw(SkCanvas* canvas) const { canvas->drawPath(path, paint); }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawLine> {
+ float startX;
+ float startY;
+ float endX;
+ float endY;
+ SkPaint paint;
+
+ void draw(SkCanvas* canvas) const {
+ canvas->drawLine(startX, startY, endX, endY, paint);
+ }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawVertices> {
+ sk_sp<SkVertices> vertices;
+ SkBlendMode mode;
+ SkPaint paint;
+ void draw(SkCanvas* canvas) const {
+ canvas->drawVertices(vertices, mode, paint);
+ }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawImage> {
+
+ CanvasOp<CanvasOpType::DrawImageRect>(
+ const sk_sp<Bitmap>& bitmap,
+ float left,
+ float top,
+ SkPaint paint
+ ) : left(left),
+ top(top),
+ paint(std::move(paint)),
+ bitmap(bitmap),
+ image(bitmap->makeImage()) { }
+
+ float left;
+ float top;
+ SkPaint paint;
+ sk_sp<Bitmap> bitmap;
+ sk_sp<SkImage> image;
+
+ void draw(SkCanvas* canvas) const {
+ canvas->drawImage(image, left, top, &paint);
+ }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawImageRect> {
+
+ CanvasOp<CanvasOpType::DrawImageRect>(
+ const sk_sp<Bitmap>& bitmap,
+ SkRect src,
+ SkRect dst,
+ SkPaint paint
+ ) : src(src),
+ dst(dst),
+ paint(std::move(paint)),
+ bitmap(bitmap),
+ image(bitmap->makeImage()) { }
+
+ SkRect src;
+ SkRect dst;
+ SkPaint paint;
+ sk_sp<Bitmap> bitmap;
+ sk_sp<SkImage> image;
+
+ void draw(SkCanvas* canvas) const {
+ canvas->drawImageRect(image,
+ src,
+ dst,
+ &paint,
+ SkCanvas::kFast_SrcRectConstraint
+ );
+ }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawImageLattice> {
+
+ CanvasOp<CanvasOpType::DrawImageLattice>(
+ const sk_sp<Bitmap>& bitmap,
+ SkRect dst,
+ SkCanvas::Lattice lattice,
+ SkPaint paint
+ ): dst(dst),
+ lattice(lattice),
+ bitmap(bitmap),
+ image(bitmap->makeImage()),
+ paint(std::move(paint)) {}
+
+ SkRect dst;
+ SkCanvas::Lattice lattice;
+ const sk_sp<Bitmap> bitmap;
+ const sk_sp<SkImage> image;
+
+ SkPaint paint;
+ void draw(SkCanvas* canvas) const {
+ canvas->drawImageLattice(image.get(), lattice, dst, &paint);
+ }
+ ASSERT_DRAWABLE()
+};
+
+template<>
+struct CanvasOp<CanvasOpType::DrawPicture> {
+ sk_sp<SkPicture> picture;
+ void draw(SkCanvas* canvas) const {
+ picture->playback(canvas);
+ }
+};
+
+// cleanup our macros
+#undef ASSERT_DRAWABLE
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/canvas/OpBuffer.h b/libs/hwui/canvas/OpBuffer.h
new file mode 100644
index 000000000000..98e385f37a6e
--- /dev/null
+++ b/libs/hwui/canvas/OpBuffer.h
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <array>
+#include <cinttypes>
+#include <cstddef>
+#include <cstdlib>
+#include <type_traits>
+#include <utility>
+
+namespace android::uirenderer {
+
+template <typename T>
+struct OpBufferItemHeader {
+ T type : 8;
+ uint32_t size : 24;
+};
+
+struct OpBufferAllocationHeader {
+ // Used size, including header size
+ size_t used = 0;
+ // Capacity, including header size
+ size_t capacity = 0;
+ // Offset relative to `this` at which the first item is
+ size_t startOffset = 0;
+ // Offset relative to `this` at which the last item is
+ size_t endOffset = 0;
+};
+
+#define BE_OPBUFFERS_FRIEND() \
+ template <typename ItemTypes, template <ItemTypes> typename, typename, typename> \
+ friend class OpBuffer
+
+template <typename ItemTypes, template <ItemTypes> typename ItemContainer,
+ typename BufferHeader = OpBufferAllocationHeader,
+ typename ItemTypesSequence = std::make_index_sequence<static_cast<int>(ItemTypes::COUNT)>>
+class OpBuffer {
+ // Instead of re-aligning individual inserts, just pad the size of everything
+ // to a multiple of pointer alignment. This assumes we never work with doubles.
+ // Which we don't.
+ static constexpr size_t Alignment = alignof(void*);
+
+ static constexpr size_t PadAlign(size_t size) {
+ return (size + (Alignment - 1)) & -Alignment;
+ }
+
+ static constexpr auto STARTING_SIZE = PadAlign(sizeof(BufferHeader));
+
+public:
+ using ItemHeader = OpBufferItemHeader<ItemTypes>;
+
+ OpBuffer() = default;
+
+ // Prevent copying by default
+ OpBuffer(const OpBuffer&) = delete;
+ void operator=(const OpBuffer&) = delete;
+
+ OpBuffer(OpBuffer&& other) {
+ mBuffer = other.mBuffer;
+ other.mBuffer = nullptr;
+ }
+
+ void operator=(OpBuffer&& other) {
+ destroy();
+ mBuffer = other.mBuffer;
+ other.mBuffer = nullptr;
+ }
+
+ ~OpBuffer() {
+ destroy();
+ }
+
+ constexpr size_t capacity() const { return mBuffer ? mBuffer->capacity : 0; }
+
+ constexpr size_t size() const { return mBuffer ? mBuffer->used : 0; }
+
+ constexpr size_t remaining() const { return capacity() - size(); }
+
+ // TODO: Add less-copy'ing variants of this. emplace_back? deferred initialization?
+ template <ItemTypes T>
+ void push_container(ItemContainer<T>&& op) {
+ static_assert(alignof(ItemContainer<T>) <= Alignment);
+ static_assert(offsetof(ItemContainer<T>, header) == 0);
+
+ constexpr auto padded_size = PadAlign(sizeof(ItemContainer<T>));
+ if (remaining() < padded_size) {
+ resize(std::max(padded_size, capacity()) * 2);
+ }
+ mBuffer->endOffset = mBuffer->used;
+ mBuffer->used += padded_size;
+
+ void* allocateAt = reinterpret_cast<uint8_t*>(mBuffer) + mBuffer->endOffset;
+ auto temp = new (allocateAt) ItemContainer<T>{std::move(op)};
+ temp->header = {.type = T, .size = padded_size};
+ }
+
+ void resize(size_t newsize) {
+ // Add the header size to newsize
+ const size_t adjustedSize = newsize + STARTING_SIZE;
+
+ if (adjustedSize < size()) {
+ // todo: throw?
+ return;
+ }
+ if (newsize == 0) {
+ free(mBuffer);
+ mBuffer = nullptr;
+ } else {
+ if (mBuffer) {
+ mBuffer = reinterpret_cast<BufferHeader*>(realloc(mBuffer, adjustedSize));
+ mBuffer->capacity = adjustedSize;
+ } else {
+ mBuffer = new (malloc(adjustedSize)) BufferHeader();
+ mBuffer->capacity = adjustedSize;
+ mBuffer->used = STARTING_SIZE;
+ mBuffer->startOffset = STARTING_SIZE;
+ }
+ }
+ }
+
+ template <typename F>
+ void for_each(F&& f) const {
+ for_each(std::forward<F>(f), ItemTypesSequence{});
+ }
+
+ void clear();
+
+ ItemHeader* first() const { return isEmpty() ? nullptr : itemAt(mBuffer->startOffset); }
+
+ ItemHeader* last() const { return isEmpty() ? nullptr : itemAt(mBuffer->endOffset); }
+
+private:
+ template <typename F, std::size_t... I>
+ void for_each(F&& f, std::index_sequence<I...>) const {
+ // Validate we're not empty
+ if (isEmpty()) return;
+
+ // Setup the jump table, mapping from each type to a springboard that invokes the template
+ // function with the appropriate concrete type
+ using F_PTR = decltype(&f);
+ using THUNK = void (*)(F_PTR, void*);
+ static constexpr auto jump = std::array<THUNK, sizeof...(I)>{[](F_PTR fp, void* t) {
+ (*fp)(reinterpret_cast<const ItemContainer<static_cast<ItemTypes>(I)>*>(t));
+ }...};
+
+ // Do the actual iteration of each item
+ uint8_t* current = reinterpret_cast<uint8_t*>(mBuffer) + mBuffer->startOffset;
+ uint8_t* end = reinterpret_cast<uint8_t*>(mBuffer) + mBuffer->used;
+ while (current != end) {
+ auto header = reinterpret_cast<ItemHeader*>(current);
+ // `f` could be a destructor, so ensure all accesses to the OP happen prior to invoking
+ // `f`
+ auto it = (void*)current;
+ current += header->size;
+ jump[static_cast<int>(header->type)](&f, it);
+ }
+ }
+
+ void destroy() {
+ clear();
+ resize(0);
+ }
+
+ bool offsetIsValid(size_t offset) const {
+ return offset >= mBuffer->startOffset && offset < mBuffer->used;
+ }
+
+ ItemHeader* itemAt(size_t offset) const {
+ if (!offsetIsValid(offset)) return nullptr;
+ return reinterpret_cast<ItemHeader*>(reinterpret_cast<uint8_t*>(mBuffer) + offset);
+ }
+
+ bool isEmpty() const { return mBuffer == nullptr || mBuffer->used == STARTING_SIZE; }
+
+ BufferHeader* mBuffer = nullptr;
+};
+
+template <typename ItemTypes, template <ItemTypes> typename ItemContainer, typename BufferHeader,
+ typename ItemTypeSequence>
+void OpBuffer<ItemTypes, ItemContainer, BufferHeader, ItemTypeSequence>::clear() {
+
+ // Don't need to do anything if we don't have a buffer
+ if (!mBuffer) return;
+
+ for_each([](auto op) {
+ using T = std::remove_reference_t<decltype(*op)>;
+ op->~T();
+ });
+ mBuffer->used = STARTING_SIZE;
+ mBuffer->startOffset = STARTING_SIZE;
+ mBuffer->endOffset = 0;
+}
+
+} // namespace android::uirenderer \ No newline at end of file
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 6ece7ef9f329..94a047c06ced 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -100,6 +100,12 @@ public:
void getSkBitmap(SkBitmap* outBitmap);
+ SkBitmap getSkBitmap() {
+ SkBitmap ret;
+ getSkBitmap(&ret);
+ return ret;
+ }
+
int getAshmemFd() const;
size_t getAllocationByteCount() const;
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index ef8d8f4ee4f3..0c3ef01ab26b 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -41,6 +41,9 @@ public:
enum Style : uint8_t { kNormal = 0, kBold = 0x01, kItalic = 0x02, kBoldItalic = 0x03 };
Style fAPIStyle;
+ // base weight in CSS-style units, 1..1000
+ int fBaseWeight;
+
static const Typeface* resolveDefault(const Typeface* src);
// The following three functions create new Typeface from an existing Typeface with a different
@@ -81,10 +84,6 @@ public:
// Sets roboto font as the default typeface for testing purpose.
static void setRobotoTypefaceForTest();
-
-private:
- // base weight in CSS-style units, 1..1000
- int fBaseWeight;
};
}
diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp
index 7d2583a2ac01..52522a320821 100644
--- a/libs/hwui/jni/BitmapFactory.cpp
+++ b/libs/hwui/jni/BitmapFactory.cpp
@@ -67,6 +67,8 @@ const char* getMimeType(SkEncodedImageFormat format) {
return "image/webp";
case SkEncodedImageFormat::kHEIF:
return "image/heif";
+ case SkEncodedImageFormat::kAVIF:
+ return "image/avif";
case SkEncodedImageFormat::kWBMP:
return "image/vnd.wap.wbmp";
case SkEncodedImageFormat::kDNG:
diff --git a/libs/hwui/jni/RenderEffect.cpp b/libs/hwui/jni/RenderEffect.cpp
index 0ebd0ca720d8..97c40d695f97 100644
--- a/libs/hwui/jni/RenderEffect.cpp
+++ b/libs/hwui/jni/RenderEffect.cpp
@@ -48,6 +48,73 @@ static jlong createBlurEffect(JNIEnv* env , jobject, jfloat radiusX,
return reinterpret_cast<jlong>(blurFilter.release());
}
+static jlong createBitmapEffect(
+ JNIEnv* env,
+ jobject,
+ jlong bitmapHandle,
+ jfloat srcLeft,
+ jfloat srcTop,
+ jfloat srcRight,
+ jfloat srcBottom,
+ jfloat dstLeft,
+ jfloat dstTop,
+ jfloat dstRight,
+ jfloat dstBottom
+) {
+ sk_sp<SkImage> image = android::bitmap::toBitmap(bitmapHandle).makeImage();
+ SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
+ SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
+ sk_sp<SkImageFilter> bitmapFilter =
+ SkImageFilters::Image(image, srcRect, dstRect, kLow_SkFilterQuality);
+ return reinterpret_cast<jlong>(bitmapFilter.release());
+}
+
+static jlong createColorFilterEffect(
+ JNIEnv* env,
+ jobject,
+ jlong colorFilterHandle,
+ jlong inputFilterHandle
+) {
+ auto* colorFilter = reinterpret_cast<const SkColorFilter*>(colorFilterHandle);
+ auto* inputFilter = reinterpret_cast<const SkImageFilter*>(inputFilterHandle);
+ sk_sp<SkImageFilter> colorFilterImageFilter = SkImageFilters::ColorFilter(
+ sk_ref_sp(colorFilter), sk_ref_sp(inputFilter), nullptr);
+ return reinterpret_cast<jlong>(colorFilterImageFilter.release());
+}
+
+static jlong createBlendModeEffect(
+ JNIEnv* env,
+ jobject,
+ jlong backgroundImageFilterHandle,
+ jlong foregroundImageFilterHandle,
+ jint blendmodeHandle
+) {
+ auto* backgroundFilter = reinterpret_cast<const SkImageFilter*>(backgroundImageFilterHandle);
+ auto* foregroundFilter = reinterpret_cast<const SkImageFilter*>(foregroundImageFilterHandle);
+ SkBlendMode blendMode = static_cast<SkBlendMode>(blendmodeHandle);
+ sk_sp<SkImageFilter> xfermodeFilter = SkImageFilters::Blend(
+ blendMode,
+ sk_ref_sp(backgroundFilter),
+ sk_ref_sp(foregroundFilter)
+ );
+ return reinterpret_cast<jlong>(xfermodeFilter.release());
+}
+
+static jlong createChainEffect(
+ JNIEnv* env,
+ jobject,
+ jlong outerFilterHandle,
+ jlong innerFilterHandle
+) {
+ auto* outerImageFilter = reinterpret_cast<const SkImageFilter*>(outerFilterHandle);
+ auto* innerImageFilter = reinterpret_cast<const SkImageFilter*>(innerFilterHandle);
+ sk_sp<SkImageFilter> composeFilter = SkImageFilters::Compose(
+ sk_ref_sp(outerImageFilter),
+ sk_ref_sp(innerImageFilter)
+ );
+ return reinterpret_cast<jlong>(composeFilter.release());
+}
+
static void RenderEffect_safeUnref(SkImageFilter* filter) {
SkSafeUnref(filter);
}
@@ -59,7 +126,11 @@ static jlong getRenderEffectFinalizer(JNIEnv*, jobject) {
static const JNINativeMethod gRenderEffectMethods[] = {
{"nativeGetFinalizer", "()J", (void*)getRenderEffectFinalizer},
{"nativeCreateOffsetEffect", "(FFJ)J", (void*)createOffsetEffect},
- {"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect}
+ {"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect},
+ {"nativeCreateBitmapEffect", "(JFFFFFFFF)J", (void*)createBitmapEffect},
+ {"nativeCreateColorFilterEffect", "(JJ)J", (void*)createColorFilterEffect},
+ {"nativeCreateBlendModeEffect", "(JJI)J", (void*)createBlendModeEffect},
+ {"nativeCreateChainEffect", "(JJ)J", (void*)createChainEffect}
};
int register_android_graphics_RenderEffect(JNIEnv* env) {
diff --git a/libs/hwui/jni/Typeface.cpp b/libs/hwui/jni/Typeface.cpp
index 2a5f402a4fa6..dc066da36cbe 100644
--- a/libs/hwui/jni/Typeface.cpp
+++ b/libs/hwui/jni/Typeface.cpp
@@ -16,10 +16,13 @@
#include "FontUtils.h"
#include "GraphicsJNI.h"
+#include "fonts/Font.h"
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
+#include "SkData.h"
#include "SkTypeface.h"
#include <hwui/Typeface.h>
+#include <minikin/FontCollection.h>
#include <minikin/FontFamily.h>
#include <minikin/SystemFonts.h>
@@ -132,6 +135,88 @@ static void Typeface_registerGenericFamily(JNIEnv *env, jobject, jstring familyN
toTypeface(ptr)->fFontCollection);
}
+static std::function<std::shared_ptr<minikin::MinikinFont>()> readMinikinFontSkia(
+ minikin::BufferReader* reader) {
+ std::string_view fontPath = reader->readString();
+ int fontIndex = reader->read<int>();
+ const minikin::FontVariation* axesPtr;
+ uint32_t axesCount;
+ std::tie(axesPtr, axesCount) = reader->readArray<minikin::FontVariation>();
+ return [fontPath, fontIndex, axesPtr, axesCount]() -> std::shared_ptr<minikin::MinikinFont> {
+ std::string path(fontPath.data(), fontPath.size());
+ sk_sp<SkData> data = SkData::MakeFromFileName(path.c_str());
+ const void* fontPtr = data->data();
+ size_t fontSize = data->size();
+ std::vector<minikin::FontVariation> axes(axesPtr, axesPtr + axesCount);
+ std::shared_ptr<minikin::MinikinFont> minikinFont =
+ fonts::createMinikinFontSkia(std::move(data), fontPath, fontPtr, fontSize,
+ fontIndex, axes);
+ if (minikinFont == nullptr) {
+ ALOGE("Failed to create MinikinFontSkia: %s", path.c_str());
+ return nullptr;
+ }
+ return minikinFont;
+ };
+}
+
+static void writeMinikinFontSkia(minikin::BufferWriter* writer,
+ const minikin::MinikinFont* typeface) {
+ writer->writeString(typeface->GetFontPath());
+ writer->write<int>(typeface->GetFontIndex());
+ const std::vector<minikin::FontVariation>& axes = typeface->GetAxes();
+ writer->writeArray<minikin::FontVariation>(axes.data(), axes.size());
+}
+
+static jint Typeface_writeTypefaces(JNIEnv *env, jobject, jobject buffer, jlongArray faceHandles) {
+ ScopedLongArrayRO faces(env, faceHandles);
+ std::vector<Typeface*> typefaces;
+ typefaces.reserve(faces.size());
+ for (size_t i = 0; i < faces.size(); i++) {
+ typefaces.push_back(toTypeface(faces[i]));
+ }
+ void* addr = buffer == nullptr ? nullptr : env->GetDirectBufferAddress(buffer);
+ minikin::BufferWriter writer(addr);
+ std::vector<std::shared_ptr<minikin::FontCollection>> fontCollections;
+ std::unordered_map<std::shared_ptr<minikin::FontCollection>, size_t> fcToIndex;
+ for (Typeface* typeface : typefaces) {
+ bool inserted = fcToIndex.emplace(typeface->fFontCollection, fontCollections.size()).second;
+ if (inserted) {
+ fontCollections.push_back(typeface->fFontCollection);
+ }
+ }
+ minikin::FontCollection::writeVector<writeMinikinFontSkia>(&writer, fontCollections);
+ writer.write<uint32_t>(typefaces.size());
+ for (Typeface* typeface : typefaces) {
+ writer.write<uint32_t>(fcToIndex.find(typeface->fFontCollection)->second);
+ typeface->fStyle.writeTo(&writer);
+ writer.write<Typeface::Style>(typeface->fAPIStyle);
+ writer.write<int>(typeface->fBaseWeight);
+ }
+ return static_cast<jint>(writer.size());
+}
+
+static jlongArray Typeface_readTypefaces(JNIEnv *env, jobject, jobject buffer) {
+ void* addr = buffer == nullptr ? nullptr : env->GetDirectBufferAddress(buffer);
+ if (addr == nullptr) return nullptr;
+ minikin::BufferReader reader(addr);
+ std::vector<std::shared_ptr<minikin::FontCollection>> fontCollections =
+ minikin::FontCollection::readVector<readMinikinFontSkia>(&reader);
+ uint32_t typefaceCount = reader.read<uint32_t>();
+ std::vector<jlong> faceHandles;
+ faceHandles.reserve(typefaceCount);
+ for (uint32_t i = 0; i < typefaceCount; i++) {
+ Typeface* typeface = new Typeface;
+ typeface->fFontCollection = fontCollections[reader.read<uint32_t>()];
+ typeface->fStyle = minikin::FontStyle(&reader);
+ typeface->fAPIStyle = reader.read<Typeface::Style>();
+ typeface->fBaseWeight = reader.read<int>();
+ faceHandles.push_back(toJLong(typeface));
+ }
+ const jlongArray result = env->NewLongArray(typefaceCount);
+ env->SetLongArrayRegion(result, 0, typefaceCount, faceHandles.data());
+ return result;
+}
+
///////////////////////////////////////////////////////////////////////////////
static const JNINativeMethod gTypefaceMethods[] = {
@@ -150,6 +235,8 @@ static const JNINativeMethod gTypefaceMethods[] = {
{ "nativeGetSupportedAxes", "(J)[I", (void*)Typeface_getSupportedAxes },
{ "nativeRegisterGenericFamily", "(Ljava/lang/String;J)V",
(void*)Typeface_registerGenericFamily },
+ { "nativeWriteTypefaces", "(Ljava/nio/ByteBuffer;[J)I", (void*)Typeface_writeTypefaces},
+ { "nativeReadTypefaces", "(Ljava/nio/ByteBuffer;)[J", (void*)Typeface_readTypefaces},
};
int register_android_graphics_Typeface(JNIEnv* env)
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 4aee6b94a2be..f0c77930cbe3 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "Minikin"
+#include "Font.h"
#include "SkData.h"
#include "SkFont.h"
#include "SkFontMetrics.h"
@@ -95,29 +96,14 @@ static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jo
jobject fontRef = MakeGlobalRefOrDie(env, buffer);
sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
release_global_ref, reinterpret_cast<void*>(fontRef)));
-
- FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
- for (const auto& axis : builder->axes) {
- skVariation.push_back({axis.axisTag, axis.value});
- }
-
- std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
-
- SkFontArguments args;
- args.setCollectionIndex(ttcIndex);
- args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
-
- sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
- sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
- if (face == nullptr) {
+ std::shared_ptr<minikin::MinikinFont> minikinFont = fonts::createMinikinFontSkia(
+ std::move(data), std::string_view(fontPath.c_str(), fontPath.size()),
+ fontPtr, fontSize, ttcIndex, builder->axes);
+ if (minikinFont == nullptr) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"Failed to create internal object. maybe invalid font data.");
return 0;
}
- std::shared_ptr<minikin::MinikinFont> minikinFont =
- std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize,
- std::string_view(fontPath.c_str(), fontPath.size()),
- ttcIndex, builder->axes);
std::shared_ptr<minikin::Font> font = minikin::Font::Builder(minikinFont).setWeight(weight)
.setSlant(static_cast<minikin::FontStyle::Slant>(italic)).build();
return reinterpret_cast<jlong>(new FontWrapper(std::move(font)));
@@ -239,13 +225,10 @@ static jlong Font_getNativeFontPtr(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
}
// Critical Native
-static jboolean Font_isSameBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong lFontHandle,
- jlong rFontHandle) {
- FontWrapper* lFont = reinterpret_cast<FontWrapper*>(lFontHandle);
- FontWrapper* rFont = reinterpret_cast<FontWrapper*>(rFontHandle);
- const void* lBufferPtr = lFont->font->typeface()->GetFontData();
- const void* rBufferPtr = rFont->font->typeface()->GetFontData();
- return lBufferPtr == rBufferPtr;
+static jlong Font_GetBufferAddress(CRITICAL_JNI_PARAMS_COMMA jlong fontHandle) {
+ FontWrapper* font = reinterpret_cast<FontWrapper*>(fontHandle);
+ const void* bufferPtr = font->font->typeface()->GetFontData();
+ return reinterpret_cast<jlong>(bufferPtr);
}
///////////////////////////////////////////////////////////////////////////////
@@ -297,7 +280,7 @@ static const JNINativeMethod gFontMethods[] = {
{ "nGetAxisInfo", "(JI)J", (void*) Font_getAxisInfo },
{ "nGetFontPath", "(J)Ljava/lang/String;", (void*) Font_getFontPath },
{ "nGetNativeFontPtr", "(J)J", (void*) Font_getNativeFontPtr },
- { "nIsSameBufferAddress", "(JJ)Z", (void*) Font_isSameBufferAddress },
+ { "nGetFontBufferAddress", "(J)J", (void*) Font_GetBufferAddress },
};
static const JNINativeMethod gFontBufferHelperMethods[] = {
@@ -315,4 +298,31 @@ int register_android_graphics_fonts_Font(JNIEnv* env) {
gFontBufferHelperMethods, NELEM(gFontBufferHelperMethods));
}
+namespace fonts {
+
+std::shared_ptr<minikin::MinikinFont> createMinikinFontSkia(
+ sk_sp<SkData>&& data, std::string_view fontPath, const void *fontPtr, size_t fontSize,
+ int ttcIndex, const std::vector<minikin::FontVariation>& axes) {
+ FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
+ for (const auto& axis : axes) {
+ skVariation.push_back({axis.axisTag, axis.value});
+ }
+
+ std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
+
+ SkFontArguments args;
+ args.setCollectionIndex(ttcIndex);
+ args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
+
+ sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
+ sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
+ if (face == nullptr) {
+ return nullptr;
+ }
+ return std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize,
+ fontPath, ttcIndex, axes);
}
+
+} // namespace fonts
+
+} // namespace android
diff --git a/libs/hwui/jni/fonts/Font.h b/libs/hwui/jni/fonts/Font.h
new file mode 100644
index 000000000000..b5d20bf8cc3c
--- /dev/null
+++ b/libs/hwui/jni/fonts/Font.h
@@ -0,0 +1,40 @@
+/*
+ * 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 FONTS_FONT_H_
+#define FONTS_FONT_H_
+
+#include <minikin/FontVariation.h>
+#include <minikin/MinikinFont.h>
+#include <SkRefCnt.h>
+
+#include <string_view>
+#include <vector>
+
+class SkData;
+
+namespace android {
+
+namespace fonts {
+
+std::shared_ptr<minikin::MinikinFont> createMinikinFontSkia(
+ sk_sp<SkData>&& data, std::string_view fontPath, const void *fontPtr, size_t fontSize,
+ int ttcIndex, const std::vector<minikin::FontVariation>& axes);
+
+} // namespace fonts
+
+} // namespace android
+
+#endif /* FONTS_FONT_H_ */
diff --git a/libs/hwui/tests/common/CallCountingCanvas.h b/libs/hwui/tests/common/CallCountingCanvas.h
new file mode 100644
index 000000000000..594afd04860b
--- /dev/null
+++ b/libs/hwui/tests/common/CallCountingCanvas.h
@@ -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.
+ */
+
+#pragma once
+
+#include <SkCanvasVirtualEnforcer.h>
+#include <SkNoDrawCanvas.h>
+
+namespace android {
+namespace uirenderer {
+namespace test {
+
+class CallCountingCanvas final : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> {
+private:
+ int START_MARKER;
+public:
+ CallCountingCanvas() : SkCanvasVirtualEnforcer<SkNoDrawCanvas>(1, 1) {}
+
+ int sumTotalDrawCalls() {
+ // Dirty hack assumes we're nothing but ints between START_MARKET and END_MARKER
+ int* cur = &START_MARKER + 1;
+ int* end = &END_MARKER;
+ int sum = 0;
+ while (cur != end) {
+ sum += *cur;
+ cur++;
+ }
+ return sum;
+ }
+
+ int drawPaintCount = 0;
+ void onDrawPaint(const SkPaint& paint) override {
+ drawPaintCount++;
+ }
+
+ int drawBehindCount = 0;
+ void onDrawBehind(const SkPaint&) override {
+ drawBehindCount++;
+ }
+
+ int drawRectCount = 0;
+ void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
+ drawRectCount++;
+ }
+
+ int drawRRectCount = 0;
+ void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
+ drawRRectCount++;
+ }
+
+ int drawDRRectCount = 0;
+ void onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
+ const SkPaint& paint) override {
+ drawDRRectCount++;
+ }
+
+ int drawOvalCount = 0;
+ void onDrawOval(const SkRect& rect, const SkPaint& paint) override {
+ drawOvalCount++;
+ }
+
+ int drawArcCount = 0;
+ void onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
+ const SkPaint& paint) override {
+ drawArcCount++;
+ }
+
+ int drawPathCount = 0;
+ void onDrawPath(const SkPath& path, const SkPaint& paint) override {
+ drawPathCount++;
+ }
+
+ int drawRegionCount = 0;
+ void onDrawRegion(const SkRegion& region, const SkPaint& paint) override {
+ drawRegionCount++;
+ }
+
+ int drawTextBlobCount = 0;
+ void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+ const SkPaint& paint) override {
+ drawTextBlobCount++;
+ }
+
+ int drawPatchCount = 0;
+ void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkBlendMode mode,
+ const SkPaint& paint) override {
+ drawPatchCount++;
+ }
+
+ int drawPoints = 0;
+ void onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[],
+ const SkPaint& paint) override {
+ drawPoints++;
+ }
+
+ int drawImageCount = 0;
+ void onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy,
+ const SkPaint* paint) override {
+ drawImageCount++;
+ }
+
+ int drawImageRectCount = 0;
+ void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
+ const SkPaint* paint, SkCanvas::SrcRectConstraint constraint) override {
+ drawImageRectCount++;
+ }
+
+ int drawImageNineCount = 0;
+ void onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
+ const SkPaint* paint) override {
+ drawImageNineCount++;
+ }
+
+ int drawImageLatticeCount = 0;
+ void onDrawImageLattice(const SkImage* image, const SkCanvas::Lattice& lattice,
+ const SkRect& dst, const SkPaint* paint) override {
+ drawImageLatticeCount++;
+ }
+
+ int drawAtlasCount = 0;
+ void onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect rect[],
+ const SkColor colors[], int count, SkBlendMode mode, const SkRect* cull,
+ const SkPaint* paint) override {
+ drawAtlasCount++;
+ }
+
+ int drawAnnotationCount = 0;
+ void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override {
+ drawAnnotationCount++;
+ }
+
+ int drawShadowRecCount = 0;
+ void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override {
+ drawShadowRecCount++;
+ }
+
+ int drawDrawableCount = 0;
+ void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
+ drawDrawableCount++;
+ }
+
+ int drawPictureCount = 0;
+ void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+ const SkPaint* paint) override {
+ drawPictureCount++;
+ }
+
+ int drawVerticesCount = 0;
+ void onDrawVerticesObject (const SkVertices *vertices, SkBlendMode mode,
+ const SkPaint &paint) override {
+ drawVerticesCount++;
+ }
+
+private:
+ int END_MARKER;
+};
+
+} /* namespace test */
+} /* namespace uirenderer */
+} /* namespace android */ \ No newline at end of file
diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp
new file mode 100644
index 000000000000..b15c3221dd60
--- /dev/null
+++ b/libs/hwui/tests/unit/CanvasOpTests.cpp
@@ -0,0 +1,617 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <canvas/CanvasOpBuffer.h>
+#include <canvas/CanvasOps.h>
+#include <canvas/CanvasOpRasterizer.h>
+
+#include <tests/common/CallCountingCanvas.h>
+
+#include "SkPictureRecorder.h"
+#include "SkColor.h"
+#include "SkLatticeIter.h"
+#include "pipeline/skia/AnimatedDrawables.h"
+
+using namespace android;
+using namespace android::uirenderer;
+using namespace android::uirenderer::test;
+
+// We lazy
+using Op = CanvasOpType;
+
+enum MockTypes {
+ Lifecycle,
+ COUNT
+};
+
+template<MockTypes T>
+struct MockOp;
+
+template<MockTypes T>
+struct MockOpContainer {
+ OpBufferItemHeader<MockTypes> header;
+ MockOp<T> impl;
+};
+
+struct LifecycleTracker {
+ int ctor_count = 0;
+ int dtor_count = 0;
+
+ int alive() { return ctor_count - dtor_count; }
+};
+
+template<>
+struct MockOp<MockTypes::Lifecycle> {
+ MockOp() = delete;
+ void operator=(const MockOp&) = delete;
+
+ MockOp(LifecycleTracker* tracker) : tracker(tracker) {
+ tracker->ctor_count += 1;
+ }
+
+ MockOp(const MockOp& other) {
+ tracker = other.tracker;
+ tracker->ctor_count += 1;
+ }
+
+ ~MockOp() {
+ tracker->dtor_count += 1;
+ }
+
+ LifecycleTracker* tracker = nullptr;
+};
+
+using MockBuffer = OpBuffer<MockTypes, MockOpContainer>;
+
+template<typename T>
+static int countItems(const T& t) {
+ int count = 0;
+ t.for_each([&](auto i) {
+ count++;
+ });
+ return count;
+}
+
+TEST(CanvasOp, lifecycleCheck) {
+ LifecycleTracker tracker;
+ {
+ MockBuffer buffer;
+ buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
+ .impl = MockOp<MockTypes::Lifecycle>{&tracker}
+ });
+ EXPECT_EQ(tracker.alive(), 1);
+ buffer.clear();
+ EXPECT_EQ(tracker.alive(), 0);
+ }
+ EXPECT_EQ(tracker.alive(), 0);
+}
+
+TEST(CanvasOp, lifecycleCheckMove) {
+ LifecycleTracker tracker;
+ {
+ MockBuffer buffer;
+ buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
+ .impl = MockOp<MockTypes::Lifecycle>{&tracker}
+ });
+ EXPECT_EQ(tracker.alive(), 1);
+ {
+ MockBuffer other(std::move(buffer));
+ EXPECT_EQ(tracker.alive(), 1);
+ EXPECT_EQ(buffer.size(), 0);
+ EXPECT_GT(other.size(), 0);
+ EXPECT_EQ(1, countItems(other));
+ EXPECT_EQ(0, countItems(buffer));
+
+ other.push_container(MockOpContainer<MockTypes::Lifecycle> {
+ .impl = MockOp<MockTypes::Lifecycle>{&tracker}
+ });
+
+ EXPECT_EQ(2, countItems(other));
+ EXPECT_EQ(2, tracker.alive());
+
+ buffer.push_container(MockOpContainer<MockTypes::Lifecycle> {
+ .impl = MockOp<MockTypes::Lifecycle>{&tracker}
+ });
+ EXPECT_EQ(1, countItems(buffer));
+ EXPECT_EQ(3, tracker.alive());
+
+ buffer = std::move(other);
+ EXPECT_EQ(2, countItems(buffer));
+ EXPECT_EQ(2, tracker.alive());
+ }
+ EXPECT_EQ(2, countItems(buffer));
+ EXPECT_EQ(2, tracker.alive());
+ buffer.clear();
+ EXPECT_EQ(0, countItems(buffer));
+ EXPECT_EQ(0, tracker.alive());
+ }
+ EXPECT_EQ(tracker.alive(), 0);
+}
+
+TEST(CanvasOp, verifyConst) {
+ CanvasOpBuffer buffer;
+ buffer.push<Op::DrawColor>({
+ .color = SkColors::kBlack,
+ .mode = SkBlendMode::kSrcOver,
+ });
+ buffer.for_each([](auto op) {
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(*op)>>,
+ "Expected container to be const");
+ static_assert(std::is_const_v<std::remove_reference_t<decltype(op->op())>>,
+ "Expected op to be const");
+ });
+}
+
+TEST(CanvasOp, simplePush) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ buffer.push<Op::Save>({});
+ buffer.push<Op::Save>({});
+ buffer.push<Op::Restore>({});
+ EXPECT_GT(buffer.size(), 0);
+
+ int saveCount = 0;
+ int restoreCount = 0;
+ int otherCount = 0;
+
+ buffer.for_each([&](auto op) {
+ switch (op->type()) {
+ case Op::Save:
+ saveCount++;
+ break;
+ case Op::Restore:
+ restoreCount++;
+ break;
+ default:
+ otherCount++;
+ break;
+ }
+ });
+
+ EXPECT_EQ(saveCount, 2);
+ EXPECT_EQ(restoreCount, 1);
+ EXPECT_EQ(otherCount, 0);
+
+ buffer.clear();
+ int itemCount = 0;
+ buffer.for_each([&](auto op) {
+ itemCount++;
+ });
+ EXPECT_EQ(itemCount, 0);
+ buffer.resize(0);
+ EXPECT_EQ(buffer.size(), 0);
+}
+
+TEST(CanvasOp, simpleDrawPaint) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ buffer.push<Op::DrawColor> ({
+ .color = SkColor4f{1, 1, 1, 1},
+ .mode = SkBlendMode::kSrcIn
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawPaintCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawPoint) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ buffer.push<Op::DrawPoint> ({
+ .x = 12,
+ .y = 42,
+ .paint = SkPaint{}
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawPoints);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawLine) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ buffer.push<Op::DrawLine> ({
+ .startX = 16,
+ .startY = 28,
+ .endX = 12,
+ .endY = 30,
+ .paint = SkPaint{}
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawPoints);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawRect) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ buffer.push<Op::DrawRect> ({
+ .paint = SkPaint{},
+ .rect = SkRect::MakeEmpty()
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawRectCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawRegionRect) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ SkRegion region;
+ region.setRect(SkIRect::MakeWH(12, 50));
+ buffer.push<Op::DrawRegion> ({
+ .paint = SkPaint{},
+ .region = region
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ // If the region is a rectangle, drawRegion calls into drawRect as a fast path
+ EXPECT_EQ(1, canvas.drawRectCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawRegionPath) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ SkPath path;
+ path.addCircle(50, 50, 50);
+ SkRegion clip;
+ clip.setRect(SkIRect::MakeWH(100, 100));
+ SkRegion region;
+ region.setPath(path, clip);
+ buffer.push<Op::DrawRegion> ({
+ .paint = SkPaint{},
+ .region = region
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawRegionCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawRoundRect) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ buffer.push<Op::DrawRoundRect> ({
+ .paint = SkPaint{},
+ .rect = SkRect::MakeEmpty(),
+ .rx = 10,
+ .ry = 10
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawRRectCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawDoubleRoundRect) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ SkRect outer = SkRect::MakeLTRB(0, 0, 100, 100);
+ SkRect inner = SkRect::MakeLTRB(20, 20, 80, 80);
+
+ const int numPts = 4;
+ SkRRect outerRRect;
+
+ auto outerPts = std::make_unique<SkVector[]>(numPts);
+ outerPts[0].set(32, 16);
+ outerPts[1].set(48, 48);
+ outerPts[2].set(16, 32);
+ outerPts[3].set(20, 20);
+ outerRRect.setRectRadii(outer, outerPts.get());
+ outerRRect.setRect(outer);
+
+ SkRRect innerRRect;
+ auto innerPts = std::make_unique<SkVector[]>(numPts);
+ innerPts[0].set(16, 8);
+ innerPts[1].set(24, 24);
+ innerPts[2].set(8, 16);
+ innerPts[3].set(10, 10);
+ innerRRect.setRectRadii(inner, innerPts.get());
+
+ buffer.push<Op::DrawDoubleRoundRect> ({
+ .outer = outerRRect,
+ .inner = innerRRect,
+ .paint = SkPaint{}
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawDRRectCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawCircle) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ buffer.push<Op::DrawCircle>({
+ .cx = 5,
+ .cy = 7,
+ .radius = 10,
+ .paint = SkPaint{}
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawOvalCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawOval) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ buffer.push<Op::DrawOval> ({
+ .oval = SkRect::MakeEmpty(),
+ .paint = SkPaint{}
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawOvalCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawArc) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ buffer.push<Op::DrawArc>({
+ .oval = SkRect::MakeWH(100, 100),
+ .startAngle = 120,
+ .sweepAngle = 70,
+ .useCenter = true,
+ .paint = SkPaint{}
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawArcCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawPath) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+ SkPath path;
+ path.addCircle(50, 50, 30);
+ buffer.push<Op::DrawPath> ({
+ .path = path,
+ .paint = SkPaint{}
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawPathCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawRoundRectProperty) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+
+ auto left = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1));
+ auto top = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2));
+ auto right = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(3));
+ auto bottom = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(4));
+ auto radiusX = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5));
+ auto radiusY = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(6));
+ auto propertyPaint =
+ sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{}));
+
+ buffer.push<Op::DrawRoundRectProperty> ({
+ .left = left,
+ .top = top,
+ .right = right,
+ .bottom = bottom,
+ .rx = radiusX,
+ .ry = radiusY,
+ .paint = propertyPaint
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawRRectCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawCircleProperty) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+
+ auto x = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(1));
+ auto y = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(2));
+ auto radius = sp<CanvasPropertyPrimitive>(new uirenderer::CanvasPropertyPrimitive(5));
+ auto propertyPaint =
+ sp<uirenderer::CanvasPropertyPaint>(new uirenderer::CanvasPropertyPaint(SkPaint{}));
+
+ buffer.push<Op::DrawCircleProperty> ({
+ .x = x,
+ .y = y,
+ .radius = radius,
+ .paint = propertyPaint
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawOvalCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawVertices) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+
+ SkPoint pts[3] = {{64, 32}, {0, 224}, {128, 224}};
+ SkColor colors[3] = {SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN};
+ sk_sp<SkVertices> vertices = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, 3, pts,
+ nullptr, colors);
+ buffer.push<Op::DrawVertices> ({
+ .vertices = vertices,
+ .mode = SkBlendMode::kSrcOver,
+ .paint = SkPaint{}
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawVerticesCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawImage) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+
+ SkImageInfo info =SkImageInfo::Make(5, 1,
+ kGray_8_SkColorType, kOpaque_SkAlphaType);
+ sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info);
+ buffer.push<Op::DrawImage> ({
+ bitmap,
+ 7,
+ 19,
+ SkPaint{}
+ }
+ );
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawImageCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawImageRect) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+
+ SkImageInfo info = SkImageInfo::Make(5, 1,
+ kGray_8_SkColorType, kOpaque_SkAlphaType);
+
+ sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info);
+ buffer.push<Op::DrawImageRect> ({
+ bitmap, SkRect::MakeWH(100, 100),
+ SkRect::MakeLTRB(120, 110, 220, 210),
+ SkPaint{}
+ }
+ );
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawImageRectCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawImageLattice) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+
+ SkBitmap skBitmap;
+ skBitmap.allocPixels(SkImageInfo::MakeN32Premul(60, 60));
+
+ const int xDivs[] = { 20, 50 };
+ const int yDivs[] = { 10, 40 };
+ SkCanvas::Lattice::RectType fillTypes[3][3];
+ memset(fillTypes, 0, sizeof(fillTypes));
+ fillTypes[1][1] = SkCanvas::Lattice::kTransparent;
+ SkColor colors[9];
+ SkCanvas::Lattice lattice = { xDivs, yDivs, fillTypes[0], 2,
+ 2, nullptr, colors };
+ sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(&skBitmap);
+ buffer.push<Op::DrawImageLattice>(
+ {
+ bitmap,
+ SkRect::MakeWH(5, 1),
+ lattice,
+ SkPaint{}
+ }
+ );
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ EXPECT_EQ(1, canvas.drawImageLatticeCount);
+ EXPECT_EQ(1, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, simpleDrawPicture) {
+ CanvasOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0);
+
+ SkPictureRecorder recorder;
+ SkCanvas* pictureCanvas = recorder.beginRecording({64, 64, 192, 192});
+ SkPaint paint;
+ pictureCanvas->drawRect(SkRect::MakeWH(200, 200), paint);
+ paint.setColor(SK_ColorWHITE);
+ pictureCanvas->drawRect(SkRect::MakeLTRB(20, 20, 180, 180), paint);
+ sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
+ buffer.push<Op::DrawPicture> ({
+ .picture = picture
+ });
+
+ CallCountingCanvas canvas;
+ EXPECT_EQ(0, canvas.sumTotalDrawCalls());
+ rasterizeCanvasBuffer(buffer, &canvas);
+ // Note because we are explicitly issuing 2 drawRect calls
+ // in the picture recorder above, when it is played back into
+ // CallCountingCanvas we will see 2 calls to drawRect instead of 1
+ // call to drawPicture.
+ // This is because SkiaCanvas::drawPicture uses picture.playback(canvas)
+ // instead of canvas->drawPicture.
+ EXPECT_EQ(2, canvas.drawRectCount);
+ EXPECT_EQ(2, canvas.sumTotalDrawCalls());
+}
+
+TEST(CanvasOp, immediateRendering) {
+ auto canvas = std::make_shared<CallCountingCanvas>();
+
+ EXPECT_EQ(0, canvas->sumTotalDrawCalls());
+ ImmediateModeRasterizer rasterizer{canvas};
+ auto op = CanvasOp<Op::DrawRect> {
+ .paint = SkPaint{},
+ .rect = SkRect::MakeEmpty()
+ };
+ EXPECT_TRUE(CanvasOpTraits::can_draw<decltype(op)>);
+ rasterizer.draw(op);
+ EXPECT_EQ(1, canvas->drawRectCount);
+ EXPECT_EQ(1, canvas->sumTotalDrawCalls());
+} \ No newline at end of file
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index 704cdbfc77b1..307fb8783c51 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -21,6 +21,8 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import com.android.internal.util.Preconditions;
+
import java.io.IOException;
import java.util.Collections;
import java.util.List;
@@ -77,12 +79,9 @@ public final class Geocoder {
* @throws NullPointerException if Locale is null
*/
public Geocoder(Context context, Locale locale) {
- if (locale == null) {
- throw new NullPointerException("locale == null");
- }
mParams = new GeocoderParams(context, locale);
- IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
- mService = ILocationManager.Stub.asInterface(b);
+ mService = ILocationManager.Stub.asInterface(
+ ServiceManager.getService(Context.LOCATION_SERVICE));
}
/**
@@ -121,13 +120,10 @@ public final class Geocoder {
* I/O problem occurs
*/
public List<Address> getFromLocation(double latitude, double longitude, int maxResults)
- throws IOException {
- if (latitude < -90.0 || latitude > 90.0) {
- throw new IllegalArgumentException("latitude == " + latitude);
- }
- if (longitude < -180.0 || longitude > 180.0) {
- throw new IllegalArgumentException("longitude == " + longitude);
- }
+ throws IOException {
+ Preconditions.checkArgumentInRange(latitude, -90.0, 90.0, "latitude");
+ Preconditions.checkArgumentInRange(longitude, -180.0, 180.0, "longitude");
+
try {
GeocodeListener listener = new GeocodeListener();
mService.getFromLocation(latitude, longitude, maxResults, mParams, listener);
@@ -161,17 +157,7 @@ public final class Geocoder {
* I/O problem occurs
*/
public List<Address> getFromLocationName(String locationName, int maxResults) throws IOException {
- if (locationName == null) {
- throw new IllegalArgumentException("locationName == null");
- }
-
- try {
- GeocodeListener listener = new GeocodeListener();
- mService.getFromLocationName(locationName, 0, 0, 0, 0, maxResults, mParams, listener);
- return listener.getResults();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getFromLocationName(locationName, maxResults, 0, 0, 0, 0);
}
/**
@@ -210,27 +196,14 @@ public final class Geocoder {
* I/O problem occurs
*/
public List<Address> getFromLocationName(String locationName, int maxResults,
- double lowerLeftLatitude, double lowerLeftLongitude,
- double upperRightLatitude, double upperRightLongitude) throws IOException {
- if (locationName == null) {
- throw new IllegalArgumentException("locationName == null");
- }
- if (lowerLeftLatitude < -90.0 || lowerLeftLatitude > 90.0) {
- throw new IllegalArgumentException("lowerLeftLatitude == "
- + lowerLeftLatitude);
- }
- if (lowerLeftLongitude < -180.0 || lowerLeftLongitude > 180.0) {
- throw new IllegalArgumentException("lowerLeftLongitude == "
- + lowerLeftLongitude);
- }
- if (upperRightLatitude < -90.0 || upperRightLatitude > 90.0) {
- throw new IllegalArgumentException("upperRightLatitude == "
- + upperRightLatitude);
- }
- if (upperRightLongitude < -180.0 || upperRightLongitude > 180.0) {
- throw new IllegalArgumentException("upperRightLongitude == "
- + upperRightLongitude);
- }
+ double lowerLeftLatitude, double lowerLeftLongitude, double upperRightLatitude,
+ double upperRightLongitude) throws IOException {
+ Preconditions.checkArgument(locationName != null);
+ Preconditions.checkArgumentInRange(lowerLeftLatitude, -90.0, 90.0, "lowerLeftLatitude");
+ Preconditions.checkArgumentInRange(lowerLeftLongitude, -180.0, 180.0, "lowerLeftLongitude");
+ Preconditions.checkArgumentInRange(upperRightLatitude, -90.0, 90.0, "upperRightLatitude");
+ Preconditions.checkArgumentInRange(upperRightLongitude, -180.0, 180.0,
+ "upperRightLongitude");
try {
GeocodeListener listener = new GeocodeListener();
diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java
index 1c6e9b6e1836..b00a9a99e75d 100644
--- a/location/java/android/location/GeocoderParams.java
+++ b/location/java/android/location/GeocoderParams.java
@@ -16,12 +16,16 @@
package android.location;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import java.util.Locale;
+import java.util.Objects;
/**
* This class contains extra parameters to pass to an IGeocodeProvider
@@ -34,64 +38,88 @@ import java.util.Locale;
* @hide
*/
public class GeocoderParams implements Parcelable {
- private Locale mLocale;
- private String mPackageName;
- // used only for parcelling
- private GeocoderParams() {
+ private final int mUid;
+ private final String mPackageName;
+ private final @Nullable String mAttributionTag;
+ private final Locale mLocale;
+
+ public GeocoderParams(Context context) {
+ this(context, Locale.getDefault());
}
- /**
- * This object is only constructed by the Geocoder class
- *
- * @hide
- */
public GeocoderParams(Context context, Locale locale) {
- mLocale = locale;
- mPackageName = context.getPackageName();
+ this(Process.myUid(), context.getPackageName(), context.getAttributionTag(), locale);
+ }
+
+ private GeocoderParams(int uid, String packageName, String attributionTag, Locale locale) {
+ mUid = uid;
+ mPackageName = Objects.requireNonNull(packageName);
+ mAttributionTag = attributionTag;
+ mLocale = Objects.requireNonNull(locale);
}
/**
- * returns the Geocoder's locale
+ * Returns the client UID.
*/
@UnsupportedAppUsage
- public Locale getLocale() {
- return mLocale;
+ public int getClientUid() {
+ return mUid;
}
/**
- * returns the package name of the Geocoder's client
+ * Returns the client package name.
*/
@UnsupportedAppUsage
- public String getClientPackage() {
+ public @NonNull String getClientPackage() {
return mPackageName;
}
- public static final @android.annotation.NonNull Parcelable.Creator<GeocoderParams> CREATOR =
+ /**
+ * Returns the client attribution tag.
+ */
+ @UnsupportedAppUsage
+ public @Nullable String getClientAttributionTag() {
+ return mAttributionTag;
+ }
+
+ /**
+ * Returns the locale.
+ */
+ @UnsupportedAppUsage
+ public @NonNull Locale getLocale() {
+ return mLocale;
+ }
+
+ public static final @NonNull Parcelable.Creator<GeocoderParams> CREATOR =
new Parcelable.Creator<GeocoderParams>() {
- public GeocoderParams createFromParcel(Parcel in) {
- GeocoderParams gp = new GeocoderParams();
- String language = in.readString();
- String country = in.readString();
- String variant = in.readString();
- gp.mLocale = new Locale(language, country, variant);
- gp.mPackageName = in.readString();
- return gp;
- }
-
- public GeocoderParams[] newArray(int size) {
- return new GeocoderParams[size];
- }
- };
+ public GeocoderParams createFromParcel(Parcel in) {
+ int uid = in.readInt();
+ String packageName = in.readString();
+ String attributionTag = in.readString();
+ String language = in.readString();
+ String country = in.readString();
+ String variant = in.readString();
+
+ return new GeocoderParams(uid, packageName, attributionTag,
+ new Locale(language, country, variant));
+ }
+
+ public GeocoderParams[] newArray(int size) {
+ return new GeocoderParams[size];
+ }
+ };
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mUid);
+ parcel.writeString(mPackageName);
+ parcel.writeString(mAttributionTag);
parcel.writeString(mLocale.getLanguage());
parcel.writeString(mLocale.getCountry());
parcel.writeString(mLocale.getVariant());
- parcel.writeString(mPackageName);
}
}
diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java
index 5734bf2e9af6..bbb5bb8fa3a7 100644
--- a/location/java/android/location/GnssCapabilities.java
+++ b/location/java/android/location/GnssCapabilities.java
@@ -29,10 +29,10 @@ public final class GnssCapabilities {
public static final long LOW_POWER_MODE = 1L << 0;
/**
- * Bit mask indicating GNSS chipset supports blacklisting satellites.
+ * Bit mask indicating GNSS chipset supports blocklisting satellites.
* @hide
*/
- public static final long SATELLITE_BLACKLIST = 1L << 1;
+ public static final long SATELLITE_BLOCKLIST = 1L << 1;
/**
* Bit mask indicating GNSS chipset supports geofencing.
@@ -110,14 +110,27 @@ public final class GnssCapabilities {
}
/**
- * Returns {@code true} if GNSS chipset supports blacklisting satellites, {@code false}
+ * Returns {@code true} if GNSS chipset supports blocklisting satellites, {@code false}
* otherwise.
*
* @hide
+ * @deprecated use {@link #hasSatelliteBlocklist} instead.
*/
@SystemApi
+ @Deprecated
public boolean hasSatelliteBlacklist() {
- return hasCapability(SATELLITE_BLACKLIST);
+ return hasCapability(SATELLITE_BLOCKLIST);
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports blocklisting satellites, {@code false}
+ * otherwise.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean hasSatelliteBlocklist() {
+ return hasCapability(SATELLITE_BLOCKLIST);
}
/**
diff --git a/location/java/android/location/ILocationListener.aidl b/location/java/android/location/ILocationListener.aidl
index 29b483af8721..ce92661cb87c 100644
--- a/location/java/android/location/ILocationListener.aidl
+++ b/location/java/android/location/ILocationListener.aidl
@@ -16,7 +16,7 @@
package android.location;
-import android.location.Location;
+import android.location.LocationResult;
import android.os.IRemoteCallback;
/**
@@ -24,6 +24,7 @@ import android.os.IRemoteCallback;
*/
oneway interface ILocationListener
{
- void onLocationChanged(in Location location, in @nullable IRemoteCallback onCompleteCallback);
+ void onLocationChanged(in LocationResult locationResult, in @nullable IRemoteCallback onCompleteCallback);
void onProviderEnabledChanged(String provider, boolean enabled);
+ void onFlushComplete(int requestCode);
}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 3905e0b2b878..d3dc3b32e15d 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -23,7 +23,6 @@ import android.location.GeocoderParams;
import android.location.Geofence;
import android.location.GnssMeasurementCorrections;
import android.location.GnssRequest;
-import android.location.IBatchedLocationCallback;
import android.location.IGeocodeListener;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
@@ -53,10 +52,13 @@ interface ILocationManager
void unregisterLocationListener(in ILocationListener listener);
void registerLocationPendingIntent(String provider, in LocationRequest request, in PendingIntent pendingIntent, String packageName, String attributionTag);
- void unregisterLocationPendingIntent(in PendingIntent intent);
+ void unregisterLocationPendingIntent(in PendingIntent pendingIntent);
void injectLocation(in Location location);
+ void requestListenerFlush(String provider, in ILocationListener listener, int requestCode);
+ void requestPendingIntentFlush(String provider, in PendingIntent pendingIntent, int requestCode);
+
void requestGeofence(in Geofence geofence, in PendingIntent intent, String packageName, String attributionTag);
void removeGeofence(in PendingIntent intent);
@@ -86,9 +88,7 @@ interface ILocationManager
void removeGnssNavigationMessageListener(in IGnssNavigationMessageListener listener);
int getGnssBatchSize();
- void setGnssBatchingCallback(in IBatchedLocationCallback callback, String packageName, String attributionTag);
- void removeGnssBatchingCallback();
- void startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName, String attributionTag);
+ void startGnssBatch(long periodNanos, in ILocationListener listener, String packageName, String attributionTag, String listenerId);
void flushGnssBatch();
void stopGnssBatch();
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 20175d70e735..b4392b1d29b4 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -18,6 +18,7 @@ package android.location;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
@@ -29,20 +30,22 @@ import android.util.Printer;
import android.util.TimeUtils;
import java.text.DecimalFormat;
+import java.util.Locale;
+import java.util.Objects;
import java.util.StringTokenizer;
/**
* A data class representing a geographic location.
*
- * <p>A location can consist of a latitude, longitude, timestamp,
- * and other information such as bearing, altitude and velocity.
+ * <p>A location may consist of a latitude, longitude, timestamp, and other information such as
+ * bearing, altitude and velocity.
*
- * <p>All locations generated by the {@link LocationManager} are
- * guaranteed to have a valid latitude, longitude, and timestamp
- * (both UTC time and elapsed real-time since boot), all other
+ * <p>All locations generated through {@link LocationManager} are guaranteed to have a valid
+ * latitude, longitude, and timestamp (both UTC time and elapsed real-time since boot). All other
* parameters are optional.
*/
public class Location implements Parcelable {
+
/**
* Constant used to specify formatting of a latitude or longitude
* in the form "[+-]DDD.DDDDD where D indicates degrees.
@@ -78,58 +81,26 @@ public class Location implements Parcelable {
@Deprecated
public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
- /**
- * Bit mask for mFieldsMask indicating the presence of mAltitude.
- */
- private static final int HAS_ALTITUDE_MASK = 1;
- /**
- * Bit mask for mFieldsMask indicating the presence of mSpeed.
- */
- private static final int HAS_SPEED_MASK = 2;
- /**
- * Bit mask for mFieldsMask indicating the presence of mBearing.
- */
- private static final int HAS_BEARING_MASK = 4;
- /**
- * Bit mask for mFieldsMask indicating the presence of mHorizontalAccuracy.
- */
- private static final int HAS_HORIZONTAL_ACCURACY_MASK = 8;
- /**
- * Bit mask for mFieldsMask indicating location is from a mock provider.
- */
- private static final int HAS_MOCK_PROVIDER_MASK = 16;
- /**
- * Bit mask for mFieldsMask indicating the presence of mVerticalAccuracy.
- */
- private static final int HAS_VERTICAL_ACCURACY_MASK = 32;
- /**
- * Bit mask for mFieldsMask indicating the presence of mSpeedAccuracy.
- */
- private static final int HAS_SPEED_ACCURACY_MASK = 64;
- /**
- * Bit mask for mFieldsMask indicating the presence of mBearingAccuracy.
- */
- private static final int HAS_BEARING_ACCURACY_MASK = 128;
- /**
- * Bit mask for mFieldsMask indicating the presence of mElapsedRealtimeUncertaintyNanos.
- */
- private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK = 256;
+ private static final int HAS_ALTITUDE_MASK = 1 << 0;
+ private static final int HAS_SPEED_MASK = 1 << 1;
+ private static final int HAS_BEARING_MASK = 1 << 2;
+ private static final int HAS_HORIZONTAL_ACCURACY_MASK = 1 << 3;
+ private static final int HAS_MOCK_PROVIDER_MASK = 1 << 4;
+ private static final int HAS_VERTICAL_ACCURACY_MASK = 1 << 5;
+ private static final int HAS_SPEED_ACCURACY_MASK = 1 << 6;
+ private static final int HAS_BEARING_ACCURACY_MASK = 1 << 7;
+ private static final int HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK = 1 << 8;
// Cached data to make bearing/distance computations more efficient for the case
// where distanceTo and bearingTo are called in sequence. Assume this typically happens
// on the same thread for caching purposes.
- private static ThreadLocal<BearingDistanceCache> sBearingDistanceCache
- = new ThreadLocal<BearingDistanceCache>() {
- @Override
- protected BearingDistanceCache initialValue() {
- return new BearingDistanceCache();
- }
- };
+ private static final ThreadLocal<BearingDistanceCache> sBearingDistanceCache =
+ ThreadLocal.withInitial(BearingDistanceCache::new);
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mProvider;
private long mTime = 0;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
+ publicAlternatives = "{@link #getElapsedRealtimeNanos()}")
private long mElapsedRealtimeNanos = 0;
// Estimate of the relative precision of the alignment of this SystemClock
// timestamp, with the reported measurements in nanoseconds (68% confidence).
@@ -227,8 +198,7 @@ public class Location implements Parcelable {
* FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS.
*/
public static String convert(double coordinate, int outputType) {
- if (coordinate < -180.0 || coordinate > 180.0 ||
- Double.isNaN(coordinate)) {
+ if (coordinate < -180.0 || coordinate > 180.0 || Double.isNaN(coordinate)) {
throw new IllegalArgumentException("coordinate=" + coordinate);
}
if ((outputType != FORMAT_DEGREES) &&
@@ -374,10 +344,10 @@ public class Location implements Parcelable {
double sigma = 0.0;
double deltaSigma = 0.0;
- double cosSqAlpha = 0.0;
- double cos2SM = 0.0;
- double cosSigma = 0.0;
- double sinSigma = 0.0;
+ double cosSqAlpha;
+ double cos2SM;
+ double cosSigma;
+ double sinSigma;
double cosLambda = 0.0;
double sinLambda = 0.0;
@@ -428,8 +398,7 @@ public class Location implements Parcelable {
}
}
- float distance = (float) (b * A * (sigma - deltaSigma));
- results.mDistance = distance;
+ results.mDistance = (float) (b * A * (sigma - deltaSigma));
float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
initialBearing *= 180.0 / Math.PI;
@@ -536,29 +505,26 @@ public class Location implements Parcelable {
}
/**
- * Return the UTC time of this fix, in milliseconds since January 1, 1970.
+ * Return the UTC time of this location fix, in milliseconds since epoch (January 1, 1970).
*
- * <p>Note that the UTC time on a device is not monotonic: it
- * can jump forwards or backwards unpredictably. So always use
- * {@link #getElapsedRealtimeNanos} when calculating time deltas.
+ * <p>Note that the UTC time on a device is not monotonic; it can jump forwards or backwards
+ * unpredictably, so this time should not be used to calculate time deltas between locations.
+ * Instead prefer {@link #getElapsedRealtimeNanos} for that purpose.
*
- * <p>On the other hand, {@link #getTime} is useful for presenting
- * a human readable time to the user, or for carefully comparing
- * location fixes across reboot or across devices.
+ * <p>On the other hand, this method is useful for presenting a human readable time to the user,
+ * or for carefully comparing location fixes across reboot or across devices.
*
- * <p>All locations generated by the {@link LocationManager}
- * are guaranteed to have a valid UTC time, however remember that
- * the system time may have changed since the location was generated.
+ * <p>All locations generated by the {@link LocationManager} are guaranteed to have a UTC time,
+ * however remember that the system time may have changed since the location was generated.
*
- * @return time of fix, in milliseconds since January 1, 1970.
+ * @return UTC time of fix, in milliseconds since January 1, 1970.
*/
public long getTime() {
return mTime;
}
/**
- * Set the UTC time of this fix, in milliseconds since January 1,
- * 1970.
+ * Set the UTC time of this fix, in milliseconds since epoch (January 1, 1970).
*
* @param time UTC time of this fix, in milliseconds since January 1, 1970
*/
@@ -886,18 +852,15 @@ public class Location implements Parcelable {
/**
* Get the estimated vertical accuracy of this location, in meters.
*
- * <p>We define vertical accuracy at 68% confidence. Specifically, as 1-side of the
- * 2-sided range above and below the estimated altitude reported by {@link #getAltitude()},
- * within which there is a 68% probability of finding the true altitude.
+ * <p>We define vertical accuracy at 68% confidence. Specifically, as 1-side of the 2-sided
+ * range above and below the estimated altitude reported by {@link #getAltitude()}, within which
+ * there is a 68% probability of finding the true altitude.
*
* <p>In the case where the underlying distribution is assumed Gaussian normal, this would be
* considered 1 standard deviation.
*
- * <p>For example, if {@link #getAltitude()} returns 150, and
- * {@link #getVerticalAccuracyMeters()} returns 20 then there is a 68% probability
- * of the true altitude being between 130 and 170 meters.
- *
- * <p>If this location does not have a vertical accuracy, then 0.0 is returned.
+ * <p>For example, if {@link #getAltitude()} returns 150m, and this method returns 20m then
+ * there is a 68% probability of the true altitude being between 130m and 170m.
*/
public float getVerticalAccuracyMeters() {
return mVerticalAccuracyMeters;
@@ -940,22 +903,19 @@ public class Location implements Parcelable {
/**
* Get the estimated speed accuracy of this location, in meters per second.
*
- * <p>We define speed accuracy at 68% confidence. Specifically, as 1-side of the
- * 2-sided range above and below the estimated speed reported by {@link #getSpeed()},
- * within which there is a 68% probability of finding the true speed.
- *
- * <p>In the case where the underlying
- * distribution is assumed Gaussian normal, this would be considered 1 standard deviation.
+ * <p>We define speed accuracy at 68% confidence. Specifically, as 1-side of the 2-sided range
+ * above and below the estimated speed reported by {@link #getSpeed()}, within which there is a
+ * 68% probability of finding the true speed.
*
- * <p>For example, if {@link #getSpeed()} returns 5, and
- * {@link #getSpeedAccuracyMetersPerSecond()} returns 1, then there is a 68% probability of
- * the true speed being between 4 and 6 meters per second.
+ * <p>In the case where the underlying distribution is assumed Gaussian normal, this would be
+ * considered 1 standard deviation.
*
- * <p>Note that the speed and speed accuracy is often better than would be obtained simply from
- * differencing sequential positions, such as when the Doppler measurements from GNSS satellites
- * are used.
+ * <p>For example, if {@link #getSpeed()} returns 5m/s, and this method returns 1m/s, then there
+ * is a 68% probability of the true speed being between 4m/s and 6m/s.
*
- * <p>If this location does not have a speed accuracy, then 0.0 is returned.
+ * <p>Note that the speed and speed accuracy may be more accurate than would be obtained simply
+ * from differencing sequential positions, such as when the Doppler measurements from GNSS
+ * satellites are taken into account.
*/
public float getSpeedAccuracyMetersPerSecond() {
return mSpeedAccuracyMetersPerSecond;
@@ -998,18 +958,15 @@ public class Location implements Parcelable {
/**
* Get the estimated bearing accuracy of this location, in degrees.
*
- * <p>We define bearing accuracy at 68% confidence. Specifically, as 1-side of the
- * 2-sided range on each side of the estimated bearing reported by {@link #getBearing()},
- * within which there is a 68% probability of finding the true bearing.
+ * <p>We define bearing accuracy at 68% confidence. Specifically, as 1-side of the 2-sided range
+ * on each side of the estimated bearing reported by {@link #getBearing()}, within which there
+ * is a 68% probability of finding the true bearing.
*
* <p>In the case where the underlying distribution is assumed Gaussian normal, this would be
* considered 1 standard deviation.
*
- * <p>For example, if {@link #getBearing()} returns 60, and
- * {@link #getBearingAccuracyDegrees()} returns 10, then there is a 68% probability of the
- * true bearing being between 50 and 70 degrees.
- *
- * <p>If this location does not have a bearing accuracy, then 0.0 is returned.
+ * <p>For example, if {@link #getBearing()} returns 60°, and this method returns 10°, then there
+ * is a 68% probability of the true bearing being between 50° and 70°.
*/
public float getBearingAccuracyDegrees() {
return mBearingAccuracyDegrees;
@@ -1056,11 +1013,7 @@ public class Location implements Parcelable {
*/
@SystemApi
public boolean isComplete() {
- if (mProvider == null) return false;
- if (!hasAccuracy()) return false;
- if (mTime == 0) return false;
- if (mElapsedRealtimeNanos == 0) return false;
- return true;
+ return mProvider != null && hasAccuracy() && mTime != 0 && mElapsedRealtimeNanos != 0;
}
/**
@@ -1084,10 +1037,9 @@ public class Location implements Parcelable {
}
/**
- * Returns additional provider-specific information about the
- * location fix as a Bundle. The keys and values are determined
- * by the provider. If no additional information is available,
- * null is returned.
+ * Returns additional provider-specific information about the location fix as a Bundle. The keys
+ * and values are determined by the provider. If no additional information is available, null
+ * is returned.
*
* <p> A number of common key/value pairs are listed
* below. Providers that use any of the keys on this list must
@@ -1096,53 +1048,105 @@ public class Location implements Parcelable {
* <ul>
* <li> satellites - the number of satellites used to derive the fix
* </ul>
+ *
+ * @deprecated Do not use. For GNSS related information, prefer listening for GNSS status
+ * information via {@link LocationManager}.
*/
+ @Deprecated
public Bundle getExtras() {
return mExtras;
}
/**
- * Sets the extra information associated with this fix to the
- * given Bundle.
+ * Sets the extra information associated with this fix to the given Bundle.
*
* <p>Note this stores a copy of the given extras, so any changes to extras after calling this
* method won't be reflected in the location bundle.
+ *
+ * @deprecated Do not use.
*/
+ @Deprecated
public void setExtras(Bundle extras) {
mExtras = (extras == null) ? null : new Bundle(extras);
}
@Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Location location = (Location) o;
+ return mTime == location.mTime
+ && mElapsedRealtimeNanos == location.mElapsedRealtimeNanos
+ && hasElapsedRealtimeUncertaintyNanos()
+ == location.hasElapsedRealtimeUncertaintyNanos()
+ && (!hasElapsedRealtimeUncertaintyNanos() || Double.compare(
+ location.mElapsedRealtimeUncertaintyNanos, mElapsedRealtimeUncertaintyNanos) == 0)
+ && Double.compare(location.mLatitude, mLatitude) == 0
+ && Double.compare(location.mLongitude, mLongitude) == 0
+ && hasAltitude() == location.hasAltitude()
+ && (!hasAltitude() || Double.compare(location.mAltitude, mAltitude) == 0)
+ && hasSpeed() == location.hasSpeed()
+ && (!hasSpeed() || Float.compare(location.mSpeed, mSpeed) == 0)
+ && hasBearing() == location.hasBearing()
+ && (!hasBearing() || Float.compare(location.mBearing, mBearing) == 0)
+ && hasAccuracy() == location.hasAccuracy()
+ && (!hasAccuracy() || Float.compare(location.mHorizontalAccuracyMeters,
+ mHorizontalAccuracyMeters) == 0)
+ && hasVerticalAccuracy() == location.hasVerticalAccuracy()
+ && (!hasVerticalAccuracy() || Float.compare(location.mVerticalAccuracyMeters,
+ mVerticalAccuracyMeters) == 0)
+ && hasSpeedAccuracy() == location.hasSpeedAccuracy()
+ && (!hasSpeedAccuracy() || Float.compare(location.mSpeedAccuracyMetersPerSecond,
+ mSpeedAccuracyMetersPerSecond) == 0)
+ && hasBearingAccuracy() == location.hasBearingAccuracy()
+ && (!hasBearingAccuracy() || Float.compare(location.mBearingAccuracyDegrees,
+ mBearingAccuracyDegrees) == 0)
+ && Objects.equals(mProvider, location.mProvider)
+ && Objects.equals(mExtras, location.mExtras);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mProvider, mElapsedRealtimeNanos, mLatitude, mLongitude);
+ }
+
+ @Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append("Location[");
s.append(mProvider);
- s.append(String.format(" %.6f,%.6f", mLatitude, mLongitude));
- if (hasAccuracy()) s.append(String.format(" hAcc=%.0f", mHorizontalAccuracyMeters));
- else s.append(" hAcc=???");
- if (mTime == 0) {
- s.append(" t=?!?");
+ s.append(" ").append(String.format(Locale.ROOT, "%.6f,%.6f", mLatitude, mLongitude));
+ if (hasAccuracy()) {
+ s.append(" hAcc=").append(mHorizontalAccuracyMeters);
}
- if (mElapsedRealtimeNanos == 0) {
- s.append(" et=?!?");
- } else {
- s.append(" et=");
- TimeUtils.formatDuration(mElapsedRealtimeNanos / 1000000L, s);
+ s.append(" et=");
+ TimeUtils.formatDuration(getElapsedRealtimeMillis(), s);
+ if (hasAltitude()) {
+ s.append(" alt=").append(mAltitude);
+ if (hasVerticalAccuracy()) {
+ s.append(" vAcc=").append(mVerticalAccuracyMeters);
+ }
}
- if (hasElapsedRealtimeUncertaintyNanos()) {
- s.append(" etAcc=");
- TimeUtils.formatDuration((long) (mElapsedRealtimeUncertaintyNanos / 1000000), s);
+ if (hasSpeed()) {
+ s.append(" vel=").append(mSpeed);
+ if (hasSpeedAccuracy()) {
+ s.append(" sAcc=").append(mSpeedAccuracyMetersPerSecond);
+ }
+ }
+ if (hasBearing()) {
+ s.append(" bear=").append(mBearing);
+ if (hasBearingAccuracy()) {
+ s.append(" bAcc=").append(mBearingAccuracyDegrees);
+ }
+ }
+ if (isFromMockProvider()) {
+ s.append(" mock");
}
- if (hasAltitude()) s.append(" alt=").append(mAltitude);
- if (hasSpeed()) s.append(" vel=").append(mSpeed);
- if (hasBearing()) s.append(" bear=").append(mBearing);
- if (hasVerticalAccuracy()) s.append(String.format(" vAcc=%.0f", mVerticalAccuracyMeters));
- else s.append(" vAcc=???");
- if (hasSpeedAccuracy()) s.append(String.format(" sAcc=%.0f", mSpeedAccuracyMetersPerSecond));
- else s.append(" sAcc=???");
- if (hasBearingAccuracy()) s.append(String.format(" bAcc=%.0f", mBearingAccuracyDegrees));
- else s.append(" bAcc=???");
- if (isFromMockProvider()) s.append(" mock");
if (mExtras != null) {
s.append(" {").append(mExtras).append('}');
@@ -1155,25 +1159,40 @@ public class Location implements Parcelable {
pw.println(prefix + toString());
}
- public static final @android.annotation.NonNull Parcelable.Creator<Location> CREATOR =
+ public static final @NonNull Parcelable.Creator<Location> CREATOR =
new Parcelable.Creator<Location>() {
@Override
public Location createFromParcel(Parcel in) {
- String provider = in.readString();
- Location l = new Location(provider);
+ Location l = new Location(in.readString());
+ l.mFieldsMask = in.readInt();
l.mTime = in.readLong();
l.mElapsedRealtimeNanos = in.readLong();
- l.mElapsedRealtimeUncertaintyNanos = in.readDouble();
- l.mFieldsMask = in.readInt();
+ if (l.hasElapsedRealtimeUncertaintyNanos()) {
+ l.mElapsedRealtimeUncertaintyNanos = in.readDouble();
+ }
l.mLatitude = in.readDouble();
l.mLongitude = in.readDouble();
- l.mAltitude = in.readDouble();
- l.mSpeed = in.readFloat();
- l.mBearing = in.readFloat();
- l.mHorizontalAccuracyMeters = in.readFloat();
- l.mVerticalAccuracyMeters = in.readFloat();
- l.mSpeedAccuracyMetersPerSecond = in.readFloat();
- l.mBearingAccuracyDegrees = in.readFloat();
+ if (l.hasAltitude()) {
+ l.mAltitude = in.readDouble();
+ }
+ if (l.hasSpeed()) {
+ l.mSpeed = in.readFloat();
+ }
+ if (l.hasBearing()) {
+ l.mBearing = in.readFloat();
+ }
+ if (l.hasAccuracy()) {
+ l.mHorizontalAccuracyMeters = in.readFloat();
+ }
+ if (l.hasVerticalAccuracy()) {
+ l.mVerticalAccuracyMeters = in.readFloat();
+ }
+ if (l.hasSpeedAccuracy()) {
+ l.mSpeedAccuracyMetersPerSecond = in.readFloat();
+ }
+ if (l.hasBearingAccuracy()) {
+ l.mBearingAccuracyDegrees = in.readFloat();
+ }
l.mExtras = Bundle.setDefusable(in.readBundle(), true);
return l;
}
@@ -1192,38 +1211,36 @@ public class Location implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mProvider);
+ parcel.writeInt(mFieldsMask);
parcel.writeLong(mTime);
parcel.writeLong(mElapsedRealtimeNanos);
- parcel.writeDouble(mElapsedRealtimeUncertaintyNanos);
- parcel.writeInt(mFieldsMask);
+ if (hasElapsedRealtimeUncertaintyNanos()) {
+ parcel.writeDouble(mElapsedRealtimeUncertaintyNanos);
+ }
parcel.writeDouble(mLatitude);
parcel.writeDouble(mLongitude);
- parcel.writeDouble(mAltitude);
- parcel.writeFloat(mSpeed);
- parcel.writeFloat(mBearing);
- parcel.writeFloat(mHorizontalAccuracyMeters);
- parcel.writeFloat(mVerticalAccuracyMeters);
- parcel.writeFloat(mSpeedAccuracyMetersPerSecond);
- parcel.writeFloat(mBearingAccuracyDegrees);
- parcel.writeBundle(mExtras);
- }
-
- /**
- * Returns one of the optional extra {@link Location}s that can be attached
- * to this Location.
- *
- * @param key the key associated with the desired extra Location
- * @return the extra Location, or null if unavailable
- * @hide
- */
- public Location getExtraLocation(String key) {
- if (mExtras != null) {
- Parcelable value = mExtras.getParcelable(key);
- if (value instanceof Location) {
- return (Location) value;
- }
+ if (hasAltitude()) {
+ parcel.writeDouble(mAltitude);
+ }
+ if (hasSpeed()) {
+ parcel.writeFloat(mSpeed);
+ }
+ if (hasBearing()) {
+ parcel.writeFloat(mBearing);
+ }
+ if (hasAccuracy()) {
+ parcel.writeFloat(mHorizontalAccuracyMeters);
}
- return null;
+ if (hasVerticalAccuracy()) {
+ parcel.writeFloat(mVerticalAccuracyMeters);
+ }
+ if (hasSpeedAccuracy()) {
+ parcel.writeFloat(mSpeedAccuracyMetersPerSecond);
+ }
+ if (hasBearingAccuracy()) {
+ parcel.writeFloat(mBearingAccuracyDegrees);
+ }
+ parcel.writeBundle(mExtras);
}
/**
diff --git a/location/java/android/location/LocationListener.java b/location/java/android/location/LocationListener.java
index 0ff0a723237b..523117b39762 100644
--- a/location/java/android/location/LocationListener.java
+++ b/location/java/android/location/LocationListener.java
@@ -46,6 +46,29 @@ public interface LocationListener {
void onLocationChanged(@NonNull Location location);
/**
+ * Called when the location has changed and locations are being delivered in batches. The
+ * default implementation calls through to ({@link #onLocationChanged(Location)} with all
+ * locations in the batch, from earliest to latest.
+ *
+ * @see LocationRequest#getMaxUpdateDelayMillis()
+ * @param locationResult the location result list
+ */
+ default void onLocationChanged(@NonNull LocationResult locationResult) {
+ final int size = locationResult.size();
+ for (int i = 0; i < size; ++i) {
+ onLocationChanged(locationResult.get(i));
+ }
+ }
+
+ /**
+ * Invoked when a flush operation is complete and after flushed locations have been delivered.
+ *
+ * @param requestCode the request code passed into
+ * {@link LocationManager#requestFlush(String, LocationListener, int)}
+ */
+ default void onFlushComplete(int requestCode) {}
+
+ /**
* This callback will never be invoked on Android Q and above, and providers can be considered
* as always in the {@link LocationProvider#AVAILABLE} state.
*
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 3493693ac67e..047b809bc766 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -33,6 +33,7 @@ import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -65,8 +66,8 @@ import com.android.internal.util.Preconditions;
import java.lang.ref.WeakReference;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
-import java.util.Objects;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -76,12 +77,11 @@ import java.util.function.Consumer;
* obtain periodic updates of the device's geographical location, or to be notified when the device
* enters the proximity of a given geographical location.
*
- * <p class="note">Unless noted, all Location API methods require the {@link
- * android.Manifest.permission#ACCESS_COARSE_LOCATION} or {@link
- * android.Manifest.permission#ACCESS_FINE_LOCATION} permissions. If your application only has the
- * coarse permission then it will not have access to fine location providers. Other providers will
- * still return location results, but the exact location will be obfuscated to a coarse level of
- * accuracy.
+ * <p class="note">Unless otherwise noted, all Location API methods require the
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions. If your application only
+ * has the coarse permission then providers will still return location results, but the exact
+ * location will be obfuscated to a coarse level of accuracy.
*/
@SuppressWarnings({"deprecation"})
@SystemService(Context.LOCATION_SERVICE)
@@ -89,6 +89,16 @@ import java.util.function.Consumer;
public class LocationManager {
/**
+ * For apps targeting Android S and above, immutable PendingIntents passed into location APIs
+ * will generate an IllegalArgumentException.
+ *
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ public static final long BLOCK_IMMUTABLE_PENDING_INTENTS = 171317480L;
+
+ /**
* For apps targeting Android S and above, LocationRequest system APIs may not be used with
* PendingIntent location requests.
*
@@ -96,7 +106,7 @@ public class LocationManager {
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
- public static final long PREVENT_PENDING_INTENT_SYSTEM_API_USAGE = 169887240L;
+ public static final long BLOCK_PENDING_INTENT_SYSTEM_API_USAGE = 169887240L;
/**
* For apps targeting Android S and above, location clients may receive historical locations
@@ -116,7 +126,7 @@ public class LocationManager {
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
- private static final long GET_PROVIDER_SECURITY_EXCEPTIONS = 150935354L;
+ public static final long GET_PROVIDER_SECURITY_EXCEPTIONS = 150935354L;
/**
* For apps targeting Android K and above, supplied {@link PendingIntent}s must be targeted to a
@@ -126,7 +136,7 @@ public class LocationManager {
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
- private static final long TARGETED_PENDING_INTENT = 148963590L;
+ public static final long BLOCK_UNTARGETED_PENDING_INTENTS = 148963590L;
/**
* For apps targeting Android K and above, incomplete locations may not be passed to
@@ -136,7 +146,7 @@ public class LocationManager {
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
- private static final long INCOMPLETE_LOCATION = 148964793L;
+ public static final long BLOCK_INCOMPLETE_LOCATIONS = 148964793L;
/**
* For apps targeting Android S and above, all {@link GpsStatus} API usage must be replaced with
@@ -146,7 +156,7 @@ public class LocationManager {
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
- private static final long GPS_STATUS_USAGE = 144027538L;
+ public static final long BLOCK_GPS_STATUS_USAGE = 144027538L;
/**
* Name of the network location provider.
@@ -192,6 +202,7 @@ public class LocationManager {
*
* @hide
*/
+ @SystemApi
@TestApi
public static final String FUSED_PROVIDER = "fused";
@@ -229,6 +240,22 @@ public class LocationManager {
public static final String KEY_LOCATION_CHANGED = "location";
/**
+ * Key used for an extra holding a {@link LocationResult} value when a location change is sent
+ * using a PendingIntent.
+ *
+ * @see #requestLocationUpdates(String, LocationRequest, PendingIntent)
+ */
+ public static final String KEY_LOCATION_RESULT = "locationResult";
+
+ /**
+ * Key used for an extra holding an integer request code when location flush completion is sent
+ * using a PendingIntent.
+ *
+ * @see #requestFlush(String, PendingIntent, int)
+ */
+ public static final String KEY_FLUSH_COMPLETE = "flushComplete";
+
+ /**
* Broadcast intent action when the set of enabled location providers changes. To check the
* status of a provider, use {@link #isProviderEnabled(String)}. From Android Q and above, will
* include a string intent extra, {@link #EXTRA_PROVIDER_NAME}, with the name of the provider
@@ -367,9 +394,6 @@ public class LocationManager {
@GuardedBy("mLock")
@Nullable private GnssAntennaInfoTransportMultiplexer mGnssAntennaInfoTransportMultiplexer;
- @GuardedBy("mLock")
- @Nullable private BatchedLocationCallbackTransport mBatchedLocationCallbackTransport;
-
/**
* @hide
*/
@@ -1372,11 +1396,16 @@ public class LocationManager {
Preconditions.checkArgument(locationRequest != null, "invalid null location request");
Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
- if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
+ if (Compatibility.isChangeEnabled(BLOCK_UNTARGETED_PENDING_INTENTS)) {
Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
"pending intent must be targeted to a package");
}
+ if (Compatibility.isChangeEnabled(BLOCK_IMMUTABLE_PENDING_INTENTS)) {
+ Preconditions.checkArgument(!pendingIntent.isImmutable(),
+ "pending intent must be mutable");
+ }
+
try {
mService.registerLocationPendingIntent(provider, locationRequest, pendingIntent,
mContext.getPackageName(), mContext.getAttributionTag());
@@ -1418,8 +1447,70 @@ public class LocationManager {
}
/**
+ * Requests that the given provider flush any batched locations to listeners. The given listener
+ * (registered with the provider) will have {@link LocationListener#onFlushComplete(int)}
+ * invoked with the given result code after any locations that were flushed have been delivered.
+ * If {@link #removeUpdates(LocationListener)} is invoked before the flush callback is executed,
+ * then the flush callback will never be executed.
+ *
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @param listener a listener registered under the provider
+ * @param requestCode an arbitrary integer passed through to
+ * {@link LocationListener#onFlushComplete(int)}
+ *
+ * @throws IllegalArgumentException if provider is null or doesn't exist
+ * @throws IllegalArgumentException if listener is null or is not registered under the provider
+ */
+ @SuppressLint("SamShouldBeLast")
+ public void requestFlush(@NonNull String provider, @NonNull LocationListener listener,
+ @SuppressLint("ListenerLast") int requestCode) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+ Preconditions.checkArgument(listener != null, "invalid null listener");
+
+ synchronized (sLocationListeners) {
+ WeakReference<LocationListenerTransport> ref = sLocationListeners.get(listener);
+ LocationListenerTransport transport = ref != null ? ref.get() : null;
+
+ Preconditions.checkArgument(transport != null,
+ "unregistered listener cannot be flushed");
+
+ try {
+ mService.requestListenerFlush(provider, transport, requestCode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Requests that the given provider flush any batched locations to listeners. The given
+ * PendingIntent (registered with the provider) will be sent with {@link #KEY_FLUSH_COMPLETE}
+ * present in the extra keys, and {@code requestCode} as the corresponding value.
+ *
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @param pendingIntent a pendingIntent registered under the provider
+ * @param requestCode an arbitrary integer that will be passed back as the extra value for
+ * {@link #KEY_FLUSH_COMPLETE}
+ *
+ * @throws IllegalArgumentException if provider is null or doesn't exist
+ * @throws IllegalArgumentException if pending intent is null or is not registered under the
+ * provider
+ */
+ public void requestFlush(@NonNull String provider, @NonNull PendingIntent pendingIntent,
+ int requestCode) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+ Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
+
+ try {
+ mService.requestPendingIntentFlush(provider, pendingIntent, requestCode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Removes location updates for the specified {@link LocationListener}. Following this call,
- * the listener will no longer receive location updates.
+ * the listener will not receive any more invocations of any kind.
*
* @param listener listener that no longer needs location updates
*
@@ -1729,7 +1820,7 @@ public class LocationManager {
Preconditions.checkArgument(provider != null, "invalid null provider");
Preconditions.checkArgument(location != null, "invalid null location");
- if (Compatibility.isChangeEnabled(INCOMPLETE_LOCATION)) {
+ if (Compatibility.isChangeEnabled(BLOCK_INCOMPLETE_LOCATIONS)) {
Preconditions.checkArgument(location.isComplete(),
"incomplete location object, missing timestamp or accuracy?");
} else {
@@ -1821,29 +1912,38 @@ public class LocationManager {
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. From API version 17 and onwards,
* this method requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
*
- * @param latitude the latitude of the central point of the alert region
- * @param longitude the longitude of the central point of the alert region
- * @param radius the radius of the central point of the alert region in meters
- * @param expiration expiration realtime for this proximity alert in milliseconds, or -1 to
- * indicate no expiration
- * @param intent a {@link PendingIntent} that will sent when entry to or exit from the alert
- * region is detected
+ * @param latitude the latitude of the central point of the alert region
+ * @param longitude the longitude of the central point of the alert region
+ * @param radius the radius of the central point of the alert region in meters
+ * @param expiration expiration realtime for this proximity alert in milliseconds, or -1 to
+ * indicate no expiration
+ * @param pendingIntent a {@link PendingIntent} that will sent when entry to or exit from the
+ * alert region is detected
* @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
* permission is not present
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
- @NonNull PendingIntent intent) {
- Preconditions.checkArgument(intent != null, "invalid null pending intent");
- if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
- Preconditions.checkArgument(intent.isTargetedToPackage(),
+ @NonNull PendingIntent pendingIntent) {
+ Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
+
+ if (Compatibility.isChangeEnabled(BLOCK_UNTARGETED_PENDING_INTENTS)) {
+ Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
"pending intent must be targeted to a package");
}
- if (expiration < 0) expiration = Long.MAX_VALUE;
+
+ if (Compatibility.isChangeEnabled(BLOCK_IMMUTABLE_PENDING_INTENTS)) {
+ Preconditions.checkArgument(!pendingIntent.isImmutable(),
+ "pending intent must be mutable");
+ }
+
+ if (expiration < 0) {
+ expiration = Long.MAX_VALUE;
+ }
try {
Geofence fence = Geofence.createCircle(latitude, longitude, radius, expiration);
- mService.requestGeofence(fence, intent, mContext.getPackageName(),
+ mService.requestGeofence(fence, pendingIntent, mContext.getPackageName(),
mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1941,7 +2041,7 @@ public class LocationManager {
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) {
- if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
+ if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
throw new UnsupportedOperationException(
"GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
@@ -1976,7 +2076,7 @@ public class LocationManager {
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addGpsStatusListener(GpsStatus.Listener listener) {
- if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
+ if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
throw new UnsupportedOperationException(
"GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
@@ -1996,7 +2096,7 @@ public class LocationManager {
*/
@Deprecated
public void removeGpsStatusListener(GpsStatus.Listener listener) {
- if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
+ if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
throw new UnsupportedOperationException(
"GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
@@ -2412,10 +2512,11 @@ public class LocationManager {
* interface.
*
* @return Maximum number of location objects that can be returned
+ * @deprecated Do not use
* @hide
*/
+ @Deprecated
@SystemApi
- @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
public int getGnssBatchSize() {
try {
return mService.getGnssBatchSize();
@@ -2435,48 +2536,47 @@ public class LocationManager {
*
* @param periodNanos Time interval, in nanoseconds, that the GNSS locations are requested
* within the batch
- * @param wakeOnFifoFull True if the hardware batching should flush the locations in a
- * a callback to the listener, when it's internal buffer is full. If
- * set to false, the oldest location information is, instead,
- * dropped when the buffer is full.
+ * @param wakeOnFifoFull ignored
* @param callback The listener on which to return the batched locations
* @param handler The handler on which to process the callback
*
- * @return True if batching was successfully started
+ * @return True always
+ * @deprecated Use {@link LocationRequest.Builder#setMaxUpdateDelayMillis(long)} instead.
* @hide
*/
+ @Deprecated
@SystemApi
- @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+ @RequiresPermission(allOf = {Manifest.permission.LOCATION_HARDWARE,
+ Manifest.permission.UPDATE_APP_OPS_STATS})
public boolean registerGnssBatchedLocationCallback(long periodNanos, boolean wakeOnFifoFull,
@NonNull BatchedLocationCallback callback, @Nullable Handler handler) {
if (handler == null) {
handler = new Handler();
}
- BatchedLocationCallbackTransport transport = new BatchedLocationCallbackTransport(callback,
- handler);
-
- synchronized (mLock) {
- try {
- mService.setGnssBatchingCallback(transport, mContext.getPackageName(),
- mContext.getAttributionTag());
- mBatchedLocationCallbackTransport = transport;
- mService.startGnssBatch(periodNanos, wakeOnFifoFull,
- mContext.getPackageName(), mContext.getFeatureId());
- return true;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ try {
+ mService.startGnssBatch(
+ periodNanos,
+ new BatchedLocationCallbackTransport(callback, handler),
+ mContext.getPackageName(),
+ mContext.getAttributionTag(),
+ AppOpsManager.toReceiverId(callback));
+ return true;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
/**
- * Flush the batched GNSS locations.
- * All GNSS locations currently ready in the batch are returned via the callback sent in
- * startGnssBatch(), and the buffer containing the batched locations is cleared.
+ * Flush the batched GNSS locations. All GNSS locations currently ready in the batch are
+ * returned via the callback sent in startGnssBatch(), and the buffer containing the batched
+ * locations is cleared.
*
* @hide
+ * @deprecated Use {@link #requestFlush(String, LocationListener, int)} or
+ * {@link #requestFlush(String, PendingIntent, int)} instead.
*/
+ @Deprecated
@SystemApi
@RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
public void flushGnssBatch() {
@@ -2488,29 +2588,25 @@ public class LocationManager {
}
/**
- * Stop batching locations. This API is primarily used when the AP is
- * asleep and the device can batch locations in the hardware.
+ * Stop batching locations. This API is primarily used when the AP is asleep and the device can
+ * batch locations in the hardware.
*
- * @param callback the specific callback class to remove from the transport layer
+ * @param callback ignored
*
* @return True always
+ * @deprecated Use {@link LocationRequest.Builder#setMaxUpdateDelayMillis(long)} instead.
* @hide
*/
+ @Deprecated
@SystemApi
@RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
public boolean unregisterGnssBatchedLocationCallback(
@NonNull BatchedLocationCallback callback) {
- synchronized (mLock) {
- if (callback == mBatchedLocationCallbackTransport.getCallback()) {
- try {
- mBatchedLocationCallbackTransport = null;
- mService.removeGnssBatchingCallback();
- mService.stopGnssBatch();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ try {
+ mService.stopGnssBatch();
return true;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
@@ -2518,10 +2614,7 @@ public class LocationManager {
ListenerExecutor, CancellationSignal.OnCancelListener {
private final Executor mExecutor;
-
- @GuardedBy("this")
- @Nullable
- private Consumer<Location> mConsumer;
+ private volatile @Nullable Consumer<Location> mConsumer;
GetCurrentLocationTransport(Executor executor, Consumer<Location> consumer,
@Nullable CancellationSignal cancellationSignal) {
@@ -2537,20 +2630,22 @@ public class LocationManager {
@Override
public void onCancel() {
- synchronized (this) {
- mConsumer = null;
- }
+ mConsumer = null;
}
@Override
public void onLocation(@Nullable Location location) {
- Consumer<Location> consumer;
- synchronized (this) {
- consumer = mConsumer;
- mConsumer = null;
- }
+ executeSafely(mExecutor, () -> mConsumer, new ListenerOperation<Consumer<Location>>() {
+ @Override
+ public void operate(Consumer<Location> consumer) {
+ consumer.accept(location);
+ }
- executeSafely(mExecutor, () -> consumer, listener -> listener.accept(location));
+ @Override
+ public void onPostExecute(boolean success) {
+ mConsumer = null;
+ }
+ });
}
}
@@ -2558,7 +2653,7 @@ public class LocationManager {
ListenerExecutor {
private Executor mExecutor;
- @Nullable private volatile LocationListener mListener;
+ private volatile @Nullable LocationListener mListener;
LocationListenerTransport(LocationListener listener, Executor executor) {
Preconditions.checkArgument(listener != null, "invalid null listener");
@@ -2580,12 +2675,12 @@ public class LocationManager {
}
@Override
- public void onLocationChanged(Location location,
+ public void onLocationChanged(LocationResult locationResult,
@Nullable IRemoteCallback onCompleteCallback) {
executeSafely(mExecutor, () -> mListener, new ListenerOperation<LocationListener>() {
@Override
public void operate(LocationListener listener) {
- listener.onLocationChanged(location);
+ listener.onLocationChanged(locationResult);
}
@Override
@@ -2602,6 +2697,12 @@ public class LocationManager {
}
@Override
+ public void onFlushComplete(int requestCode) {
+ executeSafely(mExecutor, () -> mListener,
+ listener -> listener.onFlushComplete(requestCode));
+ }
+
+ @Override
public void onProviderEnabledChanged(String provider, boolean enabled) {
executeSafely(mExecutor, () -> mListener, listener -> {
if (enabled) {
@@ -2890,39 +2991,29 @@ public class LocationManager {
}
}
- private static class BatchedLocationCallbackTransport extends IBatchedLocationCallback.Stub {
+ private static class BatchedLocationCallbackWrapper implements LocationListener {
- private final Handler mHandler;
- private volatile @Nullable BatchedLocationCallback mCallback;
+ private final BatchedLocationCallback mCallback;
- BatchedLocationCallbackTransport(BatchedLocationCallback callback, Handler handler) {
- mCallback = Objects.requireNonNull(callback);
- mHandler = Objects.requireNonNull(handler);
+ BatchedLocationCallbackWrapper(BatchedLocationCallback callback) {
+ mCallback = callback;
}
- @Nullable
- public BatchedLocationCallback getCallback() {
- return mCallback;
- }
-
- public void unregister() {
- mCallback = null;
+ @Override
+ public void onLocationChanged(@NonNull Location location) {
+ mCallback.onLocationBatch(Collections.singletonList(location));
}
@Override
- public void onLocationBatch(List<Location> locations) {
- if (mCallback == null) {
- return;
- }
+ public void onLocationChanged(@NonNull LocationResult locationResult) {
+ mCallback.onLocationBatch(locationResult.asList());
+ }
+ }
- mHandler.post(() -> {
- BatchedLocationCallback callback = mCallback;
- if (callback == null) {
- return;
- }
+ private static class BatchedLocationCallbackTransport extends LocationListenerTransport {
- callback.onLocationBatch(locations);
- });
+ BatchedLocationCallbackTransport(BatchedLocationCallback callback, Handler handler) {
+ super(new BatchedLocationCallbackWrapper(callback), new HandlerExecutor(handler));
}
}
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index ef68814bce84..1027f9c0a7be 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -21,8 +21,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.location.util.identity.CallerIdentity;
-import java.util.List;
-
/**
* Location manager local system service interface.
*
@@ -82,10 +80,4 @@ public abstract class LocationManagerInternal {
*/
// TODO: there is no reason for this to exist as part of any API. move all the logic into gnss
public abstract void sendNiResponse(int notifId, int userResponse);
-
- /**
- * Should only be used by GNSS code.
- */
- // TODO: there is no reason for this to exist as part of any API. create a real batching API
- public abstract void reportGnssBatchLocations(List<Location> locations);
}
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 1adb2b47a884..323e740ee8e3 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -191,6 +191,7 @@ public final class LocationRequest implements Parcelable {
private long mDurationMillis;
private int mMaxUpdates;
private float mMinUpdateDistanceMeters;
+ private final long mMaxUpdateDelayMillis;
private boolean mHideFromAppOps;
private boolean mLocationSettingsIgnored;
private boolean mLowPower;
@@ -285,6 +286,7 @@ public final class LocationRequest implements Parcelable {
int maxUpdates,
long minUpdateIntervalMillis,
float minUpdateDistanceMeters,
+ long maxUpdateDelayMillis,
boolean hiddenFromAppOps,
boolean locationSettingsIgnored,
boolean lowPower,
@@ -297,6 +299,7 @@ public final class LocationRequest implements Parcelable {
mDurationMillis = durationMillis;
mMaxUpdates = maxUpdates;
mMinUpdateDistanceMeters = minUpdateDistanceMeters;
+ mMaxUpdateDelayMillis = maxUpdateDelayMillis;
mHideFromAppOps = hiddenFromAppOps;
mLowPower = lowPower;
mLocationSettingsIgnored = locationSettingsIgnored;
@@ -592,6 +595,24 @@ public final class LocationRequest implements Parcelable {
}
/**
+ * Returns the maximum time any location update may be delayed, and thus grouped with following
+ * updates to enable location batching. If the maximum update delay is equal to or greater than
+ * twice the interval, then location providers may provide batched results. The maximum batch
+ * size is the maximum update delay divided by the interval. Not all devices or location
+ * providers support batching, and use of this parameter does not guarantee that the client will
+ * see batched results, or that batched results will always be of the maximum size.
+ *
+ * When available, batching can provide substantial power savings to the device, and clients are
+ * encouraged to take advantage where appropriate for the use case.
+ *
+ * @see LocationListener#onLocationChanged(LocationResult)
+ * @return the maximum time by which a location update may be delayed
+ */
+ public @IntRange(from = 0) long getMaxUpdateDelayMillis() {
+ return mMaxUpdateDelayMillis;
+ }
+
+ /**
* @hide
* @deprecated LocationRequests should be treated as immutable.
*/
@@ -725,6 +746,7 @@ public final class LocationRequest implements Parcelable {
/* maxUpdates= */ in.readInt(),
/* minUpdateIntervalMillis= */ in.readLong(),
/* minUpdateDistanceMeters= */ in.readFloat(),
+ /* maxUpdateDelayMillis= */ in.readLong(),
/* hiddenFromAppOps= */ in.readBoolean(),
/* locationSettingsIgnored= */ in.readBoolean(),
/* lowPower= */ in.readBoolean(),
@@ -752,6 +774,7 @@ public final class LocationRequest implements Parcelable {
parcel.writeInt(mMaxUpdates);
parcel.writeLong(mMinUpdateIntervalMillis);
parcel.writeFloat(mMinUpdateDistanceMeters);
+ parcel.writeLong(mMaxUpdateDelayMillis);
parcel.writeBoolean(mHideFromAppOps);
parcel.writeBoolean(mLocationSettingsIgnored);
parcel.writeBoolean(mLowPower);
@@ -775,6 +798,7 @@ public final class LocationRequest implements Parcelable {
&& mMaxUpdates == that.mMaxUpdates
&& mMinUpdateIntervalMillis == that.mMinUpdateIntervalMillis
&& Float.compare(that.mMinUpdateDistanceMeters, mMinUpdateDistanceMeters) == 0
+ && mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
&& mHideFromAppOps == that.mHideFromAppOps
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
&& mLowPower == that.mLowPower
@@ -831,6 +855,10 @@ public final class LocationRequest implements Parcelable {
if (mMinUpdateDistanceMeters > 0.0) {
s.append(", minUpdateDistance=").append(mMinUpdateDistanceMeters);
}
+ if (mMaxUpdateDelayMillis / 2 > mInterval) {
+ s.append(", maxUpdateDelay=");
+ TimeUtils.formatDuration(mMaxUpdateDelayMillis, s);
+ }
if (mLowPower) {
s.append(", lowPower");
}
@@ -858,6 +886,7 @@ public final class LocationRequest implements Parcelable {
private int mMaxUpdates;
private long mMinUpdateIntervalMillis;
private float mMinUpdateDistanceMeters;
+ private long mMaxUpdateDelayMillis;
private boolean mHiddenFromAppOps;
private boolean mLocationSettingsIgnored;
private boolean mLowPower;
@@ -876,6 +905,7 @@ public final class LocationRequest implements Parcelable {
mMaxUpdates = Integer.MAX_VALUE;
mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
mMinUpdateDistanceMeters = 0;
+ mMaxUpdateDelayMillis = 0;
mHiddenFromAppOps = false;
mLocationSettingsIgnored = false;
mLowPower = false;
@@ -892,6 +922,7 @@ public final class LocationRequest implements Parcelable {
mMaxUpdates = locationRequest.mMaxUpdates;
mMinUpdateIntervalMillis = locationRequest.mMinUpdateIntervalMillis;
mMinUpdateDistanceMeters = locationRequest.mMinUpdateDistanceMeters;
+ mMaxUpdateDelayMillis = locationRequest.mMaxUpdateDelayMillis;
mHiddenFromAppOps = locationRequest.mHideFromAppOps;
mLocationSettingsIgnored = locationRequest.mLocationSettingsIgnored;
mLowPower = locationRequest.mLowPower;
@@ -1027,6 +1058,19 @@ public final class LocationRequest implements Parcelable {
}
/**
+ * Sets the maximum time any location update may be delayed, and thus grouped with following
+ * updates to enable location batching. If the maximum update delay is equal to or greater
+ * than twice the interval, then location providers may provide batched results. Defaults to
+ * 0, which represents no batching allowed.
+ */
+ public @NonNull Builder setMaxUpdateDelayMillis(
+ @IntRange(from = 0) long maxUpdateDelayMillis) {
+ mMaxUpdateDelayMillis = Preconditions.checkArgumentInRange(maxUpdateDelayMillis, 0,
+ Long.MAX_VALUE, "maxUpdateDelayMillis");
+ return this;
+ }
+
+ /**
* If set to true, indicates that app ops should not be updated with location usage due to
* this request. This implies that someone else (usually the creator of the location
* request) is responsible for updating app ops as appropriate. Defaults to false.
@@ -1121,6 +1165,7 @@ public final class LocationRequest implements Parcelable {
mMaxUpdates,
min(mMinUpdateIntervalMillis, mIntervalMillis),
mMinUpdateDistanceMeters,
+ mMaxUpdateDelayMillis,
mHiddenFromAppOps,
mLocationSettingsIgnored,
mLowPower,
diff --git a/location/java/android/location/IBatchedLocationCallback.aidl b/location/java/android/location/LocationResult.aidl
index dce9f964c010..3bb894f17503 100644
--- a/location/java/android/location/IBatchedLocationCallback.aidl
+++ b/location/java/android/location/LocationResult.aidl
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2017, 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.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,14 +16,4 @@
package android.location;
-import android.location.Location;
-
-import java.util.List;
-
-/**
- * {@hide}
- */
-oneway interface IBatchedLocationCallback
-{
- void onLocationBatch(in List<Location> locations);
-}
+parcelable LocationResult;
diff --git a/location/java/android/location/LocationResult.java b/location/java/android/location/LocationResult.java
new file mode 100644
index 000000000000..79a000c23484
--- /dev/null
+++ b/location/java/android/location/LocationResult.java
@@ -0,0 +1,273 @@
+/*
+ * 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.location;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * A location result representing a list of locations, ordered from earliest to latest.
+ */
+public final class LocationResult implements Parcelable {
+
+ /**
+ * Creates a new LocationResult from the given location.
+ */
+ public static @NonNull LocationResult create(@NonNull Location location) {
+ ArrayList<Location> locations = new ArrayList<>(1);
+ locations.add(new Location(Objects.requireNonNull(location)));
+ return new LocationResult(locations);
+ }
+
+ /**
+ * Creates a new LocationResult from the given locations. Locations must be ordered in the same
+ * order they were derived (earliest to latest).
+ */
+ public static @NonNull LocationResult create(@NonNull List<Location> locations) {
+ Preconditions.checkArgument(!locations.isEmpty());
+ ArrayList<Location> locationsCopy = new ArrayList<>(locations.size());
+ for (Location location : locations) {
+ locationsCopy.add(new Location(Objects.requireNonNull(location)));
+ }
+ return new LocationResult(locationsCopy);
+ }
+
+ /**
+ * Creates a new LocationResult that takes ownership of the given location without copying it.
+ * Callers must ensure the given location is never mutated after this method is called.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static @NonNull LocationResult wrap(@NonNull Location location) {
+ ArrayList<Location> locations = new ArrayList<>(1);
+ locations.add(Objects.requireNonNull(location));
+ return new LocationResult(locations);
+ }
+
+ private final ArrayList<Location> mLocations;
+
+ private LocationResult(ArrayList<Location> locations) {
+ Preconditions.checkArgument(!locations.isEmpty());
+ mLocations = locations;
+ }
+
+ /**
+ * Throws an IllegalArgumentException if the ordering of locations does not appear to generally
+ * be from earliest to latest, or if any individual location is incomplete.
+ *
+ * @hide
+ */
+ public @NonNull LocationResult validate() {
+ long prevElapsedRealtimeNs = 0;
+ final int size = mLocations.size();
+ for (int i = 0; i < size; ++i) {
+ Location location = mLocations.get(i);
+ if (!location.isComplete()) {
+ throw new IllegalArgumentException(
+ "incomplete location at index " + i + ": " + mLocations);
+ }
+ if (location.getElapsedRealtimeNanos() < prevElapsedRealtimeNs) {
+ throw new IllegalArgumentException(
+ "incorrectly ordered location at index " + i + ": " + mLocations);
+ }
+ prevElapsedRealtimeNs = location.getElapsedRealtimeNanos();
+ }
+
+ return this;
+ }
+
+ /**
+ * Returns the latest location in this location result, ie, the location at the highest index.
+ */
+ public @NonNull Location getLastLocation() {
+ return mLocations.get(mLocations.size() - 1);
+ }
+
+ /**
+ * Returns the numer of locations in this location result.
+ */
+ public @IntRange(from = 1) int size() {
+ return mLocations.size();
+ }
+
+ /**
+ * Returns the location at the given index, from 0 to {@link #size()} - 1. Locations at lower
+ * indices are from earlier in time than location at higher indices.
+ */
+ public @NonNull Location get(@IntRange(from = 0) int i) {
+ return mLocations.get(i);
+ }
+
+ /**
+ * Returns an unmodifiable list of locations in this location result.
+ */
+ public @NonNull List<Location> asList() {
+ return Collections.unmodifiableList(mLocations);
+ }
+
+ /**
+ * Returns a deep copy of this LocationResult.
+ *
+ * @hide
+ */
+ public @NonNull LocationResult deepCopy() {
+ ArrayList<Location> copy = new ArrayList<>(mLocations.size());
+ final int size = mLocations.size();
+ for (int i = 0; i < size; ++i) {
+ copy.add(new Location(mLocations.get(i)));
+ }
+ return new LocationResult(copy);
+ }
+
+ /**
+ * Returns a LocationResult with only the last location from this location result.
+ *
+ * @hide
+ */
+ public @NonNull LocationResult asLastLocationResult() {
+ if (mLocations.size() == 1) {
+ return this;
+ } else {
+ return LocationResult.wrap(getLastLocation());
+ }
+ }
+
+ /**
+ * Returns a LocationResult with only locations that pass the given predicate. This
+ * implementation will avoid allocations when no locations are filtered out. The predicate is
+ * guaranteed to be invoked once per location, in order from earliest to latest. If all
+ * locations are filtered out a null value is returned instead of an empty LocationResult.
+ *
+ * @hide
+ */
+ public @Nullable LocationResult filter(Predicate<Location> predicate) {
+ ArrayList<Location> filtered = mLocations;
+ final int size = mLocations.size();
+ for (int i = 0; i < size; ++i) {
+ if (!predicate.test(mLocations.get(i))) {
+ if (filtered == mLocations) {
+ filtered = new ArrayList<>(mLocations.size() - 1);
+ for (int j = 0; j < i; ++j) {
+ filtered.add(mLocations.get(j));
+ }
+ }
+ } else if (filtered != mLocations) {
+ filtered.add(mLocations.get(i));
+ }
+ }
+
+ if (filtered == mLocations) {
+ return this;
+ } else if (filtered.isEmpty()) {
+ return null;
+ } else {
+ return new LocationResult(filtered);
+ }
+ }
+
+ /**
+ * Returns a LocationResult with locations mapped to other locations. This implementation will
+ * avoid allocations when all locations are mapped to the same location. The function is
+ * guaranteed to be invoked once per location, in order from earliest to latest.
+ *
+ * @hide
+ */
+ public @NonNull LocationResult map(Function<Location, Location> function) {
+ ArrayList<Location> mapped = mLocations;
+ final int size = mLocations.size();
+ for (int i = 0; i < size; ++i) {
+ Location location = mLocations.get(i);
+ Location newLocation = function.apply(location);
+ if (mapped != mLocations) {
+ mapped.add(newLocation);
+ } else if (newLocation != location) {
+ mapped = new ArrayList<>(mLocations.size());
+ for (int j = 0; j < i; ++j) {
+ mapped.add(mLocations.get(j));
+ }
+ mapped.add(newLocation);
+ }
+ }
+
+ if (mapped == mLocations) {
+ return this;
+ } else {
+ return new LocationResult(mapped);
+ }
+ }
+
+ public static final @NonNull Parcelable.Creator<LocationResult> CREATOR =
+ new Parcelable.Creator<LocationResult>() {
+ @Override
+ public LocationResult createFromParcel(Parcel in) {
+ return new LocationResult(
+ Objects.requireNonNull(in.createTypedArrayList(Location.CREATOR)));
+ }
+
+ @Override
+ public LocationResult[] newArray(int size) {
+ return new LocationResult[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeTypedList(mLocations);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ LocationResult that = (LocationResult) o;
+ return mLocations.equals(that.mLocations);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mLocations);
+ }
+
+ @Override
+ public String toString() {
+ return mLocations.toString();
+ }
+}
diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.java b/location/java/android/location/timezone/LocationTimeZoneEvent.java
index d3fd5c3ac061..922a38921048 100644
--- a/location/java/android/location/timezone/LocationTimeZoneEvent.java
+++ b/location/java/android/location/timezone/LocationTimeZoneEvent.java
@@ -21,7 +21,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.UserHandle;
import com.android.internal.util.Preconditions;
@@ -65,9 +64,6 @@ public final class LocationTimeZoneEvent implements Parcelable {
private static final int EVENT_TYPE_MAX = EVENT_TYPE_UNCERTAIN;
- @NonNull
- private final UserHandle mUserHandle;
-
@EventType
private final int mEventType;
@@ -76,9 +72,8 @@ public final class LocationTimeZoneEvent implements Parcelable {
private final long mElapsedRealtimeNanos;
- private LocationTimeZoneEvent(@NonNull UserHandle userHandle, @EventType int eventType,
- @NonNull List<String> timeZoneIds, long elapsedRealtimeNanos) {
- mUserHandle = Objects.requireNonNull(userHandle);
+ private LocationTimeZoneEvent(@EventType int eventType, @NonNull List<String> timeZoneIds,
+ long elapsedRealtimeNanos) {
mEventType = checkValidEventType(eventType);
mTimeZoneIds = immutableList(timeZoneIds);
@@ -89,14 +84,6 @@ public final class LocationTimeZoneEvent implements Parcelable {
}
/**
- * Returns the current user when the event was generated.
- */
- @NonNull
- public UserHandle getUserHandle() {
- return mUserHandle;
- }
-
- /**
* Returns the time of this fix, in elapsed real-time since system boot.
*
* <p>This value can be reliably compared to {@link
@@ -129,8 +116,7 @@ public final class LocationTimeZoneEvent implements Parcelable {
@Override
public String toString() {
return "LocationTimeZoneEvent{"
- + "mUserHandle=" + mUserHandle
- + ", mEventType=" + mEventType
+ + "mEventType=" + mEventType
+ ", mTimeZoneIds=" + mTimeZoneIds
+ ", mElapsedRealtimeNanos=" + mElapsedRealtimeNanos
+ '}';
@@ -140,14 +126,12 @@ public final class LocationTimeZoneEvent implements Parcelable {
new Parcelable.Creator<LocationTimeZoneEvent>() {
@Override
public LocationTimeZoneEvent createFromParcel(Parcel in) {
- UserHandle userHandle = UserHandle.readFromParcel(in);
int eventType = in.readInt();
@SuppressWarnings("unchecked")
ArrayList<String> timeZoneIds =
(ArrayList<String>) in.readArrayList(null /* classLoader */);
long elapsedRealtimeNanos = in.readLong();
- return new LocationTimeZoneEvent(
- userHandle, eventType, timeZoneIds, elapsedRealtimeNanos);
+ return new LocationTimeZoneEvent(eventType, timeZoneIds, elapsedRealtimeNanos);
}
@Override
@@ -163,7 +147,6 @@ public final class LocationTimeZoneEvent implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
- mUserHandle.writeToParcel(parcel, flags);
parcel.writeInt(mEventType);
parcel.writeList(mTimeZoneIds);
parcel.writeLong(mElapsedRealtimeNanos);
@@ -178,21 +161,19 @@ public final class LocationTimeZoneEvent implements Parcelable {
return false;
}
LocationTimeZoneEvent that = (LocationTimeZoneEvent) o;
- return mUserHandle.equals(that.mUserHandle)
- && mEventType == that.mEventType
+ return mEventType == that.mEventType
&& mElapsedRealtimeNanos == that.mElapsedRealtimeNanos
&& mTimeZoneIds.equals(that.mTimeZoneIds);
}
@Override
public int hashCode() {
- return Objects.hash(mUserHandle, mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
+ return Objects.hash(mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
}
/** @hide */
public static final class Builder {
- private UserHandle mUserHandle;
private @EventType int mEventType = EVENT_TYPE_UNKNOWN;
private @NonNull List<String> mTimeZoneIds = Collections.emptyList();
private long mElapsedRealtimeNanos;
@@ -204,21 +185,12 @@ public final class LocationTimeZoneEvent implements Parcelable {
* Sets the contents of this from the supplied instance.
*/
public Builder(@NonNull LocationTimeZoneEvent ltz) {
- mUserHandle = ltz.mUserHandle;
mEventType = ltz.mEventType;
mTimeZoneIds = ltz.mTimeZoneIds;
mElapsedRealtimeNanos = ltz.mElapsedRealtimeNanos;
}
/**
- * Set the current user when this event was generated.
- */
- public Builder setUserHandle(@NonNull UserHandle userHandle) {
- mUserHandle = Objects.requireNonNull(userHandle);
- return this;
- }
-
- /**
* Set the time zone ID of this event.
*/
public Builder setEventType(@EventType int eventType) {
@@ -247,8 +219,7 @@ public final class LocationTimeZoneEvent implements Parcelable {
* Builds a {@link LocationTimeZoneEvent} instance.
*/
public LocationTimeZoneEvent build() {
- return new LocationTimeZoneEvent(
- mUserHandle, mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
+ return new LocationTimeZoneEvent(mEventType, mTimeZoneIds, mElapsedRealtimeNanos);
}
}
diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl
index 01570dc4415d..dac08ff77938 100644
--- a/location/java/com/android/internal/location/ILocationProvider.aidl
+++ b/location/java/com/android/internal/location/ILocationProvider.aidl
@@ -35,6 +35,8 @@ interface ILocationProvider {
@UnsupportedAppUsage(maxTargetSdk = 30, publicAlternatives = "{@code Do not use}")
oneway void setRequest(in ProviderRequest request, in WorkSource ws);
+ oneway void flush();
+
@UnsupportedAppUsage(maxTargetSdk = 30, publicAlternatives = "{@code Do not use}")
oneway void sendExtraCommand(String command, in Bundle extras);
}
diff --git a/location/java/com/android/internal/location/ILocationProviderManager.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl
index 2a6cef812db1..a74538b0334e 100644
--- a/location/java/com/android/internal/location/ILocationProviderManager.aidl
+++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl
@@ -16,7 +16,7 @@
package com.android.internal.location;
-import android.location.Location;
+import android.location.LocationResult;
import com.android.internal.location.ProviderProperties;
@@ -28,5 +28,6 @@ interface ILocationProviderManager {
void onSetIdentity(@nullable String packageName, @nullable String attributionTag);
void onSetAllowed(boolean allowed);
void onSetProperties(in ProviderProperties properties);
- void onReportLocation(in Location location);
+ void onReportLocation(in LocationResult locationResult);
+ void onFlushComplete();
}
diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java
index 00ba5523b8d4..545ea528826b 100644
--- a/location/java/com/android/internal/location/ProviderRequest.java
+++ b/location/java/com/android/internal/location/ProviderRequest.java
@@ -46,7 +46,7 @@ public final class ProviderRequest implements Parcelable {
public static final long INTERVAL_DISABLED = Long.MAX_VALUE;
public static final ProviderRequest EMPTY_REQUEST = new ProviderRequest(
- INTERVAL_DISABLED, QUALITY_BALANCED_POWER_ACCURACY, false, false, new WorkSource());
+ INTERVAL_DISABLED, QUALITY_BALANCED_POWER_ACCURACY, 0, false, false, new WorkSource());
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "{@link "
+ "ProviderRequest}")
@@ -55,6 +55,7 @@ public final class ProviderRequest implements Parcelable {
+ "ProviderRequest}")
public final long interval;
private final @Quality int mQuality;
+ private final long mMaxUpdateDelayMillis;
private final boolean mLowPower;
private final boolean mLocationSettingsIgnored;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "{@link "
@@ -62,11 +63,17 @@ public final class ProviderRequest implements Parcelable {
public final List<LocationRequest> locationRequests;
private final WorkSource mWorkSource;
- private ProviderRequest(long intervalMillis, @Quality int quality, boolean lowPower,
- boolean locationSettingsIgnored, @NonNull WorkSource workSource) {
+ private ProviderRequest(
+ long intervalMillis,
+ @Quality int quality,
+ long maxUpdateDelayMillis,
+ boolean lowPower,
+ boolean locationSettingsIgnored,
+ @NonNull WorkSource workSource) {
reportLocation = intervalMillis != INTERVAL_DISABLED;
interval = intervalMillis;
mQuality = quality;
+ mMaxUpdateDelayMillis = maxUpdateDelayMillis;
mLowPower = lowPower;
mLocationSettingsIgnored = locationSettingsIgnored;
if (intervalMillis != INTERVAL_DISABLED) {
@@ -108,6 +115,17 @@ public final class ProviderRequest implements Parcelable {
}
/**
+ * The maximum time any location update may be delayed, and thus grouped with following updates
+ * to enable location batching. If the maximum update delay is equal to or greater than
+ * twice the interval, then the provider may provide batched results if possible. The maximum
+ * batch size a provider is allowed to return is the maximum update delay divided by the
+ * interval.
+ */
+ public @IntRange(from = 0) long getMaxUpdateDelayMillis() {
+ return mMaxUpdateDelayMillis;
+ }
+
+ /**
* Whether any applicable hardware low power modes should be used to satisfy this request.
*/
public boolean isLowPower() {
@@ -141,6 +159,7 @@ public final class ProviderRequest implements Parcelable {
return new ProviderRequest(
intervalMillis,
/* quality= */ in.readInt(),
+ /* maxUpdateDelayMillis= */ in.readLong(),
/* lowPower= */ in.readBoolean(),
/* locationSettingsIgnored= */ in.readBoolean(),
/* workSource= */ in.readTypedObject(WorkSource.CREATOR));
@@ -163,6 +182,7 @@ public final class ProviderRequest implements Parcelable {
parcel.writeLong(interval);
if (interval != INTERVAL_DISABLED) {
parcel.writeInt(mQuality);
+ parcel.writeLong(mMaxUpdateDelayMillis);
parcel.writeBoolean(mLowPower);
parcel.writeBoolean(mLocationSettingsIgnored);
parcel.writeTypedObject(mWorkSource, flags);
@@ -184,6 +204,7 @@ public final class ProviderRequest implements Parcelable {
} else {
return interval == that.interval
&& mQuality == that.mQuality
+ && mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
&& mLowPower == that.mLowPower
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
&& mWorkSource.equals(that.mWorkSource);
@@ -209,6 +230,10 @@ public final class ProviderRequest implements Parcelable {
s.append(", LOW_POWER");
}
}
+ if (mMaxUpdateDelayMillis / 2 > interval) {
+ s.append(", maxUpdateDelay=");
+ TimeUtils.formatDuration(mMaxUpdateDelayMillis, s);
+ }
if (mLowPower) {
s.append(", lowPower");
}
@@ -231,6 +256,7 @@ public final class ProviderRequest implements Parcelable {
public static class Builder {
private long mIntervalMillis = INTERVAL_DISABLED;
private int mQuality = QUALITY_BALANCED_POWER_ACCURACY;
+ private long mMaxUpdateDelayMillis = 0;
private boolean mLowPower;
private boolean mLocationSettingsIgnored;
private WorkSource mWorkSource = new WorkSource();
@@ -260,6 +286,19 @@ public final class ProviderRequest implements Parcelable {
}
/**
+ * Sets the maximum time any location update may be delayed, and thus grouped with following
+ * updates to enable location batching. If the maximum update delay is equal to or greater
+ * than twice the interval, then location providers may provide batched results. Defaults to
+ * 0.
+ */
+ public @NonNull Builder setMaxUpdateDelayMillis(
+ @IntRange(from = 0) long maxUpdateDelayMillis) {
+ mMaxUpdateDelayMillis = Preconditions.checkArgumentInRange(maxUpdateDelayMillis, 0,
+ Long.MAX_VALUE, "maxUpdateDelayMillis");
+ return this;
+ }
+
+ /**
* Sets whether hardware low power mode should be used. False by default.
*/
public @NonNull Builder setLowPower(boolean lowPower) {
@@ -290,8 +329,13 @@ public final class ProviderRequest implements Parcelable {
if (mIntervalMillis == INTERVAL_DISABLED) {
return EMPTY_REQUEST;
} else {
- return new ProviderRequest(mIntervalMillis, mQuality, mLowPower,
- mLocationSettingsIgnored, mWorkSource);
+ return new ProviderRequest(
+ mIntervalMillis,
+ mQuality,
+ mMaxUpdateDelayMillis,
+ mLowPower,
+ mLocationSettingsIgnored,
+ mWorkSource);
}
}
}
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index 80636c665a1a..d4f7558bf990 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -15,12 +15,14 @@ package com.android.location.provider {
method @Deprecated protected void onDisable();
method @Deprecated protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
method @Deprecated protected void onEnable();
+ method protected void onFlush(com.android.location.provider.LocationProviderBase.OnFlushCompleteCallback);
method @Deprecated protected int onGetStatus(android.os.Bundle);
method @Deprecated protected long onGetStatusUpdateTime();
method protected void onInit();
method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle);
method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
method public void reportLocation(android.location.Location);
+ method public void reportLocation(android.location.LocationResult);
method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setAdditionalProviderPackages(java.util.List<java.lang.String>);
method @RequiresApi(android.os.Build.VERSION_CODES.R) public void setAllowed(boolean);
method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setEnabled(boolean);
@@ -29,6 +31,10 @@ package com.android.location.provider {
field public static final String FUSED_PROVIDER = "fused";
}
+ protected static interface LocationProviderBase.OnFlushCompleteCallback {
+ method public void onFlushComplete();
+ }
+
@Deprecated public final class LocationRequestUnbundled {
method @Deprecated public long getFastestInterval();
method @Deprecated public long getInterval();
@@ -50,6 +56,7 @@ package com.android.location.provider {
public final class ProviderRequestUnbundled {
method public long getInterval();
method @Deprecated @NonNull public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests();
+ method @RequiresApi(android.os.Build.VERSION_CODES.S) public long getMaxUpdateDelayMillis();
method @android.location.LocationRequest.Quality @RequiresApi(android.os.Build.VERSION_CODES.S) public int getQuality();
method public boolean getReportLocation();
method @NonNull @RequiresApi(android.os.Build.VERSION_CODES.S) public android.os.WorkSource getWorkSource();
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index 32ac374b33c2..54d806671e86 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -22,6 +22,7 @@ import android.location.ILocationManager;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
+import android.location.LocationResult;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.IBinder;
@@ -61,6 +62,18 @@ import java.util.List;
public abstract class LocationProviderBase {
/**
+ * Callback to be invoked when a flush operation is complete and all flushed locations have been
+ * reported.
+ */
+ protected interface OnFlushCompleteCallback {
+
+ /**
+ * Should be invoked once the flush is complete.
+ */
+ void onFlushComplete();
+ }
+
+ /**
* Bundle key for a version of the location containing no GPS data.
* Allows location providers to flag locations as being safe to
* feed to LocationFudger.
@@ -235,23 +248,33 @@ public abstract class LocationProviderBase {
* Reports a new location from this provider.
*/
public void reportLocation(Location location) {
+ reportLocation(LocationResult.create(location));
+ }
+
+ /**
+ * Reports a new location from this provider.
+ */
+ public void reportLocation(LocationResult locationResult) {
ILocationProviderManager manager = mManager;
if (manager != null) {
- // remove deprecated extras to save on serialization
- Bundle extras = location.getExtras();
- if (extras != null && (extras.containsKey("noGPSLocation")
- || extras.containsKey("coarseLocation"))) {
- location = new Location(location);
- extras = location.getExtras();
- extras.remove("noGPSLocation");
- extras.remove("coarseLocation");
- if (extras.isEmpty()) {
- location.setExtras(null);
+ locationResult = locationResult.map(location -> {
+ // remove deprecated extras to save on serialization costs
+ Bundle extras = location.getExtras();
+ if (extras != null && (extras.containsKey("noGPSLocation")
+ || extras.containsKey("coarseLocation"))) {
+ location = new Location(location);
+ extras = location.getExtras();
+ extras.remove("noGPSLocation");
+ extras.remove("coarseLocation");
+ if (extras.isEmpty()) {
+ location.setExtras(null);
+ }
}
- }
+ return location;
+ });
try {
- manager.onReportLocation(location);
+ manager.onReportLocation(locationResult);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (RuntimeException e) {
@@ -292,6 +315,16 @@ public abstract class LocationProviderBase {
protected abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
/**
+ * Requests a flush of any pending batched locations. The callback must always be invoked once
+ * per invocation, and should be invoked after {@link #reportLocation(LocationResult)} has been
+ * invoked with any flushed locations. The callback may be invoked immediately if no locations
+ * are flushed.
+ */
+ protected void onFlush(OnFlushCompleteCallback callback) {
+ callback.onFlushComplete();
+ }
+
+ /**
* @deprecated This callback will never be invoked on Android Q and above. This method may be
* removed in the future. Prefer to dump provider state via the containing service instead.
*/
@@ -362,6 +395,24 @@ public abstract class LocationProviderBase {
}
@Override
+ public void flush() {
+ onFlush(this::onFlushComplete);
+ }
+
+ private void onFlushComplete() {
+ ILocationProviderManager manager = mManager;
+ if (manager != null) {
+ try {
+ manager.onFlushComplete();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (RuntimeException e) {
+ Log.w(mTag, e);
+ }
+ }
+ }
+
+ @Override
public void sendExtraCommand(String command, Bundle extras) {
onSendExtraCommand(command, extras);
}
diff --git a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
index f7bac74bf92d..b464fca6f596 100644
--- a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
@@ -57,6 +57,14 @@ public final class ProviderRequestUnbundled {
}
/**
+ * The interval at which a provider should report location. Will return
+ * {@link #INTERVAL_DISABLED} for an inactive request.
+ */
+ public long getInterval() {
+ return mRequest.getIntervalMillis();
+ }
+
+ /**
* The quality hint for this location request. The quality hint informs the provider how it
* should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this
* provider request.
@@ -67,11 +75,15 @@ public final class ProviderRequestUnbundled {
}
/**
- * The interval at which a provider should report location. Will return
- * {@link #INTERVAL_DISABLED} for an inactive request.
+ * The maximum time any location update may be delayed, and thus grouped with following updates
+ * to enable location batching. If the maximum update delay is equal to or greater than
+ * twice the interval, then the provider may provide batched results if possible. The maximum
+ * batch size a provider is allowed to return is the maximum update delay divided by the
+ * interval.
*/
- public long getInterval() {
- return mRequest.getIntervalMillis();
+ @RequiresApi(Build.VERSION_CODES.S)
+ public long getMaxUpdateDelayMillis() {
+ return mRequest.getMaxUpdateDelayMillis();
}
/**
diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java
index aa0e8951f77c..07396333b05c 100644
--- a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java
+++ b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java
@@ -18,10 +18,8 @@ package com.android.location.timezone.provider;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.app.ActivityManager;
import android.location.timezone.LocationTimeZoneEvent;
import android.os.SystemClock;
-import android.os.UserHandle;
import java.util.Collections;
import java.util.List;
@@ -146,7 +144,6 @@ public final class LocationTimeZoneEventUnbundled {
public LocationTimeZoneEventUnbundled build() {
final int internalEventType = this.mEventType;
LocationTimeZoneEvent event = new LocationTimeZoneEvent.Builder()
- .setUserHandle(UserHandle.of(ActivityManager.getCurrentUser()))
.setEventType(internalEventType)
.setTimeZoneIds(mTimeZoneIds)
.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos())
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 477519c0da32..b67851a6b64f 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -22,6 +22,7 @@ import android.util.SparseIntArray;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
import java.util.Objects;
import java.util.TreeSet;
@@ -468,9 +469,32 @@ public final class AudioDeviceInfo {
* @see AudioFormat
*
* Note: an empty array indicates that the device supports arbitrary encodings.
+ * For forward compatibility, applications should ignore entries it does not recognize.
*/
public @NonNull int[] getEncodings() {
- return AudioFormat.filterPublicFormats(mPort.formats());
+ final int[] encodings = AudioFormat.filterPublicFormats(mPort.formats());
+ boolean hasFloat = false;
+ boolean hasExtendedIntegerPrecision = false;
+
+ for (int encoding : encodings) {
+ if (AudioFormat.isEncodingLinearPcm(encoding)) {
+ if (encoding == AudioFormat.ENCODING_PCM_FLOAT) {
+ hasFloat = true;
+ } else if (AudioFormat.getBytesPerSample(encoding) > 2) {
+ hasExtendedIntegerPrecision = true;
+ }
+ }
+ }
+ if (hasExtendedIntegerPrecision && !hasFloat) {
+ // R and earlier compatibility - add ENCODING_PCM_FLOAT to the end
+ // (replacing the zero pad). This ensures pre-S apps that look
+ // for ENCODING_PCM_FLOAT continue to see that encoding if the device supports
+ // extended precision integers.
+ int[] encodingsPlusFloat = Arrays.copyOf(encodings, encodings.length + 1);
+ encodingsPlusFloat[encodings.length] = AudioFormat.ENCODING_PCM_FLOAT;
+ return encodingsPlusFloat;
+ }
+ return encodings;
}
/**
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index a2861c234407..255c15c65ffb 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -110,6 +110,24 @@ import java.util.Objects;
* <code>AudioTrack</code> as of API {@link android.os.Build.VERSION_CODES#LOLLIPOP}
* support <code>ENCODING_PCM_FLOAT</code>.
* </li>
+ * <li> {@link #ENCODING_PCM_24BIT_PACKED}: Introduced in
+ * API {@link android.os.Build.VERSION_CODES#S},
+ * this encoding specifies the audio sample is an
+ * extended precision 24 bit signed integer
+ * stored as a 3 Java bytes in a {@code ByteBuffer} or byte array in native endian
+ * (see {@link java.nio.ByteOrder#nativeOrder()}).
+ * Each sample has full range from [-8388608, 8388607],
+ * and can be interpreted as fixed point Q.23 data.
+ * </li>
+ * <li> {@link #ENCODING_PCM_32BIT}: Introduced in
+ * API {@link android.os.Build.VERSION_CODES#S},
+ * this encoding specifies the audio sample is an
+ * extended precision 32 bit signed integer
+ * stored as a 4 Java bytes in a {@code ByteBuffer} or byte array in native endian
+ * (see {@link java.nio.ByteOrder#nativeOrder()}).
+ * Each sample has full range from [-2147483648, 2147483647],
+ * and can be interpreted as fixed point Q.31 data.
+ * </li>
* </ul>
* <p>For compressed audio, the encoding specifies the method of compression,
* for example {@link #ENCODING_AC3} and {@link #ENCODING_DTS}. The compressed
@@ -285,6 +303,19 @@ public final class AudioFormat implements Parcelable {
/** Audio data format: OPUS compressed. */
public static final int ENCODING_OPUS = 20;
+ /** @hide
+ * We do not permit legacy short array reads or writes for encodings
+ * introduced after this threshold.
+ */
+ public static final int ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD = ENCODING_OPUS;
+
+ /** Audio data format: PCM 24 bit per sample packed as 3 bytes.
+ * Not guaranteed to be supported by devices, may be emulated if not supported. */
+ public static final int ENCODING_PCM_24BIT_PACKED = 21;
+ /** Audio data format: PCM 32 bit per sample.
+ * Not guaranteed to be supported by devices, may be emulated if not supported. */
+ public static final int ENCODING_PCM_32BIT = 22;
+
/** @hide */
public static String toLogFriendlyEncoding(int enc) {
switch(enc) {
@@ -328,6 +359,10 @@ public final class AudioFormat implements Parcelable {
return "ENCODING_DOLBY_MAT";
case ENCODING_OPUS:
return "ENCODING_OPUS";
+ case ENCODING_PCM_24BIT_PACKED:
+ return "ENCODING_PCM_24BIT_PACKED";
+ case ENCODING_PCM_32BIT:
+ return "ENCODING_PCM_32BIT";
default :
return "invalid encoding " + enc;
}
@@ -517,17 +552,20 @@ public final class AudioFormat implements Parcelable {
public static int getBytesPerSample(int audioFormat)
{
switch (audioFormat) {
- case ENCODING_PCM_8BIT:
- return 1;
- case ENCODING_PCM_16BIT:
- case ENCODING_IEC61937:
- case ENCODING_DEFAULT:
- return 2;
- case ENCODING_PCM_FLOAT:
- return 4;
- case ENCODING_INVALID:
- default:
- throw new IllegalArgumentException("Bad audio format " + audioFormat);
+ case ENCODING_PCM_8BIT:
+ return 1;
+ case ENCODING_PCM_16BIT:
+ case ENCODING_IEC61937:
+ case ENCODING_DEFAULT:
+ return 2;
+ case ENCODING_PCM_24BIT_PACKED:
+ return 3;
+ case ENCODING_PCM_FLOAT:
+ case ENCODING_PCM_32BIT:
+ return 4;
+ case ENCODING_INVALID:
+ default:
+ throw new IllegalArgumentException("Bad audio format " + audioFormat);
}
}
@@ -554,6 +592,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT:
case ENCODING_OPUS:
+ case ENCODING_PCM_24BIT_PACKED:
+ case ENCODING_PCM_32BIT:
return true;
default:
return false;
@@ -583,6 +623,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT:
case ENCODING_OPUS:
+ case ENCODING_PCM_24BIT_PACKED:
+ case ENCODING_PCM_32BIT:
return true;
default:
return false;
@@ -597,6 +639,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_PCM_16BIT:
case ENCODING_PCM_8BIT:
case ENCODING_PCM_FLOAT:
+ case ENCODING_PCM_24BIT_PACKED:
+ case ENCODING_PCM_32BIT:
case ENCODING_DEFAULT:
return true;
case ENCODING_AC3:
@@ -630,6 +674,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_PCM_8BIT:
case ENCODING_PCM_FLOAT:
case ENCODING_IEC61937: // same size as stereo PCM
+ case ENCODING_PCM_24BIT_PACKED:
+ case ENCODING_PCM_32BIT:
case ENCODING_DEFAULT:
return true;
case ENCODING_AC3:
@@ -927,6 +973,8 @@ public final class AudioFormat implements Parcelable {
case ENCODING_E_AC3_JOC:
case ENCODING_DOLBY_MAT:
case ENCODING_OPUS:
+ case ENCODING_PCM_24BIT_PACKED:
+ case ENCODING_PCM_32BIT:
mEncoding = encoding;
break;
case ENCODING_INVALID:
@@ -1147,7 +1195,9 @@ public final class AudioFormat implements Parcelable {
ENCODING_AC4,
ENCODING_E_AC3_JOC,
ENCODING_DOLBY_MAT,
- ENCODING_OPUS }
+ ENCODING_OPUS,
+ ENCODING_PCM_24BIT_PACKED,
+ ENCODING_PCM_32BIT }
)
@Retention(RetentionPolicy.SOURCE)
public @interface Encoding {}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 29477366379b..457888361f73 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4009,8 +4009,8 @@ public class AudioManager {
* @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
*/
@SystemApi
- @SuppressLint("Doclava125") // no permission enforcement, but only "undoes" what would have been
- // done by a matching requestAudioFocus
+ @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
+ // have been done by a matching requestAudioFocus
public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
int status = AUDIOFOCUS_REQUEST_FAILED;
unregisterAudioFocusRequest(l);
@@ -5602,7 +5602,7 @@ public class AudioManager {
* @hide
*/
@SystemApi
- @SuppressLint("Doclava125") // FIXME is this still used?
+ @SuppressLint("RequiresPermission") // FIXME is this still used?
public boolean isHdmiSystemAudioSupported() {
try {
return getService().isHdmiSystemAudioSupported();
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 07c8ee514e07..65e6feaa31d3 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -850,17 +850,21 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
//--------------
// audio format
switch (audioFormat) {
- case AudioFormat.ENCODING_DEFAULT:
- mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
- break;
- case AudioFormat.ENCODING_PCM_FLOAT:
- case AudioFormat.ENCODING_PCM_16BIT:
- case AudioFormat.ENCODING_PCM_8BIT:
- mAudioFormat = audioFormat;
- break;
- default:
- throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat
- + ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, or ENCODING_PCM_FLOAT.");
+ case AudioFormat.ENCODING_DEFAULT:
+ mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
+ break;
+ case AudioFormat.ENCODING_PCM_24BIT_PACKED:
+ case AudioFormat.ENCODING_PCM_32BIT:
+ case AudioFormat.ENCODING_PCM_FLOAT:
+ case AudioFormat.ENCODING_PCM_16BIT:
+ case AudioFormat.ENCODING_PCM_8BIT:
+ mAudioFormat = audioFormat;
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported sample encoding " + audioFormat
+ + ". Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT,"
+ + " ENCODING_PCM_24BIT_PACKED, ENCODING_PCM_32BIT,"
+ + " or ENCODING_PCM_FLOAT.");
}
}
@@ -1267,6 +1271,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
*/
public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
@ReadMode int readMode) {
+ // Note: we allow reads of extended integers into a byte array.
if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
return ERROR_INVALID_OPERATION;
}
@@ -1339,7 +1344,10 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
*/
public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
@ReadMode int readMode) {
- if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
+ if (mState != STATE_INITIALIZED
+ || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT
+ // use ByteBuffer instead for later encodings
+ || mAudioFormat > AudioFormat.ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD) {
return ERROR_INVALID_OPERATION;
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b2c2c4b1bbb4..e8c62067580f 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -2892,7 +2892,7 @@ public class AudioTrack extends PlayerBase
*/
public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
@WriteMode int writeMode) {
-
+ // Note: we allow writes of extended integers and compressed formats from a byte array.
if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
return ERROR_INVALID_OPERATION;
}
@@ -3006,7 +3006,10 @@ public class AudioTrack extends PlayerBase
public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
@WriteMode int writeMode) {
- if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
+ if (mState == STATE_UNINITIALIZED
+ || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT
+ // use ByteBuffer or byte[] instead for later encodings
+ || mAudioFormat > AudioFormat.ENCODING_LEGACY_SHORT_ARRAY_THRESHOLD) {
return ERROR_INVALID_OPERATION;
}
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 44890bee2291..de885f49a1d4 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -32,7 +32,6 @@ import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.FileUtils;
-import android.os.SystemProperties;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -79,7 +78,8 @@ import java.util.zip.CRC32;
/**
* This is a class for reading and writing Exif tags in various image file formats.
* <p>
- * Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF.
+ * Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF,
+ * AVIF.
* <p>
* Supported for writing: JPEG, PNG, WebP.
* <p>
@@ -543,6 +543,8 @@ public class ExifInterface {
private static final byte[] HEIF_TYPE_FTYP = new byte[] {'f', 't', 'y', 'p'};
private static final byte[] HEIF_BRAND_MIF1 = new byte[] {'m', 'i', 'f', '1'};
private static final byte[] HEIF_BRAND_HEIC = new byte[] {'h', 'e', 'i', 'c'};
+ private static final byte[] HEIF_BRAND_AVIF = new byte[] {'a', 'v', 'i', 'f'};
+ private static final byte[] HEIF_BRAND_AVIS = new byte[] {'a', 'v', 'i', 's'};
// See http://fileformats.archiveteam.org/wiki/Olympus_ORF
private static final short ORF_SIGNATURE_1 = 0x4f52;
@@ -1525,8 +1527,7 @@ public class ExifInterface {
if (fileDescriptor == null) {
throw new NullPointerException("fileDescriptor cannot be null");
}
- boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_exif_optimize", false);
- FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(fileDescriptor) : null;
+ FileDescriptor modernFd = FileUtils.convertToModernFd(fileDescriptor);
if (modernFd != null) {
fileDescriptor = modernFd;
}
@@ -2546,9 +2547,7 @@ public class ExifInterface {
mIsInputStream = false;
try {
in = new FileInputStream(filename);
- boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_exif_optimize",
- false);
- FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(in.getFD()) : null;
+ FileDescriptor modernFd = FileUtils.convertToModernFd(in.getFD());
if (modernFd != null) {
legacyInputStream = in;
in = new FileInputStream(modernFd);
@@ -2662,6 +2661,7 @@ public class ExifInterface {
byte[] brand = new byte[4];
boolean isMif1 = false;
boolean isHeic = false;
+ boolean isAvif = false;
for (long i = 0; i < chunkDataSize / 4; ++i) {
if (signatureInputStream.read(brand) != brand.length) {
return false;
@@ -2674,8 +2674,11 @@ public class ExifInterface {
isMif1 = true;
} else if (Arrays.equals(brand, HEIF_BRAND_HEIC)) {
isHeic = true;
+ } else if (Arrays.equals(brand, HEIF_BRAND_AVIF)
+ || Arrays.equals(brand, HEIF_BRAND_AVIS)) {
+ isAvif = true;
}
- if (isMif1 && isHeic) {
+ if (isMif1 && (isHeic || isAvif)) {
return true;
}
}
diff --git a/media/java/android/media/IRemoteVolumeController.aidl b/media/java/android/media/IRemoteVolumeControllerCallback.aidl
index 74c05c407571..34c63612b912 100644
--- a/media/java/android/media/IRemoteVolumeController.aidl
+++ b/media/java/android/media/IRemoteVolumeControllerCallback.aidl
@@ -25,9 +25,9 @@ import android.media.session.MediaSession;
* TODO add in better support for multiple remote sessions.
* @hide
*/
-oneway interface IRemoteVolumeController {
- void remoteVolumeChanged(in MediaSession.Token sessionToken, int flags);
+oneway interface IRemoteVolumeControllerCallback {
+ void onVolumeChanged(in MediaSession.Token sessionToken, int flags);
// sets the default session to use with the slider, replaces remoteSliderVisibility
// on IVolumeController
- void updateRemoteController(in MediaSession.Token sessionToken);
+ void onSessionChanged(in MediaSession.Token sessionToken);
}
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 610bffe13eae..0ef4b94f6e37 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -200,6 +200,7 @@ public abstract class Image implements AutoCloseable {
* @return The window transformation that needs to be applied for this frame.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract int getTransform();
/**
@@ -207,6 +208,7 @@ public abstract class Image implements AutoCloseable {
* @return The scaling mode that needs to be applied for this frame.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract int getScalingMode();
/**
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 4b208ce1ec37..9957975f1692 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -20,7 +20,6 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
-import android.app.ActivityManager;
import android.content.Context;
import android.hardware.cas.V1_0.HidlCasPluginDescriptor;
import android.hardware.cas.V1_0.ICas;
@@ -676,18 +675,10 @@ public final class MediaCas implements AutoCloseable {
return null;
}
- /**
- * Instantiate a CA system of the specified system id.
- *
- * @param CA_system_id The system id of the CA system.
- *
- * @throws UnsupportedCasException if the device does not support the
- * specified CA system.
- */
- public MediaCas(int CA_system_id) throws UnsupportedCasException {
+ private void createPlugin(int casSystemId) throws UnsupportedCasException {
try {
- mCasSystemId = CA_system_id;
- mUserId = ActivityManager.getCurrentUser();
+ mCasSystemId = casSystemId;
+ mUserId = Process.myUid();
IMediaCasService service = getService();
android.hardware.cas.V1_2.IMediaCasService serviceV12 =
android.hardware.cas.V1_2.IMediaCasService.castFrom(service);
@@ -696,16 +687,16 @@ public final class MediaCas implements AutoCloseable {
android.hardware.cas.V1_1.IMediaCasService.castFrom(service);
if (serviceV11 == null) {
Log.d(TAG, "Used cas@1_0 interface to create plugin");
- mICas = service.createPlugin(CA_system_id, mBinder);
+ mICas = service.createPlugin(casSystemId, mBinder);
} else {
Log.d(TAG, "Used cas@1.1 interface to create plugin");
- mICas = mICasV11 = serviceV11.createPluginExt(CA_system_id, mBinder);
+ mICas = mICasV11 = serviceV11.createPluginExt(casSystemId, mBinder);
}
} else {
Log.d(TAG, "Used cas@1.2 interface to create plugin");
mICas = mICasV11 = mICasV12 =
android.hardware.cas.V1_2.ICas
- .castFrom(serviceV12.createPluginExt(CA_system_id, mBinder));
+ .castFrom(serviceV12.createPluginExt(casSystemId, mBinder));
}
} catch(Exception e) {
Log.e(TAG, "Failed to create plugin: " + e);
@@ -713,11 +704,37 @@ public final class MediaCas implements AutoCloseable {
} finally {
if (mICas == null) {
throw new UnsupportedCasException(
- "Unsupported CA_system_id " + CA_system_id);
+ "Unsupported casSystemId " + casSystemId);
}
}
}
+ private void registerClient(@NonNull Context context,
+ @Nullable String tvInputServiceSessionId, @PriorityHintUseCaseType int priorityHint) {
+
+ mTunerResourceManager = (TunerResourceManager)
+ context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
+ if (mTunerResourceManager != null) {
+ int[] clientId = new int[1];
+ ResourceClientProfile profile =
+ new ResourceClientProfile(tvInputServiceSessionId, priorityHint);
+ mTunerResourceManager.registerClientProfile(
+ profile, context.getMainExecutor(), mResourceListener, clientId);
+ mClientId = clientId[0];
+ }
+ }
+ /**
+ * Instantiate a CA system of the specified system id.
+ *
+ * @param casSystemId The system id of the CA system.
+ *
+ * @throws UnsupportedCasException if the device does not support the
+ * specified CA system.
+ */
+ public MediaCas(int casSystemId) throws UnsupportedCasException {
+ createPlugin(casSystemId);
+ }
+
/**
* Instantiate a CA system of the specified system id.
*
@@ -733,19 +750,35 @@ public final class MediaCas implements AutoCloseable {
public MediaCas(@NonNull Context context, int casSystemId,
@Nullable String tvInputServiceSessionId,
@PriorityHintUseCaseType int priorityHint) throws UnsupportedCasException {
- this(casSystemId);
-
Objects.requireNonNull(context, "context must not be null");
- mTunerResourceManager = (TunerResourceManager)
- context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
- if (mTunerResourceManager != null) {
- int[] clientId = new int[1];
- ResourceClientProfile profile =
- new ResourceClientProfile(tvInputServiceSessionId, priorityHint);
- mTunerResourceManager.registerClientProfile(
- profile, context.getMainExecutor(), mResourceListener, clientId);
- mClientId = clientId[0];
- }
+ createPlugin(casSystemId);
+ registerClient(context, tvInputServiceSessionId, priorityHint);
+ }
+ /**
+ * Instantiate a CA system of the specified system id with EvenListener.
+ *
+ * @param context the context of the caller.
+ * @param casSystemId The system id of the CA system.
+ * @param tvInputServiceSessionId The Id of the session opened in TV Input Service (TIS)
+ * {@link android.media.tv.TvInputService#onCreateSession(String, String)}
+ * @param priorityHint priority hint from the use case type for new created CAS system.
+ * @param listener the event listener to be set.
+ * @param handler the handler whose looper the event listener will be called on.
+ * If handler is null, we'll try to use current thread's looper, or the main
+ * looper. If neither are available, an internal thread will be created instead.
+ *
+ * @throws UnsupportedCasException if the device does not support the
+ * specified CA system.
+ */
+ public MediaCas(@NonNull Context context, int casSystemId,
+ @Nullable String tvInputServiceSessionId,
+ @PriorityHintUseCaseType int priorityHint,
+ @Nullable Handler handler, @Nullable EventListener listener)
+ throws UnsupportedCasException {
+ Objects.requireNonNull(context, "context must not be null");
+ setEventListener(listener, handler);
+ createPlugin(casSystemId);
+ registerClient(context, tvInputServiceSessionId, priorityHint);
}
IHwBinder getBinder() {
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index ca8b9b936e99..86d1d15c8b74 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -300,9 +300,7 @@ public class MediaMetadataRetriever implements AutoCloseable {
*/
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IllegalArgumentException {
- boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_retriever_optimize",
- false);
- FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(fd) : null;
+ FileDescriptor modernFd = FileUtils.convertToModernFd(fd);
if (modernFd == null) {
_setDataSource(fd, offset, length);
} else {
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 42e39101de13..973c2a82c549 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -16,6 +16,9 @@
package android.media;
+import static android.Manifest.permission.BIND_IMS_SERVICE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -83,6 +86,7 @@ import java.util.BitSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Scanner;
import java.util.Set;
import java.util.UUID;
@@ -1254,8 +1258,7 @@ public class MediaPlayer extends PlayerBase
*/
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException {
- boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_player_optimize", false);
- FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(fd) : null;
+ FileDescriptor modernFd = FileUtils.convertToModernFd(fd);
if (modernFd == null) {
_setDataSource(fd, offset, length);
} else {
@@ -2109,8 +2112,8 @@ public class MediaPlayer extends PlayerBase
mOnInfoListener = null;
mOnVideoSizeChangedListener = null;
mOnTimedTextListener = null;
- mOnImsRxNoticeListener = null;
- mOnImsRxNoticeHandler = null;
+ mOnRtpRxNoticeListener = null;
+ mOnRtpRxNoticeHandler = null;
synchronized (mTimeProviderLock) {
if (mTimeProvider != null) {
mTimeProvider.close();
@@ -3323,7 +3326,7 @@ public class MediaPlayer extends PlayerBase
private static final int MEDIA_META_DATA = 202;
private static final int MEDIA_DRM_INFO = 210;
private static final int MEDIA_TIME_DISCONTINUITY = 211;
- private static final int MEDIA_IMS_RX_NOTICE = 300;
+ private static final int MEDIA_RTP_RX_NOTICE = 300;
private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
private TimeProvider mTimeProvider;
@@ -3633,31 +3636,34 @@ public class MediaPlayer extends PlayerBase
}
return;
- case MEDIA_IMS_RX_NOTICE:
- final OnImsRxNoticeListener imsRxNoticeListener;
- final Handler imsRxNoticeHandler;
- imsRxNoticeListener = mOnImsRxNoticeListener;
- imsRxNoticeHandler = mOnImsRxNoticeHandler;
- if (imsRxNoticeListener == null) {
+ case MEDIA_RTP_RX_NOTICE:
+ final OnRtpRxNoticeListener rtpRxNoticeListener = mOnRtpRxNoticeListener;
+ final Handler rtpRxNoticeHandler = mOnRtpRxNoticeHandler;
+ if (rtpRxNoticeListener == null) {
return;
}
if (msg.obj instanceof Parcel) {
Parcel parcel = (Parcel) msg.obj;
- byte[] event;
+ parcel.setDataPosition(0);
+ int noticeType;
+ int[] data;
try {
- event = parcel.marshall();
+ noticeType = parcel.readInt();
+ int numOfArgs = parcel.dataAvail() / 4;
+ data = new int[numOfArgs];
+ for (int i = 0; i < numOfArgs; i++) {
+ data[i] = parcel.readInt();
+ }
} finally {
parcel.recycle();
}
- if (imsRxNoticeHandler == null) {
- imsRxNoticeListener.onImsRxNotice(mMediaPlayer, event);
+ if (rtpRxNoticeHandler == null) {
+ rtpRxNoticeListener.onRtpRxNotice(mMediaPlayer, noticeType, data);
} else {
- imsRxNoticeHandler.post(new Runnable() {
- @Override
- public void run() {
- imsRxNoticeListener.onImsRxNotice(mMediaPlayer, event);
- }
- });
+ rtpRxNoticeHandler.post(
+ () ->
+ rtpRxNoticeListener
+ .onRtpRxNotice(mMediaPlayer, noticeType, data));
}
}
return;
@@ -4103,18 +4109,18 @@ public class MediaPlayer extends PlayerBase
/**
* Interface definition of a callback to be invoked when
- * IMS Rx connection has a notice.
+ * RTP Rx connection has a notice.
*
- * @see MediaPlayer.setOnImsRxNoticeListener
+ * @see #setOnRtpRxNoticeListener
*
* @hide
*/
@SystemApi
- public interface OnImsRxNoticeListener
+ public interface OnRtpRxNoticeListener
{
/**
- * Called to indicate an IMS event noticed from native media frameworks.
- * <p></p>
+ * Called when an RTP Rx connection has a notice.
+ * <p>
* Basic format. All TYPE and ARG are 4 bytes unsigned integer in native byte order.
* <pre>{@code
* 0 4 8 12
@@ -4169,14 +4175,14 @@ public class MediaPlayer extends PlayerBase
* TYPE 205 - Transport layer Feedback message. (RFC-5104 Sec.4.2)
* 0 4 8 12
* +----------------+---------------+----------------+----------------+
- * | 205 | SSRC | FB type(1 or 3)| value |
+ * | 205 |FB type(1 or 3)| SSRC | Value |
* +----------------+---------------+----------------+----------------+
- * SSRC
- * - Remote side's SSRC value of the media sender (RFC-3550 Sec.5.1)
* Feedback (FB) type: determines the type of the event.
* - if 1, we received a NACK request from the remote side.
* - if 3, we received a TMMBR (Temporary Maximum Media Stream Bit Rate Request) from
* the remote side.
+ * SSRC
+ * - Remote side's SSRC value of the media sender (RFC-3550 Sec.5.1)
* Value: the FCI (Feedback Control Information) depending on the value of FB type
* - if FB type is 1, the Generic NACK as specified in RFC-4585 Sec.6.2.1
* - if FB type is 3, the TMMBR as specified in RFC-5104 Sec.4.2.1.1
@@ -4185,13 +4191,13 @@ public class MediaPlayer extends PlayerBase
* TYPE 206 - Payload-specific Feedback message. (RFC-5104 Sec.4.3)
* 0 4 8
* +----------------+---------------+----------------+
- * | 206 | SSRC | FB type(1 or 4)|
+ * | 206 |FB type(1 or 4)| SSRC |
* +----------------+---------------+----------------+
- * SSRC
- * - Remote side's SSRC value of the media sender (RFC-3550 Sec.5.1)
* Feedback (FB) type: determines the type of the event.
* - if 1, we received a PLI request from the remote side.
* - if 4, we received a FIR request from the remote side.
+ * SSRC
+ * - Remote side's SSRC value of the media sender (RFC-3550 Sec.5.1)
*
*
* TYPE 300 - CVO (RTP Extension) message.
@@ -4212,34 +4218,39 @@ public class MediaPlayer extends PlayerBase
* }</pre>
*
* @param mp the {@code MediaPlayer} associated with this callback.
- * @param event an IMS media event serialized as byte[] array.
+ * @param noticeType TYPE of the event.
+ * @param params RTP Rx media data serialized as int[] array.
*/
- void onImsRxNotice(@NonNull MediaPlayer mp, @NonNull byte[] event);
+ void onRtpRxNotice(@NonNull MediaPlayer mp, int noticeType, @NonNull int[] params);
}
/**
- * Register a callback to be invoked when IMS Rx connection has a notice.
- * The callback required if mediaplayer configured for RTPSource by
- * MediaPlayer.setDataSource(String8 rtpParams) of mediaplayer.h
+ * Sets the listener to be invoked when an RTP Rx connection has a notice.
+ * The listener is required if MediaPlayer is configured for RTPSource by
+ * MediaPlayer.setDataSource(String8 rtpParams) of mediaplayer.h.
*
- * @see MediaPlayer.OnImsRxNoticeListener
+ * @see OnRtpRxNoticeListener
*
- * @param listener the callback that will be run
- * @param handler Specifies Handler object for the thread on which to execute
- * the callback. If null, the handler on the main looper will be used.
+ * @param listener the listener called after a notice from RTP Rx
+ * @param handler the {@link Handler} that receives RTP Tx events
*
* @hide
*/
@SystemApi
@RequiresPermission("android.permission.BIND_IMS_SERVICE")
- public void setOnImsRxNoticeListener(
- @Nullable OnImsRxNoticeListener listener, @Nullable Handler handler) {
- mOnImsRxNoticeListener = listener;
- mOnImsRxNoticeHandler = handler;
- }
-
- private OnImsRxNoticeListener mOnImsRxNoticeListener;
- private Handler mOnImsRxNoticeHandler;
+ public void setOnRtpRxNoticeListener(
+ @NonNull Context context,
+ @NonNull OnRtpRxNoticeListener listener, @Nullable Handler handler) {
+ Objects.requireNonNull(context);
+ Preconditions.checkArgument(
+ context.checkSelfPermission(BIND_IMS_SERVICE) == PERMISSION_GRANTED,
+ "android.permission.BIND_IMS_SERVICE permission not granted.");
+ mOnRtpRxNoticeListener = Objects.requireNonNull(listener);
+ mOnRtpRxNoticeHandler = handler;
+ }
+
+ private OnRtpRxNoticeListener mOnRtpRxNoticeListener;
+ private Handler mOnRtpRxNoticeHandler;
/**
* Register a callback to be invoked when a selected track has timed metadata available.
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index df5e85edbc30..da69c6cbbb5c 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -520,11 +520,12 @@ public abstract class PlayerBase {
@Override
public void applyVolumeShaper(
- @NonNull VolumeShaper.Configuration configuration,
- @NonNull VolumeShaper.Operation operation) {
+ @NonNull VolumeShaperConfiguration configuration,
+ @NonNull VolumeShaperOperation operation) {
final PlayerBase pb = mWeakPB.get();
if (pb != null) {
- pb.playerApplyVolumeShaper(configuration, operation);
+ pb.playerApplyVolumeShaper(VolumeShaper.Configuration.fromParcelable(configuration),
+ VolumeShaper.Operation.fromParcelable(operation));
}
}
}
diff --git a/media/java/android/media/PlayerProxy.java b/media/java/android/media/PlayerProxy.java
index 5f3997a50ce4..ec391284b0b2 100644
--- a/media/java/android/media/PlayerProxy.java
+++ b/media/java/android/media/PlayerProxy.java
@@ -143,7 +143,8 @@ public class PlayerProxy {
@NonNull VolumeShaper.Configuration configuration,
@NonNull VolumeShaper.Operation operation) {
try {
- mConf.getIPlayer().applyVolumeShaper(configuration, operation);
+ mConf.getIPlayer().applyVolumeShaper(configuration.toParcelable(),
+ operation.toParcelable());
} catch (NullPointerException|RemoteException e) {
throw new IllegalStateException(
"No player to proxy for applyVolumeShaper operation,"
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index fbf38dc4d808..e6d95eb6d5a1 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -272,7 +272,8 @@ public class ThumbnailUtils {
if (mimeType.equals("image/heif")
|| mimeType.equals("image/heif-sequence")
|| mimeType.equals("image/heic")
- || mimeType.equals("image/heic-sequence")) {
+ || mimeType.equals("image/heic-sequence")
+ || mimeType.equals("image/avif")) {
try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) {
retriever.setDataSource(file.getAbsolutePath());
bitmap = retriever.getThumbnailImageAtIndex(-1,
diff --git a/media/java/android/media/VolumeShaper.java b/media/java/android/media/VolumeShaper.java
index df8d08e8e846..5bad6934f981 100644
--- a/media/java/android/media/VolumeShaper.java
+++ b/media/java/android/media/VolumeShaper.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
+import android.os.BadParcelableException;
import android.os.Parcel;
import android.os.Parcelable;
@@ -482,50 +483,62 @@ public final class VolumeShaper implements AutoCloseable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- // this needs to match the native VolumeShaper.Configuration parceling
- dest.writeInt(mType);
- dest.writeInt(mId);
+ VolumeShaperConfiguration parcelable = toParcelable();
+ parcelable.writeToParcel(dest, flags);
+ }
+
+ /** @hide */
+ public VolumeShaperConfiguration toParcelable() {
+ VolumeShaperConfiguration parcelable = new VolumeShaperConfiguration();
+ parcelable.type = typeToAidl(mType);
+ parcelable.id = mId;
if (mType != TYPE_ID) {
- dest.writeInt(mOptionFlags);
- dest.writeDouble(mDurationMs);
- // this needs to match the native Interpolator parceling
- dest.writeInt(mInterpolatorType);
- dest.writeFloat(0.f); // first slope (specifying for native side)
- dest.writeFloat(0.f); // last slope (specifying for native side)
- // mTimes and mVolumes should have the same length.
- dest.writeInt(mTimes.length);
- for (int i = 0; i < mTimes.length; ++i) {
- dest.writeFloat(mTimes[i]);
- dest.writeFloat(mVolumes[i]);
- }
+ parcelable.optionFlags = optionFlagsToAidl(mOptionFlags);
+ parcelable.durationMs = mDurationMs;
+ parcelable.interpolatorConfig = toInterpolatorParcelable();
}
+ return parcelable;
}
- public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.Configuration> CREATOR
- = new Parcelable.Creator<VolumeShaper.Configuration>() {
- @Override
- public VolumeShaper.Configuration createFromParcel(Parcel p) {
- // this needs to match the native VolumeShaper.Configuration parceling
- final int type = p.readInt();
- final int id = p.readInt();
- if (type == TYPE_ID) {
- return new VolumeShaper.Configuration(id);
- } else {
- final int optionFlags = p.readInt();
- final double durationMs = p.readDouble();
- // this needs to match the native Interpolator parceling
- final int interpolatorType = p.readInt();
- final float firstSlope = p.readFloat(); // ignored on the Java side
- final float lastSlope = p.readFloat(); // ignored on the Java side
- final int length = p.readInt();
- final float[] times = new float[length];
- final float[] volumes = new float[length];
- for (int i = 0; i < length; ++i) {
- times[i] = p.readFloat();
- volumes[i] = p.readFloat();
- }
+ private InterpolatorConfig toInterpolatorParcelable() {
+ InterpolatorConfig parcelable = new InterpolatorConfig();
+ parcelable.type = interpolatorTypeToAidl(mInterpolatorType);
+ parcelable.firstSlope = 0.f; // first slope (specifying for native side)
+ parcelable.lastSlope = 0.f; // last slope (specifying for native side)
+ parcelable.xy = new float[mTimes.length * 2];
+ for (int i = 0; i < mTimes.length; ++i) {
+ parcelable.xy[i * 2] = mTimes[i];
+ parcelable.xy[i * 2 + 1] = mVolumes[i];
+ }
+ return parcelable;
+ }
+
+ /** @hide */
+ public static Configuration fromParcelable(VolumeShaperConfiguration parcelable) {
+ // this needs to match the native VolumeShaper.Configuration parceling
+ final int type = typeFromAidl(parcelable.type);
+ final int id = parcelable.id;
+ if (type == TYPE_ID) {
+ return new VolumeShaper.Configuration(id);
+ } else {
+ final int optionFlags = optionFlagsFromAidl(parcelable.optionFlags);
+ final double durationMs = parcelable.durationMs;
+ final int interpolatorType = interpolatorTypeFromAidl(
+ parcelable.interpolatorConfig.type);
+ // parcelable.interpolatorConfig.firstSlope is ignored on the Java side
+ // parcelable.interpolatorConfig.lastSlope is ignored on the Java side
+ final int length = parcelable.interpolatorConfig.xy.length;
+ if (length % 2 != 0) {
+ throw new android.os.BadParcelableException("xy length must be even");
+ }
+ final float[] times = new float[length / 2];
+ final float[] volumes = new float[length / 2];
+ for (int i = 0; i < length / 2; ++i) {
+ times[i] = parcelable.interpolatorConfig.xy[i * 2];
+ volumes[i] = parcelable.interpolatorConfig.xy[i * 2 + 1];
+ }
- return new VolumeShaper.Configuration(
+ return new VolumeShaper.Configuration(
type,
id,
optionFlags,
@@ -533,7 +546,14 @@ public final class VolumeShaper implements AutoCloseable {
interpolatorType,
times,
volumes);
- }
+ }
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.Configuration> CREATOR
+ = new Parcelable.Creator<VolumeShaper.Configuration>() {
+ @Override
+ public VolumeShaper.Configuration createFromParcel(Parcel p) {
+ return fromParcelable(VolumeShaperConfiguration.CREATOR.createFromParcel(p));
}
@Override
@@ -542,6 +562,84 @@ public final class VolumeShaper implements AutoCloseable {
}
};
+ private static @InterpolatorType
+ int interpolatorTypeFromAidl(@android.media.InterpolatorType int aidl) {
+ switch (aidl) {
+ case android.media.InterpolatorType.STEP:
+ return INTERPOLATOR_TYPE_STEP;
+ case android.media.InterpolatorType.LINEAR:
+ return INTERPOLATOR_TYPE_LINEAR;
+ case android.media.InterpolatorType.CUBIC:
+ return INTERPOLATOR_TYPE_CUBIC;
+ case android.media.InterpolatorType.CUBIC_MONOTONIC:
+ return INTERPOLATOR_TYPE_CUBIC_MONOTONIC;
+ default:
+ throw new BadParcelableException("Unknown interpolator type");
+ }
+ }
+
+ private static @android.media.InterpolatorType
+ int interpolatorTypeToAidl(@InterpolatorType int type) {
+ switch (type) {
+ case INTERPOLATOR_TYPE_STEP:
+ return android.media.InterpolatorType.STEP;
+ case INTERPOLATOR_TYPE_LINEAR:
+ return android.media.InterpolatorType.LINEAR;
+ case INTERPOLATOR_TYPE_CUBIC:
+ return android.media.InterpolatorType.CUBIC;
+ case INTERPOLATOR_TYPE_CUBIC_MONOTONIC:
+ return android.media.InterpolatorType.CUBIC_MONOTONIC;
+ default:
+ throw new RuntimeException("Unknown interpolator type");
+ }
+ }
+
+ private static @Type
+ int typeFromAidl(@android.media.VolumeShaperConfigurationType int aidl) {
+ switch (aidl) {
+ case VolumeShaperConfigurationType.ID:
+ return TYPE_ID;
+ case VolumeShaperConfigurationType.SCALE:
+ return TYPE_SCALE;
+ default:
+ throw new BadParcelableException("Unknown type");
+ }
+ }
+
+ private static @android.media.VolumeShaperConfigurationType
+ int typeToAidl(@Type int type) {
+ switch (type) {
+ case TYPE_ID:
+ return VolumeShaperConfigurationType.ID;
+ case TYPE_SCALE:
+ return VolumeShaperConfigurationType.SCALE;
+ default:
+ throw new RuntimeException("Unknown type");
+ }
+ }
+
+ private static int optionFlagsFromAidl(int aidl) {
+ int result = 0;
+ if ((aidl & (1 << VolumeShaperConfigurationOptionFlag.VOLUME_IN_DBFS)) != 0) {
+ result |= OPTION_FLAG_VOLUME_IN_DBFS;
+ }
+ if ((aidl & (1 << VolumeShaperConfigurationOptionFlag.CLOCK_TIME)) != 0) {
+ result |= OPTION_FLAG_CLOCK_TIME;
+ }
+ return result;
+ }
+
+ private static int optionFlagsToAidl(int flags) {
+ int result = 0;
+ if ((flags & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
+ result |= (1 << VolumeShaperConfigurationOptionFlag.VOLUME_IN_DBFS);
+ }
+ if ((flags & OPTION_FLAG_CLOCK_TIME) != 0) {
+ result |= (1 << VolumeShaperConfigurationOptionFlag.CLOCK_TIME);
+ }
+ return result;
+ }
+
/**
* @hide
* Constructs a {@code VolumeShaper} from an id.
@@ -1172,25 +1270,31 @@ public final class VolumeShaper implements AutoCloseable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- // this needs to match the native VolumeShaper.Operation parceling
- dest.writeInt(mFlags);
- dest.writeInt(mReplaceId);
- dest.writeFloat(mXOffset);
+ toParcelable().writeToParcel(dest, flags);
+ }
+
+ /** @hide */
+ public VolumeShaperOperation toParcelable() {
+ VolumeShaperOperation result = new VolumeShaperOperation();
+ result.flags = flagsToAidl(mFlags);
+ result.replaceId = mReplaceId;
+ result.xOffset = mXOffset;
+ return result;
+ }
+
+ /** @hide */
+ public static Operation fromParcelable(VolumeShaperOperation parcelable) {
+ return new VolumeShaper.Operation(
+ flagsFromAidl(parcelable.flags),
+ parcelable.replaceId,
+ parcelable.xOffset);
}
public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.Operation> CREATOR
= new Parcelable.Creator<VolumeShaper.Operation>() {
@Override
public VolumeShaper.Operation createFromParcel(Parcel p) {
- // this needs to match the native VolumeShaper.Operation parceling
- final int flags = p.readInt();
- final int replaceId = p.readInt();
- final float xOffset = p.readFloat();
-
- return new VolumeShaper.Operation(
- flags
- , replaceId
- , xOffset);
+ return fromParcelable(VolumeShaperOperation.CREATOR.createFromParcel(p));
}
@Override
@@ -1199,6 +1303,46 @@ public final class VolumeShaper implements AutoCloseable {
}
};
+ private static int flagsFromAidl(int aidl) {
+ int result = 0;
+ if ((aidl & (1 << VolumeShaperOperationFlag.REVERSE)) != 0) {
+ result |= FLAG_REVERSE;
+ }
+ if ((aidl & (1 << VolumeShaperOperationFlag.TERMINATE)) != 0) {
+ result |= FLAG_TERMINATE;
+ }
+ if ((aidl & (1 << VolumeShaperOperationFlag.JOIN)) != 0) {
+ result |= FLAG_JOIN;
+ }
+ if ((aidl & (1 << VolumeShaperOperationFlag.DELAY)) != 0) {
+ result |= FLAG_DEFER;
+ }
+ if ((aidl & (1 << VolumeShaperOperationFlag.CREATE_IF_NECESSARY)) != 0) {
+ result |= FLAG_CREATE_IF_NEEDED;
+ }
+ return result;
+ }
+
+ private static int flagsToAidl(int flags) {
+ int result = 0;
+ if ((flags & FLAG_REVERSE) != 0) {
+ result |= (1 << VolumeShaperOperationFlag.REVERSE);
+ }
+ if ((flags & FLAG_TERMINATE) != 0) {
+ result |= (1 << VolumeShaperOperationFlag.TERMINATE);
+ }
+ if ((flags & FLAG_JOIN) != 0) {
+ result |= (1 << VolumeShaperOperationFlag.JOIN);
+ }
+ if ((flags & FLAG_DEFER) != 0) {
+ result |= (1 << VolumeShaperOperationFlag.DELAY);
+ }
+ if ((flags & FLAG_CREATE_IF_NEEDED) != 0) {
+ result |= (1 << VolumeShaperOperationFlag.CREATE_IF_NECESSARY);
+ }
+ return result;
+ }
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private Operation(@Flag int flags, int replaceId, float xOffset) {
mFlags = flags;
@@ -1393,17 +1537,27 @@ public final class VolumeShaper implements AutoCloseable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeFloat(mVolume);
- dest.writeFloat(mXOffset);
+ toParcelable().writeToParcel(dest, flags);
+ }
+
+ /** @hide */
+ public VolumeShaperState toParcelable() {
+ VolumeShaperState result = new VolumeShaperState();
+ result.volume = mVolume;
+ result.xOffset = mXOffset;
+ return result;
+ }
+
+ /** @hide */
+ public static State fromParcelable(VolumeShaperState p) {
+ return new VolumeShaper.State(p.volume, p.xOffset);
}
public static final @android.annotation.NonNull Parcelable.Creator<VolumeShaper.State> CREATOR
= new Parcelable.Creator<VolumeShaper.State>() {
@Override
public VolumeShaper.State createFromParcel(Parcel p) {
- return new VolumeShaper.State(
- p.readFloat() // volume
- , p.readFloat()); // xOffset
+ return fromParcelable(VolumeShaperState.CREATOR.createFromParcel(p));
}
@Override
diff --git a/media/java/android/media/permission/PermissionUtil.java b/media/java/android/media/permission/PermissionUtil.java
index 458f11243f68..315ee4f1e998 100644
--- a/media/java/android/media/permission/PermissionUtil.java
+++ b/media/java/android/media/permission/PermissionUtil.java
@@ -17,10 +17,8 @@
package android.media.permission;
import android.annotation.NonNull;
-import android.app.AppOpsManager;
import android.content.Context;
import android.content.PermissionChecker;
-import android.content.pm.PackageManager;
import android.os.Binder;
import java.util.Objects;
@@ -180,57 +178,6 @@ public class PermissionUtil {
}
/**
- * Checks whether the given identity has the given permission to receive data.
- *
- * This variant ignores the proc-state for the sake of the check, i.e. overrides any
- * restrictions that apply specifically to apps running in the background.
- *
- * TODO(ytai): This is a temporary hack until we have permissions that are specifically intended
- * for background microphone access.
- *
- * @param context A {@link Context}, used for permission checks.
- * @param identity The identity to check.
- * @param permission The identifier of the permission we want to check.
- * @param reason The reason why we're requesting the permission, for auditing purposes.
- * @return The permission check result which is either
- * {@link PermissionChecker#PERMISSION_GRANTED}
- * or {@link PermissionChecker#PERMISSION_SOFT_DENIED} or
- * {@link PermissionChecker#PERMISSION_HARD_DENIED}.
- */
- public static int checkPermissionForDataDeliveryIgnoreProcState(@NonNull Context context,
- @NonNull Identity identity,
- @NonNull String permission,
- @NonNull String reason) {
- if (context.checkPermission(permission, identity.pid, identity.uid)
- != PackageManager.PERMISSION_GRANTED) {
- return PermissionChecker.PERMISSION_HARD_DENIED;
- }
-
- String appOpOfPermission = AppOpsManager.permissionToOp(permission);
- if (appOpOfPermission == null) {
- // not platform defined
- return PermissionChecker.PERMISSION_GRANTED;
- }
-
- String packageName = identity.packageName;
- if (packageName == null) {
- String[] packageNames = context.getPackageManager().getPackagesForUid(identity.uid);
- if (packageNames != null && packageNames.length > 0) {
- packageName = packageNames[0];
- }
- }
-
- final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
-
- int appOpMode = appOpsManager.unsafeCheckOpRawNoThrow(appOpOfPermission, identity.uid,
- packageName);
- if (appOpMode == AppOpsManager.MODE_ALLOWED) {
- return PermissionChecker.PERMISSION_GRANTED;
- }
- return PermissionChecker.PERMISSION_SOFT_DENIED;
- }
-
- /**
* Checks whether the given identity has the given permission.
*
* @param context A {@link Context}, used for permission checks.
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 1557ea632b66..f157d7f4845d 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -17,7 +17,7 @@ package android.media.session;
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
-import android.media.IRemoteVolumeController;
+import android.media.IRemoteVolumeControllerCallback;
import android.media.Session2Token;
import android.media.session.IActiveSessionsListener;
import android.media.session.IOnMediaKeyEventDispatchedListener;
@@ -57,8 +57,8 @@ interface ISessionManager {
void addSession2TokensListener(in ISession2TokensListener listener, int userId);
void removeSession2TokensListener(in ISession2TokensListener listener);
- void registerRemoteVolumeController(in IRemoteVolumeController rvc);
- void unregisterRemoteVolumeController(in IRemoteVolumeController rvc);
+ void registerRemoteVolumeControllerCallback(in IRemoteVolumeControllerCallback rvc);
+ void unregisterRemoteVolumeControllerCallback(in IRemoteVolumeControllerCallback rvc);
// For PhoneWindowManager to precheck media keys
boolean isGlobalPriorityActive();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 38e2bdfc308d..e9bb7f8d6cb8 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.PendingIntent;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.media.AudioAttributes;
@@ -32,6 +33,7 @@ import android.media.VolumeProvider;
import android.media.VolumeProvider.ControlType;
import android.media.session.MediaSession.QueueItem;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -462,10 +464,11 @@ public final class MediaController {
}
/**
+ * @hide
* Returns whether this and {@code other} media controller controls the same session.
- * @deprecated Check equality of {@link #getSessionToken() tokens} instead.
*/
- @Deprecated
+ @UnsupportedAppUsage(publicAlternatives = "Check equality of {@link #getSessionToken() tokens} "
+ + "instead.", maxTargetSdk = Build.VERSION_CODES.R)
public boolean controlsSameSession(@Nullable MediaController other) {
if (other == null) return false;
return mToken.equals(other.mToken);
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index b7b9e4ba6f40..36158b70005b 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -28,10 +28,11 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.media.AudioManager;
-import android.media.IRemoteVolumeController;
+import android.media.IRemoteVolumeControllerCallback;
import android.media.MediaFrameworkInitializer;
import android.media.MediaSession2;
import android.media.Session2Token;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
@@ -88,6 +89,8 @@ public final class MediaSessionManager {
private final OnMediaKeyEventSessionChangedListenerStub
mOnMediaKeyEventSessionChangedListenerStub =
new OnMediaKeyEventSessionChangedListenerStub();
+ private final RemoteVolumeControllerCallbackStub mRemoteVolumeControllerCallbackStub =
+ new RemoteVolumeControllerCallbackStub();
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -106,6 +109,9 @@ public final class MediaSessionManager {
private String mCurMediaKeyEventSessionPackage;
@GuardedBy("mLock")
private MediaSession.Token mCurMediaKeyEventSession;
+ @GuardedBy("mLock")
+ private final Map<RemoteVolumeControllerCallback, Executor>
+ mRemoteVolumeControllerCallbacks = new ArrayMap<>();
private Context mContext;
private OnVolumeKeyLongPressListenerImpl mOnVolumeKeyLongPressListener;
@@ -204,7 +210,10 @@ public final class MediaSessionManager {
* @return A list of controllers for ongoing sessions.
* @hide
*/
- @UnsupportedAppUsage
+ // TODO: Remove @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Should only be"
+ + " used by system apps, since non-system apps cannot get other users' sessions."
+ + " Use {@link #getActiveSessions} instead.")
public @NonNull List<MediaController> getActiveSessionsForUser(
@Nullable ComponentName notificationListener, int userId) {
ArrayList<MediaController> controllers = new ArrayList<MediaController>();
@@ -462,33 +471,62 @@ public final class MediaSessionManager {
}
/**
- * Set the remote volume controller to receive volume updates on.
+ * Set the remote volume controller callback to receive volume updates on.
* Only for use by System UI and Settings application.
*
- * @param rvc The volume controller to receive updates on.
+ * @param callback The volume controller callback to receive updates on.
* @hide
*/
- public void registerRemoteVolumeController(IRemoteVolumeController rvc) {
- try {
- mService.registerRemoteVolumeController(rvc);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in registerRemoteVolumeController.", e);
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void registerRemoteVolumeControllerCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull RemoteVolumeControllerCallback callback) {
+ Objects.requireNonNull(executor, "executor shouldn't be null");
+ Objects.requireNonNull(callback, "callback shouldn't be null");
+ boolean shouldRegisterCallback = false;
+ synchronized (mLock) {
+ int prevCallbackCount = mRemoteVolumeControllerCallbacks.size();
+ mRemoteVolumeControllerCallbacks.put(callback, executor);
+ if (prevCallbackCount == 0 && mRemoteVolumeControllerCallbacks.size() == 1) {
+ shouldRegisterCallback = true;
+ }
+ }
+ if (shouldRegisterCallback) {
+ try {
+ mService.registerRemoteVolumeControllerCallback(
+ mRemoteVolumeControllerCallbackStub);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to register remote volume controller callback", e);
+ }
}
}
/**
- * Unregisters the remote volume controller which was previously registered with
- * {@link #registerRemoteVolumeController(IRemoteVolumeController)}.
+ * Unregisters the remote volume controller callback which was previously registered with
+ * {@link #registerRemoteVolumeControllerCallback(Executor, RemoteVolumeControllerCallback)}.
* Only for use by System UI and Settings application.
*
- * @param rvc The volume controller which was registered.
+ * @param callback The volume controller callback to receive updates on.
* @hide
*/
- public void unregisterRemoteVolumeController(IRemoteVolumeController rvc) {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void unregisterRemoteVolumeControllerCallback(
+ @NonNull RemoteVolumeControllerCallback callback) {
+ Objects.requireNonNull(callback, "callback shouldn't be null");
+ boolean shouldUnregisterCallback = false;
+ synchronized (mLock) {
+ if (mRemoteVolumeControllerCallbacks.remove(callback) != null
+ && mRemoteVolumeControllerCallbacks.size() == 0) {
+ shouldUnregisterCallback = true;
+ }
+ }
try {
- mService.unregisterRemoteVolumeController(rvc);
+ if (shouldUnregisterCallback) {
+ mService.unregisterRemoteVolumeControllerCallback(
+ mRemoteVolumeControllerCallbackStub);
+ }
} catch (RemoteException e) {
- Log.e(TAG, "Error in unregisterRemoteVolumeController.", e);
+ Log.e(TAG, "Failed to unregister remote volume controller callback", e);
}
}
@@ -1048,10 +1086,11 @@ public final class MediaSessionManager {
* has specified the target.
* <p>
* The session token can be {@link null} if the media button session is unset. In that case,
- * framework would dispatch to the last sessions's media button receiver. If the media
- * button receive isn't set as well, then it
+ * packageName will return the package name of the last session's media button receiver, or
+ * an empty string if the last session didn't set a media button receiver.
*
- * @param packageName The package name who would receive the media key event. Can be empty.
+ * @param packageName The package name of the component that will receive the media key
+ * event. Can be empty.
* @param sessionToken The media session's token. Can be {@code null}.
*/
void onMediaKeyEventSessionChanged(@NonNull String packageName,
@@ -1059,6 +1098,29 @@ public final class MediaSessionManager {
}
/**
+ * Callback to receive changes in the remote volume controller.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public interface RemoteVolumeControllerCallback {
+ /**
+ * Called when the volume is changed.
+ *
+ * @param sessionToken the remote media session token
+ * @param flags any of the flags from {@link AudioManager}
+ */
+ void onVolumeChanged(@NonNull MediaSession.Token sessionToken, int flags);
+
+ /**
+ * Called when the session for the default remote controller is changed.
+ *
+ * @param sessionToken the remote media session token
+ */
+ void onSessionChanged(@Nullable MediaSession.Token sessionToken);
+ }
+
+ /**
* Information of a remote user of {@link MediaSession} or {@link MediaBrowserService}.
* This can be used to decide whether the remote user is trusted app, and also differentiate
* caller of {@link MediaSession} and {@link MediaBrowserService} callbacks.
@@ -1290,4 +1352,29 @@ public final class MediaSessionManager {
}
}
}
+
+ private final class RemoteVolumeControllerCallbackStub
+ extends IRemoteVolumeControllerCallback.Stub {
+ @Override
+ public void onVolumeChanged(MediaSession.Token sessionToken, int flags) {
+ Map<RemoteVolumeControllerCallback, Executor> callbacks = new ArrayMap<>();
+ synchronized (mLock) {
+ callbacks.putAll(mRemoteVolumeControllerCallbacks);
+ }
+ for (Map.Entry<RemoteVolumeControllerCallback, Executor> e : callbacks.entrySet()) {
+ e.getValue().execute(() -> e.getKey().onVolumeChanged(sessionToken, flags));
+ }
+ }
+
+ @Override
+ public void onSessionChanged(MediaSession.Token sessionToken) {
+ Map<RemoteVolumeControllerCallback, Executor> callbacks = new ArrayMap<>();
+ synchronized (mLock) {
+ callbacks.putAll(mRemoteVolumeControllerCallbacks);
+ }
+ for (Map.Entry<RemoteVolumeControllerCallback, Executor> e : callbacks.entrySet()) {
+ e.getValue().execute(() -> e.getKey().onSessionChanged(sessionToken));
+ }
+ }
+ }
}
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index 00e3bcebd0f3..f60c7089c4a9 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -41,6 +41,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.provider.Settings;
@@ -69,6 +70,7 @@ public final class SoundTriggerManager {
private final Context mContext;
private final ISoundTriggerSession mSoundTriggerSession;
+ private final IBinder mBinderToken = new Binder();
// Stores a mapping from the sound model UUID to the SoundTriggerInstance created by
// the createSoundTriggerDetector() call.
@@ -90,7 +92,8 @@ public final class SoundTriggerManager {
originatorIdentity.packageName = ActivityThread.currentOpPackageName();
try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
- mSoundTriggerSession = soundTriggerService.attachAsOriginator(originatorIdentity);
+ mSoundTriggerSession = soundTriggerService.attachAsOriginator(originatorIdentity,
+ mBinderToken);
}
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
diff --git a/media/java/android/media/tv/tuner/Descrambler.java b/media/java/android/media/tv/tuner/Descrambler.java
index 7b58bfc30b24..5f79dc52a2f1 100644
--- a/media/java/android/media/tv/tuner/Descrambler.java
+++ b/media/java/android/media/tv/tuner/Descrambler.java
@@ -111,10 +111,13 @@ public class Descrambler implements AutoCloseable {
/**
* Set a key token to link descrambler to a key slot
*
- * A descrambler instance can have only one key slot to link, but a key slot can hold a few
+ * <p>A descrambler instance can have only one key slot to link, but a key slot can hold a few
* keys for different purposes.
*
- * @param keyToken the token to be used to link the key slot.
+ * @param keyToken the token to be used to link the key slot. Use {@link Tuner.INVALID_KEYTOKEN}
+ * to remove the to remove the current key from descrambler. If the current keyToken
+ * comes from MediaCas session, use {@link Tuner.INVALID_KEYTOKEN} to remove current key
+ * before close MediaCas session.
* @return result status of the operation.
*/
@Result
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 1881e38a5010..27b33ace532a 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -61,6 +61,7 @@ import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -122,6 +123,17 @@ public class Tuner implements AutoCloseable {
android.hardware.tv.tuner.V1_1.Constants.Constant
.INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM;
/**
+ * Invalid first macroblock address in MmtpRecordEvent and TsRecordEvent.
+ *
+ * <p>Returned by {@link MmtpRecordEvent#getMbInSlice()} and
+ * {@link TsRecordEvent#getMbInSlice()} when the requested sequence number is not available.
+ *
+ * @see android.media.tv.tuner.filter.MmtpRecordEvent#getMbInSlice()
+ * @see android.media.tv.tuner.filter.TsRecordEvent#getMbInSlice()
+ */
+ public static final int INVALID_FIRST_MACROBLOCK_IN_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_FIRST_MACROBLOCK_IN_SLICE;
+ /**
* Invalid local transport stream id.
*
* <p>Returned by {@link #linkFrontendToCiCam(int)} when the requested failed
@@ -141,6 +153,27 @@ public class Tuner implements AutoCloseable {
*/
public static final int INVALID_FRONTEND_SETTING_FREQUENCY =
android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_FRONTEND_SETTING_FREQUENCY;
+ /**
+ * Invalid frontend id.
+ */
+ public static final int INVALID_FRONTEND_ID =
+ android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_FRONTEND_ID;
+ /**
+ * Invalid LNB id.
+ *
+ * @hide
+ */
+ public static final int INVALID_LNB_ID =
+ android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_LNB_ID;
+ /**
+ * Invalid key token. It is used to remove the current key from descrambler.
+ *
+ * <p>If the current keyToken comes from a MediaCas session, App is recommended to
+ * to use this constant to remove current key before closing MediaCas session.
+ */
+ @NonNull
+ public static final byte[] INVALID_KEYTOKEN =
+ {android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_KEYTOKEN};
/** @hide */
@IntDef(prefix = "SCAN_TYPE_", value = {SCAN_TYPE_UNDEFINED, SCAN_TYPE_AUTO, SCAN_TYPE_BLIND})
@@ -337,6 +370,28 @@ public class Tuner implements AutoCloseable {
mTunerResourceManager.setFrontendInfoList(infos);
}
+ /**
+ * Get frontend info list from native and build them into a {@link FrontendInfo} list. Any
+ * {@code null} FrontendInfo element would be removed.
+ */
+ private FrontendInfo[] getFrontendInfoListInternal() {
+ List<Integer> ids = getFrontendIds();
+ if (ids == null) {
+ return null;
+ }
+ FrontendInfo[] infos = new FrontendInfo[ids.size()];
+ for (int i = 0; i < ids.size(); i++) {
+ int id = ids.get(i);
+ FrontendInfo frontendInfo = getFrontendInfoById(id);
+ if (frontendInfo == null) {
+ Log.e(TAG, "Failed to get a FrontendInfo on frontend id:" + id + "!");
+ continue;
+ }
+ infos[i] = frontendInfo;
+ }
+ return Arrays.stream(infos).filter(Objects::nonNull).toArray(FrontendInfo[]::new);
+ }
+
/** @hide */
public static int getTunerVersion() {
return sTunerVersion;
@@ -685,10 +740,14 @@ public class Tuner implements AutoCloseable {
@Result
public int scan(@NonNull FrontendSettings settings, @ScanType int scanType,
@NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) {
- if (mScanCallback != null || mScanCallbackExecutor != null) {
+ /**
+ * Scan can be called again for blink scan if scanCallback and executor are same as before.
+ */
+ if (((mScanCallback != null) && (mScanCallback != scanCallback))
+ || ((mScanCallbackExecutor != null) && (mScanCallbackExecutor != executor))) {
throw new IllegalStateException(
- "Scan already in progress. stopScan must be called before a new scan can be "
- + "started.");
+ "Different Scan session already in progress. stopScan must be called "
+ + "before a new scan session can be " + "started.");
}
mFrontendType = settings.getType();
if (mFrontendType == FrontendSettings.TYPE_DTMB) {
@@ -900,7 +959,7 @@ public class Tuner implements AutoCloseable {
}
/**
- * Gets the frontend information.
+ * Gets the initialized frontend information.
*
* @return The frontend information. {@code null} if the operation failed.
*/
@@ -918,6 +977,16 @@ public class Tuner implements AutoCloseable {
return mFrontendInfo;
}
+ /**
+ * Get a list all the existed frontend information.
+ *
+ * @return The list of all the frontend information. {@code null} if the operation failed.
+ */
+ @Nullable
+ public List<FrontendInfo> getFrontendInfoList() {
+ return Arrays.asList(getFrontendInfoListInternal());
+ }
+
/** @hide */
public FrontendInfo getFrontendInfoById(int id) {
return nativeGetFrontendInfo(id);
@@ -1062,6 +1131,13 @@ public class Tuner implements AutoCloseable {
}
}
+ private void onDvbcAnnexReported(int dvbcAnnex) {
+ if (mScanCallbackExecutor != null && mScanCallback != null) {
+ mScanCallbackExecutor.execute(
+ () -> mScanCallback.onDvbcAnnexReported(dvbcAnnex));
+ }
+ }
+
/**
* Opens a filter object based on the given types and buffer size.
*
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 2f2d8f74c908..82cc78d7e47d 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -25,6 +25,7 @@ import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.Tuner;
import android.media.tv.tuner.Tuner.Result;
import android.media.tv.tuner.TunerUtils;
+import android.media.tv.tuner.TunerVersionChecker;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -148,7 +149,6 @@ public class Filter implements AutoCloseable {
public static final int SUBTYPE_PTP = 16;
-
/** @hide */
@IntDef(flag = true, prefix = "STATUS_", value = {STATUS_DATA_READY, STATUS_LOW_WATER,
STATUS_HIGH_WATER, STATUS_OVERFLOW})
@@ -180,6 +180,31 @@ public class Filter implements AutoCloseable {
*/
public static final int STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW;
+ /** @hide */
+ @IntDef(flag = true,
+ prefix = "SCRAMBLING_STATUS_",
+ value = {SCRAMBLING_STATUS_UNKNOWN, SCRAMBLING_STATUS_NOT_SCRAMBLED,
+ SCRAMBLING_STATUS_SCRAMBLED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ScramblingStatusMask {}
+
+ /**
+ * Content’s scrambling status is unknown
+ */
+ public static final int SCRAMBLING_STATUS_UNKNOWN =
+ android.hardware.tv.tuner.V1_1.Constants.ScramblingStatus.UNKNOWN;
+ /**
+ * Content is not scrambled.
+ */
+ public static final int SCRAMBLING_STATUS_NOT_SCRAMBLED =
+ android.hardware.tv.tuner.V1_1.Constants.ScramblingStatus.NOT_SCRAMBLED;
+ /**
+ * Content is scrambled.
+ */
+ public static final int SCRAMBLING_STATUS_SCRAMBLED =
+ android.hardware.tv.tuner.V1_1.Constants.ScramblingStatus.SCRAMBLED;
+
+
private static final String TAG = "Filter";
private long mNativeContext;
@@ -197,6 +222,7 @@ public class Filter implements AutoCloseable {
int type, int subType, FilterConfiguration settings);
private native int nativeGetId();
private native long nativeGetId64Bit();
+ private native int nativeconfigureScramblingEvent(int scramblingStatusMask);
private native int nativeSetDataSource(Filter source);
private native int nativeStartFilter();
private native int nativeStopFilter();
@@ -280,6 +306,38 @@ public class Filter implements AutoCloseable {
}
/**
+ * Configure the Filter to monitor specific Scrambling Status through
+ * {@link ScramblingStatusEvent}.
+ *
+ * <p>{@link ScramblingStatusEvent} should be sent at the following two scenarios:
+ *
+ * <ul>
+ * <li>When this method is called, the first detected scrambling status should be sent.
+ * <li>When the filter transits into the monitored statuses configured in
+ * {@code scramblingStatusMask}, event should be sent.
+ * <ul/>
+ *
+ * <p>This configuration is only supported in Tuner 1.1 or higher version. Unsupported version
+ * will cause no-op. Use {@link TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
+ *
+ * @param scramblingStatusMask Scrambling Statuses to be monitored. Set corresponding bit to
+ * monitor it. Reset to stop monitoring.
+ * @return result status of the operation.
+ */
+ @Result
+ public int configureScramblingStatusEvent(@ScramblingStatusMask int scramblingStatusMask) {
+ synchronized (mLock) {
+ TunerUtils.checkResourceState(TAG, mIsClosed);
+ if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "configureScramblingStatusEvent")) {
+ return Tuner.RESULT_UNAVAILABLE;
+ }
+ return nativeconfigureScramblingEvent(scramblingStatusMask);
+ }
+ }
+
+ /**
* Sets the filter's data source.
*
* A filter uses demux as data source by default. If the data was packetized
diff --git a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
index 7060bd722d57..1bbd6e36c104 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpRecordEvent.java
@@ -21,7 +21,7 @@ import android.annotation.SystemApi;
import android.media.tv.tuner.filter.RecordSettings.ScHevcIndex;
/**
- * Filter event sent from {@link Filter} objects with MMTP type.
+ * Filter event sent from {@link Filter} objects with MPEG media Transport Protocol(MMTP) type.
*
* @hide
*/
@@ -31,13 +31,18 @@ public class MmtpRecordEvent extends FilterEvent {
private final long mDataLength;
private final int mMpuSequenceNumber;
private final long mPts;
+ private final int mFirstMbInSlice;
+ private final int mTsIndexMask;
// This constructor is used by JNI code only
- private MmtpRecordEvent(int scHevcIndexMask, long dataLength, int mpuSequenceNumber, long pts) {
+ private MmtpRecordEvent(int scHevcIndexMask, long dataLength, int mpuSequenceNumber, long pts,
+ int firstMbInSlice, int tsIndexMask) {
mScHevcIndexMask = scHevcIndexMask;
mDataLength = dataLength;
mMpuSequenceNumber = mpuSequenceNumber;
mPts = pts;
+ mFirstMbInSlice = firstMbInSlice;
+ mTsIndexMask = tsIndexMask;
}
/**
@@ -58,6 +63,11 @@ public class MmtpRecordEvent extends FilterEvent {
/**
* Get the MPU sequence number of the filtered data.
+ *
+ * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+ * return {@link android.media.tv.tuner.Tuner.INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM}. Use
+ * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
*/
public int getMpuSequenceNumber() {
return mMpuSequenceNumber;
@@ -65,10 +75,39 @@ public class MmtpRecordEvent extends FilterEvent {
/**
* Get the Presentation Time Stamp(PTS) for the audio or video frame. It is based on 90KHz
- * and has the same format as the PTS in ISO/IEC 13818-1. It is used only for the SC and
- * the SC_HEVC.
+ * and has the same format as the PTS in ISO/IEC 13818-1.
+ *
+ * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+ * return {@link android.media.tv.tuner.Tuner.INVALID_TIMESTAMP}. Use
+ * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
*/
public long getPts() {
return mPts;
}
+
+ /**
+ * Get the address of the first macroblock in the slice defined in ITU-T Rec. H.264.
+ *
+ * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+ * return {@link android.media.tv.tuner.Tuner.INVALID_FIRST_MACROBLOCK_IN_SLICE}. Use
+ * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
+ */
+ public int getFirstMacroblockInSlice() {
+ return mFirstMbInSlice;
+ }
+
+ /**
+ * Get the offset of the recorded keyframe from MMT Packet Table.
+ *
+ * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+ * return {@link RecordSettings.TS_INDEX_INVALID}. Use
+ * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the
+ * version information.
+ */
+ @RecordSettings.TsIndexMask
+ public int getTsIndexMask() {
+ return mTsIndexMask;
+ }
}
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
index ec01e44b975c..52ce208f251e 100644
--- a/media/java/android/media/tv/tuner/filter/RecordSettings.java
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -38,17 +38,23 @@ public class RecordSettings extends Settings {
* @hide
*/
@IntDef(flag = true,
- prefix = "TS_INDEX_",
- value = {TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
+ value = {TS_INDEX_INVALID, TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
TS_INDEX_CHANGE_TO_NOT_SCRAMBLED, TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED,
TS_INDEX_CHANGE_TO_ODD_SCRAMBLED, TS_INDEX_DISCONTINUITY_INDICATOR,
TS_INDEX_RANDOM_ACCESS_INDICATOR, TS_INDEX_PRIORITY_INDICATOR,
TS_INDEX_PCR_FLAG, TS_INDEX_OPCR_FLAG, TS_INDEX_SPLICING_POINT_FLAG,
- TS_INDEX_PRIVATE_DATA, TS_INDEX_ADAPTATION_EXTENSION_FLAG})
+ TS_INDEX_PRIVATE_DATA, TS_INDEX_ADAPTATION_EXTENSION_FLAG,
+ MPT_INDEX_MPT, MPT_INDEX_VIDEO, MPT_INDEX_AUDIO,
+ MPT_INDEX_TIMESTAMP_TARGET_VIDEO,
+ MPT_INDEX_TIMESTAMP_TARGET_AUDIO})
@Retention(RetentionPolicy.SOURCE)
public @interface TsIndexMask {}
/**
+ * Invalid TS index.
+ */
+ public static final int TS_INDEX_INVALID = 0;
+ /**
* TS index FIRST_PACKET.
*/
public static final int TS_INDEX_FIRST_PACKET = Constants.DemuxTsIndex.FIRST_PACKET;
@@ -108,6 +114,32 @@ public class RecordSettings extends Settings {
*/
public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG =
Constants.DemuxTsIndex.ADAPTATION_EXTENSION_FLAG;
+ /**
+ * Index the address of MPEG Media Transport Packet Table(MPT).
+ */
+ public static final int MPT_INDEX_MPT =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_MPT;
+ /**
+ * Index the address of Video.
+ */
+ public static final int MPT_INDEX_VIDEO =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_VIDEO;
+ /**
+ * Index the address of Audio.
+ */
+ public static final int MPT_INDEX_AUDIO =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_AUDIO;
+ /**
+ * Index to indicate this is a target of timestamp extraction for video.
+ */
+ public static final int MPT_INDEX_TIMESTAMP_TARGET_VIDEO =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_TIMESTAMP_TARGET_VIDEO;
+ /**
+ * Index to indicate this is a target of timestamp extraction for audio.
+ */
+ public static final int MPT_INDEX_TIMESTAMP_TARGET_AUDIO =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxTsIndex.MPT_INDEX_TIMESTAMP_TARGET_AUDIO;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -133,8 +165,11 @@ public class RecordSettings extends Settings {
* according to ISO/IEC 13818-1.
* @hide
*/
- @IntDef(flag = true, value = {SC_INDEX_I_FRAME, SC_INDEX_P_FRAME, SC_INDEX_B_FRAME,
- SC_INDEX_SEQUENCE})
+ @IntDef(prefix = "SC_INDEX_",
+ flag = true,
+ value = {SC_INDEX_I_FRAME, SC_INDEX_P_FRAME, SC_INDEX_B_FRAME,
+ SC_INDEX_SEQUENCE, SC_INDEX_I_SLICE, SC_INDEX_P_SLICE,
+ SC_INDEX_B_SLICE, SC_INDEX_SI_SLICE, SC_INDEX_SP_SLICE})
@Retention(RetentionPolicy.SOURCE)
public @interface ScIndex {}
@@ -154,7 +189,31 @@ public class RecordSettings extends Settings {
* SC index for a new sequence.
*/
public static final int SC_INDEX_SEQUENCE = Constants.DemuxScIndex.SEQUENCE;
-
+ /**
+ * All blocks are coded as I blocks.
+ */
+ public static final int SC_INDEX_I_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.I_SLICE;
+ /**
+ * Blocks are coded as I or P blocks.
+ */
+ public static final int SC_INDEX_P_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.P_SLICE;
+ /**
+ * Blocks are coded as I, P or B blocks.
+ */
+ public static final int SC_INDEX_B_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.B_SLICE;
+ /**
+ * A so-called switching I slice that is coded.
+ */
+ public static final int SC_INDEX_SI_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.SI_SLICE;
+ /**
+ * A so-called switching P slice that is coded.
+ */
+ public static final int SC_INDEX_SP_SLICE =
+ android.hardware.tv.tuner.V1_1.Constants.DemuxScIndex.SP_SLICE;
/**
* Indexes can be tagged by NAL unit group in HEVC according to ISO/IEC 23008-2.
diff --git a/media/java/android/media/tv/tuner/filter/ScramblingStatusEvent.java b/media/java/android/media/tv/tuner/filter/ScramblingStatusEvent.java
new file mode 100644
index 000000000000..a78b96e9cf51
--- /dev/null
+++ b/media/java/android/media/tv/tuner/filter/ScramblingStatusEvent.java
@@ -0,0 +1,48 @@
+/*
+ * 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.media.tv.tuner.filter;
+
+import android.annotation.SystemApi;
+
+/**
+ * Scrambling Status event sent from {@link Filter} objects with Scrambling Status type.
+ *
+ * <p>This event is only sent in Tuner 1.1 or higher version. Use
+ * {@link TunerVersionChecker.getTunerVersion()} to get the version information.
+ *
+ * @hide
+ */
+@SystemApi
+public final class ScramblingStatusEvent extends FilterEvent {
+ private final int mScramblingStatus;
+
+ private ScramblingStatusEvent(@Filter.ScramblingStatusMask int scramblingStatus) {
+ mScramblingStatus = scramblingStatus;
+ }
+
+ /**
+ * Gets Scrambling Status Type.
+ *
+ * <p>This event field is only sent in Tuner 1.1 or higher version. Unsupported version returns
+ * default value 0. Use {@link TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
+ */
+ @Filter.ScramblingStatusMask
+ public int getScramblingStatus() {
+ return mScramblingStatus;
+ }
+}
diff --git a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
index 258e2f22427c..28161993e5c8 100644
--- a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
+++ b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java
@@ -33,14 +33,17 @@ public class TsRecordEvent extends FilterEvent {
private final int mScIndexMask;
private final long mDataLength;
private final long mPts;
+ private final int mFirstMbInSlice;
// This constructor is used by JNI code only
- private TsRecordEvent(int pid, int tsIndexMask, int scIndexMask, long dataLength, long pts) {
+ private TsRecordEvent(int pid, int tsIndexMask, int scIndexMask, long dataLength, long pts,
+ int firstMbInSlice) {
mPid = pid;
mTsIndexMask = tsIndexMask;
mScIndexMask = scIndexMask;
mDataLength = dataLength;
mPts = pts;
+ mFirstMbInSlice = firstMbInSlice;
}
/**
@@ -77,10 +80,26 @@ public class TsRecordEvent extends FilterEvent {
/**
* Gets the Presentation Time Stamp(PTS) for the audio or video frame. It is based on 90KHz
- * and has the same format as the PTS in ISO/IEC 13818-1. It is used only for the SC and
- * the SC_HEVC.
+ * and has the same format as the PTS in ISO/IEC 13818-1.
+ *
+ * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+ * return {@link android.media.tv.tuner.Tuner.INVALID_TIMESTAMP}. Use
+ * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
*/
public long getPts() {
return mPts;
}
+
+ /**
+ * Get the address of the first macroblock in the slice defined in ITU-T Rec. H.264.
+ *
+ * <p>This field is only supported in Tuner 1.1 or higher version. Unsupported version will
+ * return {@link android.media.tv.tuner.Tuner.INVALID_FIRST_MACROBLOCK_IN_SLICE}. Use
+ * {@link android.media.tv.tuner.TunerVersionChecker.getTunerVersion()} to get the version
+ * information.
+ */
+ public int getFirstMacroblockInSlice() {
+ return mFirstMbInSlice;
+ }
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java
index faa54344573a..948f4a77e361 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendCapabilities.java
@@ -26,10 +26,10 @@ import android.annotation.SystemApi;
@SystemApi
public class DvbcFrontendCapabilities extends FrontendCapabilities {
private final int mModulationCap;
- private final int mFecCap;
+ private final long mFecCap;
private final int mAnnexCap;
- private DvbcFrontendCapabilities(int modulationCap, int fecCap, int annexCap) {
+ private DvbcFrontendCapabilities(int modulationCap, long fecCap, int annexCap) {
mModulationCap = modulationCap;
mFecCap = fecCap;
mAnnexCap = annexCap;
@@ -44,9 +44,24 @@ public class DvbcFrontendCapabilities extends FrontendCapabilities {
}
/**
* Gets inner FEC capability.
+ *
+ * @deprecated Use {@link getInnerFecCapability()} with long return value instead. This function
+ * returns the correct cap value when the value is not bigger than the max integer
+ * value. Otherwise it returns {@link FrontendSettings#FEC_UNDEFINED}.
*/
+ @Deprecated
@FrontendSettings.InnerFec
public int getFecCapability() {
+ if (mFecCap > Integer.MAX_VALUE) {
+ return (int) FrontendSettings.FEC_UNDEFINED;
+ }
+ return (int) mFecCap;
+ }
+ /**
+ * Gets code rate capability.
+ */
+ @FrontendSettings.InnerFec
+ public long getCodeRateCapability() {
return mFecCap;
}
/**
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index fadc00475930..98f80965523f 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
@@ -341,12 +341,13 @@ public class DvbsFrontendSettings extends FrontendSettings {
return mScanType;
}
/**
- * To receive Diseqc Message or not. Default value is false.
+ * Get if the client could handle the Diseqc Rx Message or not. Default value is false.
*
- * The setter {@link Builder#setDiseqcRxMessage(boolean)} is only supported with Tuner HAL 1.1
- * or higher.
+ * The setter {@link Builder#setCouldHandleDiseqcRxMessage(boolean)} is only supported with
+ * Tuner HAL 1.1 or higher. Use {@link TunerVersionChecker.getTunerVersion()} to check the
+ * version.
*/
- public boolean isDiseqcRxMessage() {
+ public boolean getCouldHandleDiseqcRxMessage() {
return mIsDiseqcRxMessage;
}
@@ -408,16 +409,18 @@ public class DvbsFrontendSettings extends FrontendSettings {
}
/**
- * Set true to receive Diseqc Message.
+ * Set true to indicate the client could handle the Diseqc Messages. Note that it's still
+ * possible that the client won't receive the messages when HAL is not able to setup Rx
+ * channel in the hardware layer.
*
* <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
* no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
*/
@NonNull
- public Builder setDiseqcRxMessage(boolean isDiseqcRxMessage) {
+ public Builder setCouldHandleDiseqcRxMessage(boolean couldReceiveDiseqcMessage) {
if (TunerVersionChecker.checkHigherOrEqualVersionTo(
- TunerVersionChecker.TUNER_VERSION_1_1, "setDiseqcRxMessage")) {
- mIsDiseqcRxMessage = isDiseqcRxMessage;
+ TunerVersionChecker.TUNER_VERSION_1_1, "setCouldHandleDiseqcRxMessage")) {
+ mIsDiseqcRxMessage = couldReceiveDiseqcMessage;
}
return this;
}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
index 334900ba705a..f3e94760c847 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
@@ -22,6 +22,9 @@ import android.media.tv.tuner.frontend.FrontendSettings.Type;
import android.media.tv.tuner.frontend.FrontendStatus.FrontendStatusType;
import android.util.Range;
+import java.util.Arrays;
+import java.util.Objects;
+
/**
* This class is used to specify meta information of a frontend.
*
@@ -53,6 +56,9 @@ public class FrontendInfo {
/**
* Gets frontend ID.
+ *
+ * @return the frontend ID or {@link android.media.tv.tuner.Tuner.INVALID_FRONTEND_ID}
+ * if invalid
*/
public int getId() {
return mId;
@@ -115,4 +121,30 @@ public class FrontendInfo {
public FrontendCapabilities getFrontendCapabilities() {
return mFrontendCap;
}
+
+
+ /** @hide */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || !(o instanceof FrontendInfo)) {
+ return false;
+ }
+ // TODO: compare FrontendCapabilities
+ FrontendInfo info = (FrontendInfo) o;
+ return mId == info.getId() && mType == info.getType()
+ && Objects.equals(mFrequencyRange, info.getFrequencyRange())
+ && Objects.equals(mSymbolRateRange, info.getSymbolRateRange())
+ && mAcquireRange == info.getAcquireRange()
+ && mExclusiveGroupId == info.getExclusiveGroupId()
+ && Arrays.equals(mStatusCaps, info.getStatusCapabilities());
+ }
+
+ /** @hide */
+ @Override
+ public int hashCode() {
+ return mId;
+ }
}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
index 2147622d349d..f8470b11fdbd 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
@@ -302,6 +302,7 @@ public abstract class FrontendSettings {
*
* @return the end frequency in Hz.
*/
+ @IntRange(from = 1)
public int getEndFrequency() {
return mEndFrequency;
}
@@ -341,11 +342,15 @@ public abstract class FrontendSettings {
*
* @param endFrequency the end frequency used during blind scan. The default value is
* {@link android.media.tv.tuner.Tuner#INVALID_FRONTEND_SETTING_FREQUENCY}.
+ * @throws IllegalArgumentException if the {@code endFrequency} is not greater than 0.
*/
@IntRange(from = 1)
public void setEndFrequency(int endFrequency) {
if (TunerVersionChecker.checkHigherOrEqualVersionTo(
TunerVersionChecker.TUNER_VERSION_1_1, "setEndFrequency")) {
+ if (endFrequency < 1) {
+ throw new IllegalArgumentException("endFrequency must be greater than 0");
+ }
mEndFrequency = endFrequency;
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index c93e07915441..af1ff01a3ebe 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -51,7 +51,9 @@ public class FrontendStatus {
FRONTEND_STATUS_TYPE_TRANSMISSION_MODE, FRONTEND_STATUS_TYPE_UEC,
FRONTEND_STATUS_TYPE_T2_SYSTEM_ID, FRONTEND_STATUS_TYPE_INTERLEAVINGS,
FRONTEND_STATUS_TYPE_ISDBT_SEGMENTS, FRONTEND_STATUS_TYPE_TS_DATA_RATES,
- FRONTEND_STATUS_TYPE_MODULATIONS_EXT})
+ FRONTEND_STATUS_TYPE_MODULATIONS_EXT, FRONTEND_STATUS_TYPE_ROLL_OFF,
+ FRONTEND_STATUS_TYPE_IS_MISO, FRONTEND_STATUS_TYPE_IS_LINEAR,
+ FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES})
@Retention(RetentionPolicy.SOURCE)
public @interface FrontendStatusType {}
@@ -208,6 +210,26 @@ public class FrontendStatus {
*/
public static final int FRONTEND_STATUS_TYPE_MODULATIONS_EXT =
android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.MODULATIONS;
+ /**
+ * Roll Off Type status of the frontend. Only supported in Tuner HAL 1.1 or higher.
+ */
+ public static final int FRONTEND_STATUS_TYPE_ROLL_OFF =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.ROLL_OFF;
+ /**
+ * If the frontend currently supports MISO or not. Only supported in Tuner HAL 1.1 or higher.
+ */
+ public static final int FRONTEND_STATUS_TYPE_IS_MISO =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.IS_MISO;
+ /**
+ * If the frontend code rate is linear or not. Only supported in Tuner HAL 1.1 or higher.
+ */
+ public static final int FRONTEND_STATUS_TYPE_IS_LINEAR =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.IS_LINEAR;
+ /**
+ * If short frames is enabled or not. Only supported in Tuner HAL 1.1 or higher.
+ */
+ public static final int FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendStatusTypeExt1_1.IS_SHORT_FRAMES;
/** @hide */
@IntDef(value = {
@@ -379,6 +401,22 @@ public class FrontendStatus {
@Retention(RetentionPolicy.SOURCE)
public @interface FrontendGuardInterval {}
+ /** @hide */
+ @IntDef(value = {
+ DvbsFrontendSettings.ROLLOFF_UNDEFINED,
+ DvbsFrontendSettings.ROLLOFF_0_35,
+ DvbsFrontendSettings.ROLLOFF_0_25,
+ DvbsFrontendSettings.ROLLOFF_0_20,
+ DvbsFrontendSettings.ROLLOFF_0_15,
+ DvbsFrontendSettings.ROLLOFF_0_10,
+ DvbsFrontendSettings.ROLLOFF_0_5,
+ Isdbs3FrontendSettings.ROLLOFF_UNDEFINED,
+ Isdbs3FrontendSettings.ROLLOFF_0_03,
+ IsdbsFrontendSettings.ROLLOFF_UNDEFINED,
+ IsdbsFrontendSettings.ROLLOFF_0_35})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FrontendRollOff {}
+
private Boolean mIsDemodLocked;
private Integer mSnr;
private Integer mBer;
@@ -412,6 +450,10 @@ public class FrontendStatus {
private int[] mTsDataRate;
private int[] mIsdbtSegment;
private int[] mModulationsExt;
+ private Integer mRollOff;
+ private Boolean mIsMisoEnabled;
+ private Boolean mIsLinear;
+ private Boolean mIsShortFrames;
// Constructed and fields set by JNI code.
@@ -817,6 +859,67 @@ public class FrontendStatus {
}
/**
+ * Gets roll off status.
+ *
+ * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ */
+ @FrontendRollOff
+ public int getRollOff() {
+ TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "getRollOff status");
+ if (mRollOff == null) {
+ throw new IllegalStateException();
+ }
+ return mRollOff;
+ }
+
+ /**
+ * Gets is MISO enabled status.
+ *
+ * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ */
+ public boolean isMisoEnabled() {
+ TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "isMisoEnabled status");
+ if (mIsMisoEnabled == null) {
+ throw new IllegalStateException();
+ }
+ return mIsMisoEnabled;
+ }
+
+ /**
+ * Gets is the Code Rate of the frontend is linear or not status.
+ *
+ * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ */
+ public boolean isLinear() {
+ TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "isLinear status");
+ if (mIsLinear == null) {
+ throw new IllegalStateException();
+ }
+ return mIsLinear;
+ }
+
+ /**
+ * Gets is the Short Frames enabled or not status.
+ *
+ * <p>This status query is only supported by Tuner HAL 1.1 or higher. Use
+ * {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ */
+ public boolean isShortFramesEnabled() {
+ TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "isShortFramesEnabled status");
+ if (mIsShortFrames == null) {
+ throw new IllegalStateException();
+ }
+ return mIsShortFrames;
+ }
+
+ /**
* Status for each tuning Physical Layer Pipes.
*/
public static class Atsc3PlpTuningInfo {
diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
index 9bf7a5dd40cb..27627d7ad968 100644
--- a/media/java/android/media/tv/tuner/frontend/ScanCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
@@ -75,4 +75,7 @@ public interface ScanCallback {
/** Frontend scan message priority reported. */
default void onPriorityReported(boolean isHighPriority) {}
+
+ /** DVBC Frontend Annex reported. */
+ default void onDvbcAnnexReported(@DvbcFrontendSettings.Annex int dvbcAnnex) {}
}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 724965dac947..c7fb50f61666 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -31,6 +31,8 @@ cc_library_shared {
],
shared_libs: [
+ "audioclient-types-aidl-unstable-cpp",
+ "av-types-aidl-unstable-cpp",
"libandroid_runtime",
"libaudioclient",
"libnativehelper",
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 27e199205459..b9e78483a188 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -156,6 +156,7 @@ using ::android::hardware::tv::tuner::V1_1::FrontendDtmbTransmissionMode;
using ::android::hardware::tv::tuner::V1_1::FrontendGuardInterval;
using ::android::hardware::tv::tuner::V1_1::FrontendInterleaveMode;
using ::android::hardware::tv::tuner::V1_1::FrontendModulation;
+using ::android::hardware::tv::tuner::V1_1::FrontendRollOff;
using ::android::hardware::tv::tuner::V1_1::FrontendSpectralInversion;
using ::android::hardware::tv::tuner::V1_1::FrontendStatusExt1_1;
using ::android::hardware::tv::tuner::V1_1::FrontendStatusTypeExt1_1;
@@ -605,9 +606,13 @@ jobjectArray FilterCallback::getTsRecordEvent(
jlong pts = (eventsExt.size() > i) ? static_cast<jlong>(eventsExt[i].tsRecord().pts)
: static_cast<jlong>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
+ jlong firstMbInSlice = (eventsExt.size() > i)
+ ? static_cast<jint>(eventsExt[i].tsRecord().firstMbInSlice)
+ : static_cast<jint>(Constant::INVALID_FIRST_MACROBLOCK_IN_SLICE);
jobject obj =
- env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber, pts);
+ env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber,
+ pts, firstMbInSlice);
env->SetObjectArrayElement(arr, i, obj);
}
return arr;
@@ -632,10 +637,15 @@ jobjectArray FilterCallback::getMmtpRecordEvent(
: static_cast<jint>(Constant::INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM);
jlong pts = (eventsExt.size() > i) ? static_cast<jlong>(eventsExt[i].mmtpRecord().pts)
: static_cast<jlong>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
+ jlong firstMbInSlice = (eventsExt.size() > i)
+ ? static_cast<jint>(eventsExt[i].mmtpRecord().firstMbInSlice)
+ : static_cast<jint>(Constant::INVALID_FIRST_MACROBLOCK_IN_SLICE);
+ jlong tsIndexMask = (eventsExt.size() > i)
+ ? static_cast<jint>(eventsExt[i].mmtpRecord().tsIndexMask) : 0;
jobject obj =
env->NewObject(eventClazz, eventInit, scHevcIndexMask, byteNumber,
- mpuSequenceNumber, pts);
+ mpuSequenceNumber, pts, firstMbInSlice, tsIndexMask);
env->SetObjectArrayElement(arr, i, obj);
}
return arr;
@@ -1058,10 +1068,18 @@ Return<void> FrontendCallback::onScanMessageExt1_1(FrontendScanMessageTypeExt1_1
bool isHighPriority = message.isHighPriority();
env->CallVoidMethod(
mObject,
- env->GetMethodID(clazz, "onPriorityReported", "([B)V"),
+ env->GetMethodID(clazz, "onPriorityReported", "(B)V"),
isHighPriority);
break;
}
+ case FrontendScanMessageTypeExt1_1::DVBC_ANNEX: {
+ jint dvbcAnnex = (jint) message.annex();
+ env->CallVoidMethod(
+ mObject,
+ env->GetMethodID(clazz, "onDvbcAnnexReported", "(I)V"),
+ dvbcAnnex);
+ break;
+ }
default:
break;
}
@@ -1227,10 +1245,10 @@ jobject JTuner::getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilit
jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) {
jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendCapabilities");
- jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(III)V");
+ jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IJI)V");
jint modulationCap = caps.dvbcCaps().modulationCap;
- jint fecCap = caps.dvbcCaps().fecCap;
+ jlong fecCap = caps.dvbcCaps().fecCap;
jint annexCap = caps.dvbcCaps().annexCap;
return env->NewObject(clazz, capsInit, modulationCap, fecCap, annexCap);
@@ -2469,6 +2487,55 @@ jobject JTuner::getFrontendStatus(jintArray types) {
env->SetObjectField(statusObj, field, valObj);
break;
}
+ case FrontendStatusExt1_1::hidl_discriminator::rollOff: {
+ jfieldID field = env->GetFieldID(clazz, "mRollOff", "Ljava/lang/Integer;");
+ auto rollOff = s.rollOff();
+ jint intRollOff;
+ bool valid = true;
+ switch(rollOff.getDiscriminator()) {
+ case FrontendRollOff::hidl_discriminator::dvbs: {
+ intRollOff = static_cast<jint>(rollOff.dvbs());
+ break;
+ }
+ case FrontendRollOff::hidl_discriminator::isdbs: {
+ intRollOff = static_cast<jint>(rollOff.isdbs());
+ break;
+ }
+ case FrontendRollOff::hidl_discriminator::isdbs3: {
+ intRollOff = static_cast<jint>(rollOff.isdbs3());
+ break;
+ }
+ default:
+ valid = false;
+ break;
+ }
+ if (valid) {
+ jobject newIntegerObj = env->NewObject(intClazz, initInt, intRollOff);
+ env->SetObjectField(statusObj, field, newIntegerObj);
+ }
+ break;
+ }
+ case FrontendStatusExt1_1::hidl_discriminator::isMiso: {
+ jfieldID field = env->GetFieldID(clazz, "mIsMisoEnabled", "Ljava/lang/Boolean;");
+ jobject newBooleanObj = env->NewObject(
+ booleanClazz, initBoolean, static_cast<jboolean>(s.isMiso()));
+ env->SetObjectField(statusObj, field, newBooleanObj);
+ break;
+ }
+ case FrontendStatusExt1_1::hidl_discriminator::isLinear: {
+ jfieldID field = env->GetFieldID(clazz, "mIsLinear", "Ljava/lang/Boolean;");
+ jobject newBooleanObj = env->NewObject(
+ booleanClazz, initBoolean, static_cast<jboolean>(s.isLinear()));
+ env->SetObjectField(statusObj, field, newBooleanObj);
+ break;
+ }
+ case FrontendStatusExt1_1::hidl_discriminator::isShortFrames: {
+ jfieldID field = env->GetFieldID(clazz, "mIsShortFrames", "Ljava/lang/Boolean;");
+ jobject newBooleanObj = env->NewObject(
+ booleanClazz, initBoolean, static_cast<jboolean>(s.isShortFrames()));
+ env->SetObjectField(statusObj, field, newBooleanObj);
+ break;
+ }
default: {
break;
}
@@ -2479,7 +2546,7 @@ jobject JTuner::getFrontendStatus(jintArray types) {
bool JTuner::isV1_1ExtendedStatusType(int type) {
return (type > static_cast<int>(FrontendStatusType::ATSC3_PLP_INFO)
- && type <= static_cast<int>(FrontendStatusTypeExt1_1::TS_DATA_RATES));
+ && type <= static_cast<int>(FrontendStatusTypeExt1_1::IS_SHORT_FRAMES));
}
jint JTuner::closeFrontend() {
@@ -3957,6 +4024,28 @@ static jlong android_media_tv_Tuner_get_filter_64bit_id(JNIEnv* env, jobject fil
::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT);
}
+static jint android_media_tv_Tuner_configure_scrambling_status_event(
+ JNIEnv* env, jobject filter, int scramblingStatusMask) {
+ sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
+ if (iFilterSp == NULL) {
+ ALOGD("Failed to configure scrambling event: filter not found");
+ return (jint) Result::NOT_INITIALIZED;
+ }
+
+ sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
+ iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
+ Result res;
+
+ if (iFilterSp_1_1 != NULL) {
+ res = iFilterSp_1_1->configureScramblingEvent(scramblingStatusMask);
+ } else {
+ ALOGW("configureScramblingEvent is not supported with the current HAL implementation.");
+ return (jint) Result::INVALID_STATE;
+ }
+
+ return (jint) res;
+}
+
static jint android_media_tv_Tuner_set_filter_data_source(
JNIEnv* env, jobject filter, jobject srcFilter) {
sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
@@ -4628,6 +4717,8 @@ static const JNINativeMethod gFilterMethods[] = {
{ "nativeGetId", "()I", (void *)android_media_tv_Tuner_get_filter_id },
{ "nativeGetId64Bit", "()J",
(void *)android_media_tv_Tuner_get_filter_64bit_id },
+ { "nativeconfigureScramblingEvent", "(I)I",
+ (void *)android_media_tv_Tuner_configure_scrambling_status_event },
{ "nativeSetDataSource", "(Landroid/media/tv/tuner/filter/Filter;)I",
(void *)android_media_tv_Tuner_set_filter_data_source },
{ "nativeStartFilter", "()I", (void *)android_media_tv_Tuner_start_filter },
diff --git a/media/packages/BluetoothMidiService/tests/unit/Android.bp b/media/packages/BluetoothMidiService/tests/unit/Android.bp
index 4d4ae9e15532..fa4612bc22e7 100644
--- a/media/packages/BluetoothMidiService/tests/unit/Android.bp
+++ b/media/packages/BluetoothMidiService/tests/unit/Android.bp
@@ -20,7 +20,6 @@ android_test {
certificate: "platform",
static_libs: [
//"frameworks-base-testutils",
- "android-support-test",
"androidx.test.core",
"androidx.test.ext.truth",
"androidx.test.runner",
diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp
index 234462f1dc9b..3f1954a0874a 100644
--- a/media/tests/MediaFrameworkTest/Android.bp
+++ b/media/tests/MediaFrameworkTest/Android.bp
@@ -10,7 +10,6 @@ android_test {
"androidx.test.ext.junit",
"androidx.test.rules",
"android-ex-camera2",
- "android-support-test",
"testng"
],
platform_apis: true,
diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp
index 4d0c258843f9..a439b79fa2f0 100644
--- a/media/tests/MediaRouter/Android.bp
+++ b/media/tests/MediaRouter/Android.bp
@@ -9,7 +9,7 @@ android_test {
],
static_libs: [
- "android-support-test",
+ "androidx.test.rules",
"mockito-target-minus-junit4",
"testng",
"truth-prebuilt",
diff --git a/media/tests/MediaRouter/AndroidManifest.xml b/media/tests/MediaRouter/AndroidManifest.xml
index d9806f3cbb1d..02688d5d641a 100644
--- a/media/tests/MediaRouter/AndroidManifest.xml
+++ b/media/tests/MediaRouter/AndroidManifest.xml
@@ -27,7 +27,7 @@
</service>
</application>
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.mediaroutertest"
android:label="MediaRouter Tests"/>
</manifest>
diff --git a/media/tests/MediaRouter/AndroidTest.xml b/media/tests/MediaRouter/AndroidTest.xml
index 1301062db496..d350e05ecc33 100644
--- a/media/tests/MediaRouter/AndroidTest.xml
+++ b/media/tests/MediaRouter/AndroidTest.xml
@@ -10,7 +10,7 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.mediaroutertest"/>
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouteInfoTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouteInfoTest.java
index 92e4c9554cb4..255b95f63682 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouteInfoTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouteInfoTest.java
@@ -20,13 +20,14 @@ import static com.google.common.truth.Truth.assertThat;
import android.hardware.display.DisplayManagerGlobal;
import android.media.MediaRouter;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayAdjustments;
import android.view.DisplayInfo;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index ddefe266d897..1286fc1ad16a 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -52,12 +52,13 @@ import android.media.MediaRouter2Utils;
import android.media.RouteDiscoveryPreference;
import android.media.RoutingSessionInfo;
import android.os.Bundle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
import android.text.TextUtils;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
index 31f240d87f94..77b3160a8016 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
@@ -20,8 +20,9 @@ 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 androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/media/tests/MediaTranscodingTest/Android.bp b/media/tests/MediaTranscodingTest/Android.bp
index 907c3c8b4933..bd687a1f9a8f 100644
--- a/media/tests/MediaTranscodingTest/Android.bp
+++ b/media/tests/MediaTranscodingTest/Android.bp
@@ -9,7 +9,7 @@ android_test {
"androidx.test.ext.junit",
"androidx.test.rules",
"androidx.test.uiautomator_uiautomator",
- "android-support-test",
+ "androidx.test.rules",
"testng"
],
platform_apis: true,
diff --git a/media/tests/TunerTest/Android.bp b/media/tests/TunerTest/Android.bp
index cef879112225..e86560447f31 100644
--- a/media/tests/TunerTest/Android.bp
+++ b/media/tests/TunerTest/Android.bp
@@ -9,7 +9,7 @@ android_test {
],
static_libs: [
- "android-support-test",
+ "androidx.test.rules",
"testng"
],
diff --git a/media/tests/TunerTest/AndroidManifest.xml b/media/tests/TunerTest/AndroidManifest.xml
index 17e9f197b68c..ec155ca46f06 100644
--- a/media/tests/TunerTest/AndroidManifest.xml
+++ b/media/tests/TunerTest/AndroidManifest.xml
@@ -23,7 +23,7 @@
<uses-library android:name="android.test.runner" />
</application>
- <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.mediatunertest"
android:label="Media Tuner Tests"/>
</manifest>
diff --git a/media/tests/TunerTest/AndroidTest.xml b/media/tests/TunerTest/AndroidTest.xml
index d9c31f45532f..c718b150d922 100644
--- a/media/tests/TunerTest/AndroidTest.xml
+++ b/media/tests/TunerTest/AndroidTest.xml
@@ -12,6 +12,6 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.mediatunertest"/>
<option name="hidden-api-checks" value="false"/>
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
</test>
</configuration>
diff --git a/media/tests/TunerTest/src/com/android/mediatunertest/TunerTest.java b/media/tests/TunerTest/src/com/android/mediatunertest/TunerTest.java
index afdbce0badae..de7f7ebabd8c 100644
--- a/media/tests/TunerTest/src/com/android/mediatunertest/TunerTest.java
+++ b/media/tests/TunerTest/src/com/android/mediatunertest/TunerTest.java
@@ -21,9 +21,10 @@ import static org.junit.Assert.assertNotNull;
import android.content.Context;
import android.media.tv.tuner.Descrambler;
import android.media.tv.tuner.Tuner;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types
index f3730f2756d2..e5273a927007 100644
--- a/mime/java-res/android.mime.types
+++ b/mime/java-res/android.mime.types
@@ -91,6 +91,7 @@
?image/heic-sequence heics
?image/heif heif hif
?image/heif-sequence heifs
+?image/avif avif
?image/ico cur
?image/webp webp
?image/x-adobe-dng dng
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 02e1ebe05b02..7793d6c45d5e 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -46,6 +46,7 @@ cc_library_shared {
"native_window_jni.cpp",
"net.c",
"obb.cpp",
+ "permission_manager.cpp",
"sensor.cpp",
"sharedmem.cpp",
"storage_manager.cpp",
diff --git a/native/android/TEST_MAPPING b/native/android/TEST_MAPPING
new file mode 100644
index 000000000000..6a5d2c008b1d
--- /dev/null
+++ b/native/android/TEST_MAPPING
@@ -0,0 +1,17 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsPermissionManagerNativeTestCases",
+ "file_patterns": ["permission_manager.cpp"]
+ },
+ {
+ "name": "CtsPermissionTestCases",
+ "options": [
+ {
+ "include-filter": "android.permission.cts.PermissionManagerNativeJniTest"
+ }
+ ],
+ "file_patterns": ["permission_manager.cpp"]
+ }
+ ]
+}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 0414930b4078..3027eac3a224 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -176,6 +176,7 @@ LIBANDROID {
AObbInfo_getPackageName;
AObbInfo_getVersion;
AObbScanner_getObbInfo;
+ APermissionManager_checkPermission; # introduced=31
ASensorEventQueue_disableSensor;
ASensorEventQueue_enableSensor;
ASensorEventQueue_getEvents;
diff --git a/native/android/permission_manager.cpp b/native/android/permission_manager.cpp
new file mode 100644
index 000000000000..166e00e8dbe2
--- /dev/null
+++ b/native/android/permission_manager.cpp
@@ -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.
+ */
+
+#include <android/permission_manager.h>
+#include <binder/ActivityManager.h>
+
+namespace android {
+namespace permissionmananger {
+
+// Global instance of ActivityManager, service is obtained only on first use.
+static ActivityManager gAm;
+
+} // permissionmanager
+} // android
+
+using namespace android;
+using namespace permissionmananger;
+
+int32_t APermissionManager_checkPermission(const char* permission,
+ pid_t pid,
+ uid_t uid,
+ int32_t* outResult) {
+ status_t result = gAm.checkPermission(String16(permission), pid, uid, outResult);
+ if (result == DEAD_OBJECT) {
+ return PERMISSION_MANAGER_STATUS_SERVICE_UNAVAILABLE;
+ } else if (result != NO_ERROR) {
+ return PERMISSION_MANAGER_STATUS_ERROR_UNKNOWN;
+ }
+ return PERMISSION_MANAGER_STATUS_OK;
+}
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
deleted file mode 100644
index 08dd79973fa9..000000000000
--- a/packages/CarSystemUI/Android.bp
+++ /dev/null
@@ -1,165 +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.
-//
-android_library {
- name: "CarSystemUI-core",
-
- srcs: [
- "src/**/*.java",
- "src/**/I*.aidl",
- ],
-
- resource_dirs: [
- "res-keyguard",
- "res",
- ],
-
- static_libs: [
- "SystemUI-core",
- "CarNotificationLib",
- "SystemUIPluginLib",
- "SystemUISharedLib",
- "SettingsLib",
- "car-ui-lib",
- "android.car.userlib",
- "androidx.legacy_legacy-support-v4",
- "androidx.recyclerview_recyclerview",
- "androidx.preference_preference",
- "androidx.appcompat_appcompat",
- "androidx.mediarouter_mediarouter",
- "androidx.palette_palette",
- "androidx.legacy_legacy-preference-v14",
- "androidx.leanback_leanback",
- "androidx.slice_slice-core",
- "androidx.slice_slice-view",
- "androidx.slice_slice-builders",
- "androidx.arch.core_core-runtime",
- "androidx.lifecycle_lifecycle-extensions",
- "SystemUI-tags",
- "SystemUI-proto",
- "dagger2",
- "//external/kotlinc:kotlin-annotations",
- ],
-
- libs: [
- "android.car",
- ],
-
- manifest: "AndroidManifest.xml",
-
- plugins: ["dagger2-compiler"],
-
-}
-
-android_library {
- name: "CarSystemUI-tests",
- manifest: "tests/AndroidManifest.xml",
- resource_dirs: [
- "tests/res",
- "res-keyguard",
- "res",
- ],
- srcs: [
- "tests/src/**/*.java",
- "src/**/*.java",
- "src/**/I*.aidl",
- ],
- static_libs: [
- "SystemUI-tests",
- "CarNotificationLib",
- "SystemUIPluginLib",
- "SystemUISharedLib",
- "SettingsLib",
- "android.car.userlib",
- "androidx.legacy_legacy-support-v4",
- "androidx.recyclerview_recyclerview",
- "androidx.preference_preference",
- "androidx.appcompat_appcompat",
- "androidx.mediarouter_mediarouter",
- "androidx.palette_palette",
- "androidx.legacy_legacy-preference-v14",
- "androidx.leanback_leanback",
- "androidx.slice_slice-core",
- "androidx.slice_slice-view",
- "androidx.slice_slice-builders",
- "androidx.arch.core_core-runtime",
- "androidx.lifecycle_lifecycle-extensions",
- "car-ui-lib",
- "SystemUI-tags",
- "SystemUI-proto",
- "metrics-helper-lib",
- "androidx.test.rules", "hamcrest-library",
- "mockito-target-inline-minus-junit4",
- "testables",
- "truth-prebuilt",
- "dagger2",
- "//external/kotlinc:kotlin-annotations",
- ],
- libs: [
- "android.test.runner",
- "android.test.base",
- "android.car",
- ],
-
- aaptflags: [
- "--extra-packages",
- "com.android.systemui",
- ],
-
- plugins: ["dagger2-compiler"],
-}
-
-android_app {
- name: "CarSystemUI",
-
- static_libs: [
- "CarSystemUI-core",
- ],
-
- export_package_resources: true,
-
- libs: [
- "android.car",
- ],
-
- resource_dirs: [],
-
- overrides: [
- "SystemUI",
- ],
-
- platform_apis: true,
- system_ext_specific: true,
- certificate: "platform",
- privileged: true,
-
- optimize: {
- proguard_flags_files: [
- "proguard.flags",
- ],
- },
- dxflags: ["--multi-dex"],
-
- aaptflags: [
- "--extra-packages",
- "com.android.keyguard",
- ],
-
- kotlincflags: ["-Xjvm-default=enable"],
-
- plugins: ["dagger2-compiler"],
-
- required: ["privapp_whitelist_com.android.systemui"],
-}
diff --git a/packages/CarSystemUI/AndroidManifest.xml b/packages/CarSystemUI/AndroidManifest.xml
deleted file mode 100644
index f0cf2a9b7156..000000000000
--- a/packages/CarSystemUI/AndroidManifest.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- package="com.android.systemui"
- android:sharedUserId="android.uid.systemui"
- coreApp="true">
- <!-- This permission is required to monitor car power state. -->
- <uses-permission android:name="android.car.permission.CAR_POWER" />
- <!-- This permission is required to get the trusted device list of a user. -->
- <uses-permission android:name="android.car.permission.CAR_ENROLL_TRUST"/>
- <!-- This permission is required to monitor gear state. -->
- <uses-permission android:name="android.car.permission.CAR_POWERTRAIN" />
- <!-- This permission is required to get bluetooth broadcast. -->
- <uses-permission android:name="android.permission.BLUETOOTH" />
- <!-- These permissions are required to implement icons based on role holders. -->
- <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"/>
- <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS"/>
- <!-- This permission is required to access app information from other users. -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
- <!-- This permission is required to check the foreground user id. -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
-</manifest>
diff --git a/packages/CarSystemUI/CleanSpec.mk b/packages/CarSystemUI/CleanSpec.mk
deleted file mode 100644
index ceac67c55f09..000000000000
--- a/packages/CarSystemUI/CleanSpec.mk
+++ /dev/null
@@ -1,50 +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.
-#
-
-# If you don't need to do a full clean build but would like to touch
-# a file or delete some intermediate files, add a clean step to the end
-# of the list. These steps will only be run once, if they haven't been
-# run before.
-#
-# E.g.:
-# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
-# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
-#
-# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
-# files that are missing or have been moved.
-#
-# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
-# Use $(OUT_DIR) to refer to the "out" directory.
-#
-# If you need to re-do something that's already mentioned, just copy
-# the command and add it to the bottom of the list. E.g., if a change
-# that you made last week required touching a file and a change you
-# made today requires touching the same file, just copy the old
-# touch step and add it to the end of the list.
-#
-# *****************************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
-# *****************************************************************
-
-# For example:
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
-#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
-#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/priv-app/CarSystemUI)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/priv-app/CarSystemUI)
-# ******************************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
-# ******************************************************************
diff --git a/packages/CarSystemUI/TEST_MAPPING b/packages/CarSystemUI/TEST_MAPPING
deleted file mode 100644
index 54afb9097f87..000000000000
--- a/packages/CarSystemUI/TEST_MAPPING
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "auto-end-to-end-presubmit": [
- {
- "name": "AndroidAutoUiTests",
- "options" : [
- {
- "include-filter": "android.test.functional.auto.apps.HomeHelperTest"
- }
- ]
- }
- ],
- "auto-end-to-end-postsubmit": [
- {
- "name": "AndroidAutoUiTests",
- "options" : [
- {
- "include-filter": "android.test.functional.auto.apps.NotificationHelperTest"
- }
- ]
- }
- ],
- "carsysui-presubmit": [
- {
- "name": "CarSystemUITests",
- "options" : [
- {
- "include-annotation": "com.android.systemui.car.CarSystemUiTest"
- }
- ]
- }
- ]
-}
diff --git a/packages/CarSystemUI/proguard.flags b/packages/CarSystemUI/proguard.flags
deleted file mode 100644
index f0b20c105b84..000000000000
--- a/packages/CarSystemUI/proguard.flags
+++ /dev/null
@@ -1,7 +0,0 @@
--keep class com.android.systemui.CarSystemUIFactory
--keep class com.android.car.notification.headsup.animationhelper.**
-
--keep class com.android.systemui.DaggerCarGlobalRootComponent { *; }
--keep class com.android.systemui.DaggerCarGlobalRootComponent$CarSysUIComponentImpl { *; }
-
--include ../SystemUI/proguard.flags
diff --git a/packages/CarSystemUI/res-keyguard/drawable/ic_backspace.xml b/packages/CarSystemUI/res-keyguard/drawable/ic_backspace.xml
deleted file mode 100644
index f3a2f0f76a08..000000000000
--- a/packages/CarSystemUI/res-keyguard/drawable/ic_backspace.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="36dp"
- android:height="36dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M9,15.59L12.59,12L9,8.41L10.41,7L14,10.59L17.59,7L19,8.41L15.41,12L19,15.59L17.59,17L14,13.41L10.41,17L9,15.59zM21,6H8l-4.5,6L8,18h13V6M21,4c1.1,0 2,0.9 2,2v12c0,1.1 -0.9,2 -2,2H8c-0.63,0 -1.22,-0.3 -1.6,-0.8L1,12l5.4,-7.2C6.78,4.3 7.37,4 8,4H21L21,4z"/>
-</vector>
diff --git a/packages/CarSystemUI/res-keyguard/drawable/ic_done.xml b/packages/CarSystemUI/res-keyguard/drawable/ic_done.xml
deleted file mode 100644
index ef0aac27b84e..000000000000
--- a/packages/CarSystemUI/res-keyguard/drawable/ic_done.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="36dp"
- android:height="36dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M9,16.2l-3.5,-3.5a0.984,0.984 0,0 0,-1.4 0,0.984 0.984,0 0,0 0,1.4l4.19,4.19c0.39,0.39 1.02,0.39 1.41,0L20.3,7.7a0.984,0.984 0,0 0,0 -1.4,0.984 0.984,0 0,0 -1.4,0L9,16.2z"/>
-</vector>
diff --git a/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml b/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml
deleted file mode 100644
index 8b2779d10481..000000000000
--- a/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true">
- <shape android:shape="rectangle">
- <corners android:radius="@*android:dimen/car_button_radius"/>
- <solid android:color="#131315"/>
- </shape>
- </item>
- <item>
- <shape android:shape="rectangle">
- <corners android:radius="@*android:dimen/car_button_radius"/>
- <solid android:color="@color/button_background"/>
- </shape>
- </item>
-</selector>
diff --git a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
deleted file mode 100644
index a465254afebb..000000000000
--- a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
+++ /dev/null
@@ -1,82 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<!-- Car customizations
- - Added title "Enter your Pattern" at the top
- - Hid the emergency call at the bottom
--->
-
-<com.android.keyguard.KeyguardPatternView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/keyguard_pattern_view"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingHorizontal="@*android:dimen/car_margin">
-
- <FrameLayout
- android:layout_height="match_parent"
- android:layout_width="0dp"
- android:layout_weight="1">
-
- <com.android.internal.widget.LockPatternView
- android:id="@+id/lockPatternView"
- android:layout_width="@dimen/keyguard_pattern_dimension"
- android:layout_height="@dimen/keyguard_pattern_dimension"
- android:layout_gravity="center"/>
- </FrameLayout>
-
- <LinearLayout
- android:id="@+id/container"
- android:layout_height="match_parent"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:orientation="vertical"
- android:gravity="center_vertical">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="@*android:dimen/car_padding_2"
- android:gravity="center"
- android:textColor="@android:color/white"
- android:textSize="@*android:dimen/car_body1_size"
- android:text="@string/keyguard_enter_your_pattern" />
-
- <include layout="@layout/keyguard_message_area" />
-
- <Button
- android:id="@+id/cancel_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- style="@style/KeyguardButton"
- android:text="@string/cancel"/>
-
- <include layout="@layout/keyguard_eca"
- android:id="@+id/keyguard_selector_fade_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="bottom|center_horizontal"
- android:gravity="center_horizontal"
- android:visibility="gone" />
- </LinearLayout>
-
-</com.android.keyguard.KeyguardPatternView>
diff --git a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml
deleted file mode 100644
index 5746102f5f27..000000000000
--- a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml
+++ /dev/null
@@ -1,126 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-
-<!-- Car customizations
- - Added title "Enter your PIN" under the entry field
- - Put backspace and enter buttons in row 4
- - PIN pad is on start side while entry field and title are on the end side
- - Hid the emergency call at the bottom
--->
-
-<com.android.keyguard.KeyguardPINView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/keyguard_pin_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:paddingHorizontal="@*android:dimen/car_margin">
-
- <FrameLayout
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="match_parent">
-
- <GridLayout
- android:id="@+id/container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center"
- android:columnCount="3">
-
- <include layout="@layout/num_pad_keys"/>
- </GridLayout>
- </FrameLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center"
- android:orientation="vertical">
-
- <com.android.keyguard.PasswordTextView
- android:id="@+id/pinEntry"
- android:layout_width="@dimen/keyguard_security_width"
- android:layout_height="@dimen/pin_entry_height"
- android:gravity="center"
- app:scaledTextSize="@integer/password_text_view_scale"
- android:contentDescription="@string/keyguard_accessibility_pin_area" />
-
- <View
- android:id="@+id/divider"
- android:layout_width="@dimen/keyguard_security_width"
- android:layout_height="@dimen/divider_height"
- android:background="@android:color/white" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="@*android:dimen/car_padding_2"
- android:gravity="center"
- android:textColor="@android:color/white"
- android:textSize="@*android:dimen/car_body1_size"
- android:text="@string/keyguard_enter_your_pin" />
-
- <include layout="@layout/keyguard_message_area" />
-
- <Button
- android:id="@+id/cancel_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- style="@style/KeyguardButton"
- android:text="@string/cancel"/>
- </LinearLayout>
-
- <!-- KeyguardPinView references these resources ids in code so removing them will cause the
- keyguard to crash. Instead put them down here where they are out of the way and set their
- visibility to gone. -->
- <com.android.keyguard.AlphaOptimizedRelativeLayout
- android:id="@+id/row0"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
- <LinearLayout
- android:id="@+id/row1"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
- <LinearLayout
- android:id="@+id/row2"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
- <LinearLayout
- android:id="@+id/row3"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
- <LinearLayout
- android:id="@+id/row4"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
-
- <include layout="@layout/keyguard_eca"
- android:id="@+id/keyguard_selector_fade_container"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
-</com.android.keyguard.KeyguardPINView>
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml
deleted file mode 100644
index d105e4415ca3..000000000000
--- a/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<!-- Car customizations
- Car has solid black background instead of a transparent one
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/black"
- android:fitsSystemWindows="true">
-
- <include
- style="@style/BouncerSecurityContainer"
- layout="@layout/keyguard_host_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-</FrameLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_container.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_container.xml
deleted file mode 100644
index 3e35df9d9b0c..000000000000
--- a/packages/CarSystemUI/res-keyguard/layout/keyguard_container.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
- -->
-
-<!-- Car customizations
- Car has solid black background instead of a transparent one
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/keyguard_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"/> \ No newline at end of file
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml
deleted file mode 100644
index 09cf4722dae0..000000000000
--- a/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.keyguard.KeyguardMessageArea
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- style="@style/Keyguard.TextView"
- android:id="@+id/keyguard_message_area"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:focusable="true"
- android:layout_marginBottom="@*android:dimen/car_padding_4"
- android:textSize="@*android:dimen/car_body2_size" />
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_num_pad_key.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
deleted file mode 100644
index c7eda3888d7a..000000000000
--- a/packages/CarSystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<!-- Car customizations
- The mnemonics is not shown for car but KeyguardPinView references the resource id in code.
- Removing it will cause the keyguard to crash. Hide them instead
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <TextView
- android:id="@+id/digit_text"
- style="@style/Widget.TextView.NumPadKey"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- />
- <!-- The mnemonics is not shown for car but KeyguardPinView references the resource id in code.
- Removing it will cause the keyguard to crash. Hide them instead -->
- <TextView
- android:id="@+id/klondike_text"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone"
- />
-</merge>
-
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml
deleted file mode 100644
index d57875f8daba..000000000000
--- a/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<!-- Car customizations
- - Added title "Enter your Password" below the password field
- - Hid the emergency call at the bottom
--->
-
-<com.android.keyguard.KeyguardPasswordView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- android:id="@+id/keyguard_password_view"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center">
-
- <include layout="@layout/keyguard_message_area" />
-
- <!-- Password entry field -->
- <LinearLayout
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="center_horizontal"
- android:orientation="vertical"
- android:theme="?attr/passwordStyle">
-
- <EditText
- android:id="@+id/passwordEntry"
- android:layout_width="@dimen/password_field_width"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:singleLine="true"
- android:textStyle="normal"
- android:inputType="textPassword"
- android:textSize="@*android:dimen/car_body1_size"
- android:textColor="?attr/wallpaperTextColor"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:imeOptions="flagForceAscii|actionDone"
- android:maxLength="@integer/password_max_length"
- />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="@*android:dimen/car_padding_2"
- android:gravity="center"
- android:textColor="@android:color/white"
- android:textSize="@*android:dimen/car_body1_size"
- android:text="@string/keyguard_enter_your_password" />
-
- <Button
- android:id="@+id/cancel_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- style="@style/KeyguardButton"
- android:text="@string/cancel"/>
-
- <ImageView android:id="@+id/switch_ime_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="12dp"
- android:src="@drawable/ic_lockscreen_ime"
- android:contentDescription="@string/accessibility_ime_switch_button"
- android:clickable="true"
- android:padding="8dp"
- android:tint="@color/background_protected"
- android:layout_gravity="end|center_vertical"
- android:background="?android:attr/selectableItemBackground"
- android:visibility="gone"
- />
- </LinearLayout>
-
- <include layout="@layout/keyguard_eca"
- android:id="@+id/keyguard_selector_fade_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="12dp"
- android:orientation="vertical"
- android:layout_gravity="bottom|center_horizontal"
- android:gravity="center_horizontal"
- android:visibility="gone"
- />
-
-</com.android.keyguard.KeyguardPasswordView>
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_pattern_view.xml
deleted file mode 100644
index bb69d44a3ac7..000000000000
--- a/packages/CarSystemUI/res-keyguard/layout/keyguard_pattern_view.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<!-- Car customizations
- - Added title "Enter your Pattern" at the top
- - Hid the emergency call at the bottom
--->
-
-<com.android.keyguard.KeyguardPatternView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- android:id="@+id/keyguard_pattern_view"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- androidprv:layout_maxWidth="@dimen/keyguard_security_width"
- android:gravity="center_horizontal">
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:id="@+id/container"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="center">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="@*android:dimen/car_padding_2"
- android:gravity="center"
- android:textColor="@android:color/white"
- android:textSize="@*android:dimen/car_body1_size"
- android:text="@string/keyguard_enter_your_pattern" />
-
- <include layout="@layout/keyguard_message_area" />
-
- <com.android.internal.widget.LockPatternView
- android:id="@+id/lockPatternView"
- android:layout_width="@dimen/keyguard_pattern_dimension"
- android:layout_height="@dimen/keyguard_pattern_dimension"
- android:layout_marginVertical="@dimen/pin_pattern_pad_margin_vertical"
- android:layout_gravity="center_horizontal"
- android:gravity="center" />
-
- <Button
- android:id="@+id/cancel_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- style="@style/KeyguardButton"
- android:text="@string/cancel"/>
-
- <include layout="@layout/keyguard_eca"
- android:id="@+id/keyguard_selector_fade_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="bottom|center_horizontal"
- android:gravity="center_horizontal"
- android:visibility="gone" />
- </LinearLayout>
- </FrameLayout>
-
-</com.android.keyguard.KeyguardPatternView>
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_pin_view.xml
deleted file mode 100644
index 815e67d1e278..000000000000
--- a/packages/CarSystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-
-<!-- Car customizations
- - Added title "Enter your PIN" under the entry field
- - Put backspace and enter buttons in row 4
- - Hid the emergency call at the bottom
--->
-
-<com.android.keyguard.KeyguardPINView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/keyguard_pin_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginLeft="@dimen/num_pad_margin_left"
- android:layout_marginRight="@dimen/num_pad_margin_right"
- android:orientation="vertical"
- android:gravity="center">
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="vertical">
-
- <com.android.keyguard.PasswordTextView
- android:id="@+id/pinEntry"
- android:layout_width="@dimen/keyguard_security_width"
- android:layout_height="@dimen/pin_entry_height"
- android:gravity="center"
- app:scaledTextSize="@integer/password_text_view_scale"
- android:contentDescription="@string/keyguard_accessibility_pin_area" />
-
- <View
- android:id="@+id/divider"
- android:layout_width="@dimen/keyguard_security_width"
- android:layout_height="@dimen/divider_height"
- android:background="@android:color/white" />
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="@*android:dimen/car_padding_2"
- android:gravity="center"
- android:textColor="@android:color/white"
- android:textSize="@*android:dimen/car_body1_size"
- android:text="@string/keyguard_enter_your_pin" />
-
- <include layout="@layout/keyguard_message_area" />
-
- </LinearLayout>
-
- <GridLayout
- android:id="@+id/container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginVertical="@dimen/pin_pattern_pad_margin_vertical"
- android:columnCount="3">
-
- <include layout="@layout/num_pad_keys"/>
- </GridLayout>
-
- <Button
- android:id="@+id/cancel_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- style="@style/KeyguardButton"
- android:text="@string/cancel"/>
-
- </LinearLayout>
-
- <!-- KeyguardPinView references these resources ids in code so removing them will cause the
- keyguard to crash. Instead put them down here where they are out of the way and set their
- visibility to gone. -->
- <com.android.keyguard.AlphaOptimizedRelativeLayout
- android:id="@+id/row0"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
- <LinearLayout
- android:id="@+id/row1"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
- <LinearLayout
- android:id="@+id/row2"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
- <LinearLayout
- android:id="@+id/row3"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
- <LinearLayout
- android:id="@+id/row4"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
-
- <include
- layout="@layout/keyguard_eca"
- android:id="@+id/keyguard_selector_fade_container"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:visibility="gone" />
-</com.android.keyguard.KeyguardPINView>
diff --git a/packages/CarSystemUI/res-keyguard/layout/num_pad_keys.xml b/packages/CarSystemUI/res-keyguard/layout/num_pad_keys.xml
deleted file mode 100644
index 8306cb4a708a..000000000000
--- a/packages/CarSystemUI/res-keyguard/layout/num_pad_keys.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
- <!-- Row 1 -->
- <com.android.keyguard.NumPadKey
- android:id="@+id/key1"
- style="@style/NumPadKeyButton"
- app:digit="1" />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key2"
- style="@style/NumPadKeyButton.MiddleColumn"
- app:digit="2" />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key3"
- style="@style/NumPadKeyButton"
- app:digit="3" />
-
- <!-- Row 2 -->
- <com.android.keyguard.NumPadKey
- android:id="@+id/key4"
- style="@style/NumPadKeyButton"
- app:digit="4" />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key5"
- style="@style/NumPadKeyButton.MiddleColumn"
- app:digit="5" />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key6"
- style="@style/NumPadKeyButton"
- app:digit="6" />
-
- <!-- Row 3 -->
- <com.android.keyguard.NumPadKey
- android:id="@+id/key7"
- style="@style/NumPadKeyButton"
- app:digit="7" />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key8"
- style="@style/NumPadKeyButton.MiddleColumn"
- app:digit="8" />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key9"
- style="@style/NumPadKeyButton"
- app:digit="9" />
-
- <!-- Row 4 -->
- <ImageButton
- android:id="@+id/delete_button"
- style="@style/NumPadKeyButton.LastRow"
- android:gravity="center_vertical"
- android:src="@drawable/ic_backspace"
- android:clickable="true"
- android:tint="@android:color/white"
- android:background="@drawable/ripple_drawable"
- android:contentDescription="@string/keyboardview_keycode_delete" />
- <com.android.keyguard.NumPadKey
- android:id="@+id/key0"
- style="@style/NumPadKeyButton.LastRow.MiddleColumn"
- app:digit="0" />
- <ImageButton
- android:id="@+id/key_enter"
- style="@style/NumPadKeyButton.LastRow"
- android:src="@drawable/ic_done"
- android:tint="@android:color/white"
- android:background="@drawable/ripple_drawable"
- android:contentDescription="@string/keyboardview_keycode_enter" />
-</merge>
-
diff --git a/packages/CarSystemUI/res-keyguard/values-h1000dp/dimens.xml b/packages/CarSystemUI/res-keyguard/values-h1000dp/dimens.xml
deleted file mode 100644
index d055efa25078..000000000000
--- a/packages/CarSystemUI/res-keyguard/values-h1000dp/dimens.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-<resources>
- <dimen name="pin_pattern_pad_margin_vertical">178dp</dimen>
-</resources>
diff --git a/packages/CarSystemUI/res-keyguard/values-land/dimens.xml b/packages/CarSystemUI/res-keyguard/values-land/dimens.xml
deleted file mode 100644
index c39e0e4731e8..000000000000
--- a/packages/CarSystemUI/res-keyguard/values-land/dimens.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-<resources>
- <dimen name="num_pad_key_margin_horizontal">@*android:dimen/car_padding_5</dimen>
- <dimen name="num_pad_key_margin_bottom">@*android:dimen/car_padding_4</dimen>
-</resources>
diff --git a/packages/CarSystemUI/res-keyguard/values/colors.xml b/packages/CarSystemUI/res-keyguard/values/colors.xml
deleted file mode 100644
index ba9f060fab88..000000000000
--- a/packages/CarSystemUI/res-keyguard/values/colors.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 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.
--->
-
-<resources>
- <color name="button_background">@*android:color/car_dark_blue_grey_600</color>
- <color name="button_text">@android:color/white</color>
-</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/res-keyguard/values/dimens.xml b/packages/CarSystemUI/res-keyguard/values/dimens.xml
deleted file mode 100644
index 8dfe1716ef54..000000000000
--- a/packages/CarSystemUI/res-keyguard/values/dimens.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2017, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License")
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources>
- <dimen name="num_pad_margin_left">112dp</dimen>
- <dimen name="num_pad_margin_right">144dp</dimen>
- <dimen name="num_pad_key_width">80dp</dimen>
- <dimen name="num_pad_key_height">80dp</dimen>
- <dimen name="num_pad_key_margin_horizontal">@*android:dimen/car_padding_5</dimen>
- <dimen name="num_pad_key_margin_bottom">@*android:dimen/car_padding_5</dimen>
- <dimen name="pin_entry_height">@dimen/num_pad_key_height</dimen>
- <dimen name="divider_height">1dp</dimen>
- <dimen name="key_enter_margin_top">128dp</dimen>
- <dimen name="keyguard_pattern_dimension">400dp</dimen>
- <dimen name="password_field_width">350dp</dimen>
- <dimen name="pin_pattern_pad_margin_vertical">0dp</dimen>
-</resources>
diff --git a/packages/CarSystemUI/res-keyguard/values/integers.xml b/packages/CarSystemUI/res-keyguard/values/integers.xml
deleted file mode 100644
index bad1346af452..000000000000
--- a/packages/CarSystemUI/res-keyguard/values/integers.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2017, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License")
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources>
- <integer name="password_text_view_scale">40</integer>
- <integer name="password_max_length">500</integer>
-</resources>
diff --git a/packages/CarSystemUI/res-keyguard/values/styles.xml b/packages/CarSystemUI/res-keyguard/values/styles.xml
deleted file mode 100644
index ecea30a13ced..000000000000
--- a/packages/CarSystemUI/res-keyguard/values/styles.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright 2017, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License")
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-
- <!-- The style for the volume icons in the volume dialog. This style makes the icon scale to
- fit its container since auto wants the icon to be larger. The padding is added to make it
- so the icon does not press along the edges of the dialog. -->
- <style name="NumPadKeyButton">
- <item name="android:layout_width">@dimen/num_pad_key_width</item>
- <item name="android:layout_height">@dimen/num_pad_key_height</item>
- <item name="android:layout_marginBottom">@dimen/num_pad_key_margin_bottom</item>
- <item name="textView">@id/pinEntry</item>
- </style>
-
- <style name="NumPadKeyButton.MiddleColumn">
- <item name="android:layout_marginStart">@dimen/num_pad_key_margin_horizontal</item>
- <item name="android:layout_marginEnd">@dimen/num_pad_key_margin_horizontal</item>
- </style>
-
- <style name="NumPadKeyButton.LastRow">
- <item name="android:layout_marginBottom">0dp</item>
- </style>
-
- <style name="NumPadKeyButton.LastRow.MiddleColumn">
- <item name="android:layout_marginStart">@dimen/num_pad_key_margin_horizontal</item>
- <item name="android:layout_marginEnd">@dimen/num_pad_key_margin_horizontal</item>
- </style>
-
- <style name="KeyguardButton" parent="@android:style/Widget.DeviceDefault.Button">
- <item name="android:background">@drawable/keyguard_button_background</item>
- <item name="android:textColor">@color/button_text</item>
- <item name="android:textAllCaps">false</item>
- </style>
-
- <style name="Widget.TextView.NumPadKey" parent="@android:style/Widget.TextView">
- <!-- Only replaces the text size. -->
- <item name="android:textSize">@*android:dimen/car_body1_size</item>
- </style>
-</resources>
diff --git a/packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_down.xml b/packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_down.xml
deleted file mode 100644
index 74f38d4f9946..000000000000
--- a/packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_down.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together">
- <objectAnimator
- android:propertyName="rotation"
- android:duration="0"
- android:valueFrom="180"
- android:valueTo="0"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:propertyName="alpha"
- android:valueFrom="0.0"
- android:valueTo="1.0"
- android:valueType="floatType"
- android:duration="300"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:propertyName="scaleX"
- android:valueFrom="0.8"
- android:valueTo="1.0"
- android:valueType="floatType"
- android:duration="300"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:propertyName="scaleY"
- android:valueFrom="0.8"
- android:valueTo="1.0"
- android:valueType="floatType"
- android:duration="300"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_up.xml b/packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_up.xml
deleted file mode 100644
index 0f28297f0214..000000000000
--- a/packages/CarSystemUI/res/anim/car_arrow_fade_in_rotate_up.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together">
- <objectAnimator
- android:propertyName="rotation"
- android:duration="0"
- android:valueFrom="0"
- android:valueTo="180"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:propertyName="alpha"
- android:valueFrom="0.0"
- android:valueTo="1.0"
- android:valueType="floatType"
- android:duration="300"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:propertyName="scaleX"
- android:valueFrom="0.8"
- android:valueTo="1.0"
- android:valueType="floatType"
- android:duration="300"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:propertyName="scaleY"
- android:valueFrom="0.8"
- android:valueTo="1.0"
- android:valueType="floatType"
- android:duration="300"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/anim/car_arrow_fade_out.xml b/packages/CarSystemUI/res/anim/car_arrow_fade_out.xml
deleted file mode 100644
index e6757d2862b1..000000000000
--- a/packages/CarSystemUI/res/anim/car_arrow_fade_out.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together">
- <objectAnimator
- android:propertyName="alpha"
- android:valueFrom="1.0"
- android:valueTo="0.0"
- android:valueType="floatType"
- android:duration="300"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:propertyName="scaleX"
- android:valueFrom="1.0"
- android:valueTo="0.8"
- android:valueType="floatType"
- android:duration="300"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:propertyName="scaleY"
- android:valueFrom="1.0"
- android:valueTo="0.8"
- android:valueType="floatType"
- android:duration="300"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/anim/car_user_switcher_close_pod_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_close_pod_animation.xml
deleted file mode 100644
index 986a9cb06459..000000000000
--- a/packages/CarSystemUI/res/anim/car_user_switcher_close_pod_animation.xml
+++ /dev/null
@@ -1,24 +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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together" >
-
- <objectAnimator
- android:duration="50"
- android:propertyName="alpha"
- android:valueType="floatType"
- android:valueFrom="1"
- android:valueTo="0" />
-</set> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/anim/car_user_switcher_open_icon_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_open_icon_animation.xml
deleted file mode 100644
index 721376cae960..000000000000
--- a/packages/CarSystemUI/res/anim/car_user_switcher_open_icon_animation.xml
+++ /dev/null
@@ -1,24 +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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-
- <objectAnimator
- android:duration="167"
- android:propertyName="rotation"
- android:valueType="floatType"
- android:valueFrom="0"
- android:valueTo="180"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/anim/car_user_switcher_open_name_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_open_name_animation.xml
deleted file mode 100644
index 246099ef7b35..000000000000
--- a/packages/CarSystemUI/res/anim/car_user_switcher_open_name_animation.xml
+++ /dev/null
@@ -1,24 +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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-
- <objectAnimator
- android:duration="83"
- android:startOffset="83"
- android:propertyName="alpha"
- android:valueType="floatType"
- android:valueFrom="1"
- android:valueTo="0" />
-</set> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/anim/car_user_switcher_open_pages_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_open_pages_animation.xml
deleted file mode 100644
index 9a1c642363d0..000000000000
--- a/packages/CarSystemUI/res/anim/car_user_switcher_open_pages_animation.xml
+++ /dev/null
@@ -1,24 +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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-
- <objectAnimator
- android:duration="83"
- android:startOffset="83"
- android:propertyName="alpha"
- android:valueType="floatType"
- android:valueFrom="0"
- android:valueTo="1" />
-</set> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/anim/car_user_switcher_open_pod_animation.xml b/packages/CarSystemUI/res/anim/car_user_switcher_open_pod_animation.xml
deleted file mode 100644
index 1414b6688c8f..000000000000
--- a/packages/CarSystemUI/res/anim/car_user_switcher_open_pod_animation.xml
+++ /dev/null
@@ -1,33 +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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together" >
-
- <objectAnimator
- android:duration="167"
- android:startOffset="67"
- android:propertyName="translationY"
- android:valueType="floatType"
- android:valueFrom="@dimen/car_user_switcher_container_anim_height"
- android:valueTo="0"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="83"
- android:startOffset="117"
- android:propertyName="alpha"
- android:valueType="floatType"
- android:valueFrom="0"
- android:valueTo="1" />
-</set> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_add_white.xml b/packages/CarSystemUI/res/drawable/car_ic_add_white.xml
deleted file mode 100644
index 9d5ca264cdfa..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_add_white.xml
+++ /dev/null
@@ -1,23 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@*android:dimen/car_touch_target_size"
- android:height="@*android:dimen/car_touch_target_size"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="@color/car_user_switcher_add_user_add_sign_color"
- android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_apps.xml b/packages/CarSystemUI/res/drawable/car_ic_apps.xml
deleted file mode 100644
index e028a0ed45c9..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_apps.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="44"
- android:viewportHeight="44">
- <path
- android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml
deleted file mode 100644
index 9504e61e53e4..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="44"
- android:viewportHeight="44">
- <path
- android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
- android:fillColor="@color/car_nav_icon_fill_color_selected" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_arrow.xml b/packages/CarSystemUI/res/drawable/car_ic_arrow.xml
deleted file mode 100644
index cfacbf98354f..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_arrow.xml
+++ /dev/null
@@ -1,24 +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
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48.0dp"
- android:height="48.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
-</vector>
diff --git a/packages/CarSystemUI/res/drawable/car_ic_arrow_drop_up.xml b/packages/CarSystemUI/res/drawable/car_ic_arrow_drop_up.xml
deleted file mode 100644
index 81e7262c7cea..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_arrow_drop_up.xml
+++ /dev/null
@@ -1,24 +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
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48.0dp"
- android:height="48.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M14 28l10-10 10 10z"/>
-</vector>
diff --git a/packages/CarSystemUI/res/drawable/car_ic_hvac.xml b/packages/CarSystemUI/res/drawable/car_ic_hvac.xml
deleted file mode 100644
index 55c968eacc4d..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_hvac.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:pathData="M16.34,8.36l-2.29,0.82c-0.18,-0.13 -0.38,-0.25 -0.58,-0.34c0.17,-0.83 0.63,-1.58 1.36,-2.06C16.85,5.44 16.18,2 13.39,2C9,2 7.16,5.01 8.36,7.66l0.82,2.29c-0.13,0.18 -0.25,0.38 -0.34,0.58c-0.83,-0.17 -1.58,-0.63 -2.06,-1.36C5.44,7.15 2,7.82 2,10.61c0,4.4 3.01,6.24 5.66,5.03l2.29,-0.82c0.18,0.13 0.38,0.25 0.58,0.34c-0.17,0.83 -0.63,1.58 -1.36,2.06C7.15,18.56 7.82,22 10.61,22c4.4,0 6.24,-3.01 5.03,-5.66l-0.82,-2.29c0.13,-0.18 0.25,-0.38 0.34,-0.58c0.83,0.17 1.58,0.63 2.06,1.36c1.34,2.01 4.77,1.34 4.77,-1.45C22,9 18.99,7.16 16.34,8.36zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM10.24,5.22C10.74,4.44 11.89,4 13.39,4c0.79,0 0.71,0.86 0.34,1.11c-1.22,0.81 -2,2.06 -2.25,3.44c-0.21,0.03 -0.42,0.08 -0.62,0.15l-0.68,-1.88C10,6.42 9.86,5.81 10.24,5.22zM6.83,13.82c-0.4,0.18 -1.01,0.32 -1.61,-0.06C4.44,13.26 4,12.11 4,10.61c0,-0.79 0.86,-0.71 1.11,-0.34c0.81,1.22 2.06,2 3.44,2.25c0.03,0.21 0.08,0.42 0.15,0.62L6.83,13.82zM13.76,18.78c-0.5,0.77 -1.65,1.22 -3.15,1.22c-0.79,0 -0.71,-0.86 -0.34,-1.11c1.22,-0.81 2,-2.06 2.25,-3.44c0.21,-0.03 0.42,-0.08 0.62,-0.15l0.68,1.88C14,17.58 14.14,18.18 13.76,18.78zM18.89,13.73c-0.81,-1.22 -2.06,-2 -3.44,-2.25c-0.03,-0.21 -0.08,-0.42 -0.15,-0.62l1.88,-0.68c0.4,-0.18 1.01,-0.32 1.61,0.06c0.77,0.5 1.22,1.65 1.22,3.15C20,14.19 19.14,14.11 18.89,13.73z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector>
diff --git a/packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml
deleted file mode 100644
index 817b7148ecdd..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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.
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:pathData="M16.34,8.36l-2.29,0.82c-0.18,-0.13 -0.38,-0.25 -0.58,-0.34c0.17,-0.83 0.63,-1.58 1.36,-2.06C16.85,5.44 16.18,2 13.39,2C9,2 7.16,5.01 8.36,7.66l0.82,2.29c-0.13,0.18 -0.25,0.38 -0.34,0.58c-0.83,-0.17 -1.58,-0.63 -2.06,-1.36C5.44,7.15 2,7.82 2,10.61c0,4.4 3.01,6.24 5.66,5.03l2.29,-0.82c0.18,0.13 0.38,0.25 0.58,0.34c-0.17,0.83 -0.63,1.58 -1.36,2.06C7.15,18.56 7.82,22 10.61,22c4.4,0 6.24,-3.01 5.03,-5.66l-0.82,-2.29c0.13,-0.18 0.25,-0.38 0.34,-0.58c0.83,0.17 1.58,0.63 2.06,1.36c1.34,2.01 4.77,1.34 4.77,-1.45C22,9 18.99,7.16 16.34,8.36zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM10.24,5.22C10.74,4.44 11.89,4 13.39,4c0.79,0 0.71,0.86 0.34,1.11c-1.22,0.81 -2,2.06 -2.25,3.44c-0.21,0.03 -0.42,0.08 -0.62,0.15l-0.68,-1.88C10,6.42 9.86,5.81 10.24,5.22zM6.83,13.82c-0.4,0.18 -1.01,0.32 -1.61,-0.06C4.44,13.26 4,12.11 4,10.61c0,-0.79 0.86,-0.71 1.11,-0.34c0.81,1.22 2.06,2 3.44,2.25c0.03,0.21 0.08,0.42 0.15,0.62L6.83,13.82zM13.76,18.78c-0.5,0.77 -1.65,1.22 -3.15,1.22c-0.79,0 -0.71,-0.86 -0.34,-1.11c1.22,-0.81 2,-2.06 2.25,-3.44c0.21,-0.03 0.42,-0.08 0.62,-0.15l0.68,1.88C14,17.58 14.14,18.18 13.76,18.78zM18.89,13.73c-0.81,-1.22 -2.06,-2 -3.44,-2.25c-0.03,-0.21 -0.08,-0.42 -0.15,-0.62l1.88,-0.68c0.4,-0.18 1.01,-0.32 1.61,0.06c0.77,0.5 1.22,1.65 1.22,3.15C20,14.19 19.14,14.11 18.89,13.73z"
- android:fillColor="@color/car_nav_icon_fill_color_selected" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_keyboard_arrow_down.xml b/packages/CarSystemUI/res/drawable/car_ic_keyboard_arrow_down.xml
deleted file mode 100644
index 3709aa546766..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_keyboard_arrow_down.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~
- ~ Copyright (C) 2018 Google Inc.
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT 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="44dp"
- android:height="44dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:pathData="M14.83 16.42L24 25.59l9.17-9.17L36 19.25l-12 12-12-12z"
- android:fillColor="#ffffff"/>
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_music.xml b/packages/CarSystemUI/res/drawable/car_ic_music.xml
deleted file mode 100644
index 6339ebb3ea8d..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_music.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M22 5.5L22 24.8416667C20.9183333 24.2183333 19.6716667 23.8333333 18.3333333 23.8333333C14.2816667 23.8333333 11 27.115 11 31.1666667C11 35.2183333 14.2816667 38.5 18.3333333 38.5C22.385 38.5 25.6666667 35.2183333 25.6666667 31.1666667L25.6666667 12.8333333L33 12.8333333L33 5.5L22 5.5Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_music_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_music_selected.xml
deleted file mode 100644
index a56bcb38d883..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_music_selected.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M22 5.5L22 24.8416667C20.9183333 24.2183333 19.6716667 23.8333333 18.3333333 23.8333333C14.2816667 23.8333333 11 27.115 11 31.1666667C11 35.2183333 14.2816667 38.5 18.3333333 38.5C22.385 38.5 25.6666667 35.2183333 25.6666667 31.1666667L25.6666667 12.8333333L33 12.8333333L33 5.5L22 5.5Z"
- android:fillColor="@color/car_nav_icon_fill_color_selected" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_navigation.xml b/packages/CarSystemUI/res/drawable/car_ic_navigation.xml
deleted file mode 100644
index e1fabe07cdeb..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_navigation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M39.8016667 20.6983333L23.3016667 4.19833333C22.5866667 3.48333333 21.4316667 3.48333333 20.7166667 4.19833333L4.21666667 20.6983333C3.50166667 21.4133333 3.50166667 22.5683333 4.21666667 23.2833333L20.7166667 39.7833333C21.4316667 40.4983333 22.5866667 40.4983333 23.3016667 39.7833333L39.8016667 23.2833333C40.5166667 22.5866667 40.5166667 21.4316667 39.8016667 20.6983333ZM25.6666667 26.5833333L25.6666667 22L18.3333333 22L18.3333333 27.5L14.6666667 27.5L14.6666667 20.1666667C14.6666667 19.1583333 15.4916667 18.3333333 16.5 18.3333333L25.6666667 18.3333333L25.6666667 13.75L32.0833333 20.1666667L25.6666667 26.5833333Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_navigation_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_navigation_selected.xml
deleted file mode 100644
index d11cf28f6ca7..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_navigation_selected.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M39.8016667 20.6983333L23.3016667 4.19833333C22.5866667 3.48333333 21.4316667 3.48333333 20.7166667 4.19833333L4.21666667 20.6983333C3.50166667 21.4133333 3.50166667 22.5683333 4.21666667 23.2833333L20.7166667 39.7833333C21.4316667 40.4983333 22.5866667 40.4983333 23.3016667 39.7833333L39.8016667 23.2833333C40.5166667 22.5866667 40.5166667 21.4316667 39.8016667 20.6983333ZM25.6666667 26.5833333L25.6666667 22L18.3333333 22L18.3333333 27.5L14.6666667 27.5L14.6666667 20.1666667C14.6666667 19.1583333 15.4916667 18.3333333 16.5 18.3333333L25.6666667 18.3333333L25.6666667 13.75L32.0833333 20.1666667L25.6666667 26.5833333Z"
- android:fillColor="@color/car_nav_icon_fill_color_selected" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_notification.xml b/packages/CarSystemUI/res/drawable/car_ic_notification.xml
deleted file mode 100644
index aabf9161c11f..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_notification.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="44"
- android:viewportHeight="44">
- <path
- android:pathData="M22 39.125C23.925 39.125 25.5 37.55 25.5 35.625L18.5 35.625C18.5 37.55 20.0575 39.125 22 39.125ZM32.5 28.625L32.5 19.875C32.5 14.5025 29.63 10.005 24.625 8.815L24.625 7.625C24.625 6.1725 23.4525 5 22 5C20.5475 5 19.375 6.1725 19.375 7.625L19.375 8.815C14.3525 10.005 11.5 14.485 11.5 19.875L11.5 28.625L8 32.125L8 33.875L36 33.875L36 32.125L32.5 28.625Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_overview.xml b/packages/CarSystemUI/res/drawable/car_ic_overview.xml
deleted file mode 100644
index f185eb9afb75..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_overview.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M36.92857 22.39286A14.53571 14.53571 0 0 1 7.857143 22.39286A14.53571 14.53571 0 0 1 36.92857 22.39286Z"
- android:strokeColor="@color/car_nav_icon_fill_color"
- android:strokeWidth="4" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_overview_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_overview_selected.xml
deleted file mode 100644
index 19b558363720..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_overview_selected.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M36.92857 22.39286A14.53571 14.53571 0 0 1 7.857143 22.39286A14.53571 14.53571 0 0 1 36.92857 22.39286Z"
- android:strokeColor="@color/car_nav_icon_fill_color_selected"
- android:strokeWidth="4" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_phone.xml b/packages/CarSystemUI/res/drawable/car_ic_phone.xml
deleted file mode 100644
index 50e36b5a6e3c..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_phone.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M12.1366667 19.7816667C14.7766667 24.97 19.03 29.205 24.2183333 31.8633333L28.2516667 27.83C28.7466667 27.335 29.48 27.17 30.1216667 27.39C32.175 28.0683333 34.3933333 28.435 36.6666667 28.435C37.675 28.435 38.5 29.26 38.5 30.2683333L38.5 36.6666667C38.5 37.675 37.675 38.5 36.6666667 38.5C19.4516667 38.5 5.5 24.5483333 5.5 7.33333333C5.5 6.325 6.325 5.5 7.33333333 5.5L13.75 5.5C14.7583333 5.5 15.5833333 6.325 15.5833333 7.33333333C15.5833333 9.625 15.95 11.825 16.6283333 13.8783333C16.83 14.52 16.6833333 15.235 16.17 15.7483333L12.1366667 19.7816667Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_phone_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_phone_selected.xml
deleted file mode 100644
index 11b1687cf1c1..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_phone_selected.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M12.1366667 19.7816667C14.7766667 24.97 19.03 29.205 24.2183333 31.8633333L28.2516667 27.83C28.7466667 27.335 29.48 27.17 30.1216667 27.39C32.175 28.0683333 34.3933333 28.435 36.6666667 28.435C37.675 28.435 38.5 29.26 38.5 30.2683333L38.5 36.6666667C38.5 37.675 37.675 38.5 36.6666667 38.5C19.4516667 38.5 5.5 24.5483333 5.5 7.33333333C5.5 6.325 6.325 5.5 7.33333333 5.5L13.75 5.5C14.7583333 5.5 15.5833333 6.325 15.5833333 7.33333333C15.5833333 9.625 15.95 11.825 16.6283333 13.8783333C16.83 14.52 16.6833333 15.235 16.17 15.7483333L12.1366667 19.7816667Z"
- android:fillColor="@color/car_nav_icon_fill_color_selected" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_selection_bg.xml b/packages/CarSystemUI/res/drawable/car_ic_selection_bg.xml
deleted file mode 100644
index 12993f5b8b7c..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_selection_bg.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="70dp"
- android:height="70dp"
- android:viewportHeight="70.0"
- android:viewportWidth="70.0">
- <path
- android:fillColor="?android:attr/colorAccent"
- android:fillType="evenOdd"
- android:pathData="M4,0L66,0A4,4 0,0 1,70 4L70,66A4,4 0,0 1,66 70L4,70A4,4 0,0 1,0 66L0,4A4,4 0,0 1,4 0z"
- android:strokeColor="#00000000"
- android:strokeWidth="1"/>
-</vector>
diff --git a/packages/CarSystemUI/res/drawable/car_ic_settings_icon.xml b/packages/CarSystemUI/res/drawable/car_ic_settings_icon.xml
deleted file mode 100644
index 147f5397361e..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_settings_icon.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@*android:dimen/status_bar_system_icon_size"
- android:height="@*android:dimen/status_bar_system_icon_size"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="@color/system_bar_icon_color"
- android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4C9.75,2 9.54,2.18 9.51,2.42L9.13,5.07C8.52,5.32 7.96,5.66 7.44,6.05l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46C2.21,8.95 2.27,9.22 2.46,9.37l2.11,1.65C4.53,11.34 4.5,11.67 4.5,12s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65C9.54,21.82 9.75,22 10,22h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64L19.43,12.98zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5s3.5,1.57 3.5,3.5S13.93,15.5 12,15.5z"/>
-</vector>
diff --git a/packages/CarSystemUI/res/drawable/car_ic_unseen_indicator.xml b/packages/CarSystemUI/res/drawable/car_ic_unseen_indicator.xml
deleted file mode 100644
index 025fc9c4ea3b..000000000000
--- a/packages/CarSystemUI/res/drawable/car_ic_unseen_indicator.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <group
- android:translateX="30"
- android:translateY="2">
- <path
- android:fillColor="@color/car_nav_unseen_indicator_color"
- android:strokeWidth="1"
- android:pathData="M 6 0 C 9.31370849898 0 12 2.68629150102 12 6 C 12 9.31370849898 9.31370849898 12 6 12 C 2.68629150102 12 0 9.31370849898 0 6 C 0 2.68629150102 2.68629150102 0 6 0 Z" />
- </group>
-</vector>
diff --git a/packages/CarSystemUI/res/drawable/car_seekbar_thumb.xml b/packages/CarSystemUI/res/drawable/car_seekbar_thumb.xml
deleted file mode 100644
index 2649a005a971..000000000000
--- a/packages/CarSystemUI/res/drawable/car_seekbar_thumb.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item>
- <shape android:shape="oval">
- <padding
- android:bottom="@*android:dimen/car_padding_1"
- android:left="@*android:dimen/car_padding_1"
- android:right="@*android:dimen/car_padding_1"
- android:top="@*android:dimen/car_padding_1"/>
- <solid android:color="@android:color/black"/>
- </shape>
- </item>
- <item>
- <shape android:shape="oval">
- <solid android:color="@*android:color/car_accent"/>
- <size
- android:width="@*android:dimen/car_seekbar_thumb_size"
- android:height="@*android:dimen/car_seekbar_thumb_size"/>
- </shape>
- </item>
-</layer-list>
diff --git a/packages/CarSystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml b/packages/CarSystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml
deleted file mode 100644
index 34578fe252d4..000000000000
--- a/packages/CarSystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="18.0"
- android:viewportHeight="18.0">
- <group
- android:translateY="0.5"
- android:translateX="0.5" >
- <path
- android:pathData="M9.57,8.5l2.79,-2.78c0.3,-0.3 0.3,-0.8 0,-1.1L9.04,1.29L9.02,1.27C8.7,0.98 8.21,1 7.91,1.31C7.78,1.45 7.71,1.64 7.71,1.84v4.79L4.69,3.61c-0.3,-0.3 -0.79,-0.3 -1.09,0s-0.3,0.79 0,1.09L7.39,8.5L3.6,12.29c-0.3,0.3 -0.3,0.79 0,1.09s0.79,0.3 1.09,0l3.01,-3.01v4.8c0,0.42 0.35,0.77 0.77,0.77c0.19,0 0.39,-0.07 0.53,-0.21l0.04,-0.04l3.32,-3.32c0.3,-0.3 0.3,-0.8 0,-1.1L9.57,8.5zM9.19,6.77v-3.2l1.6,1.6L9.19,6.77zM9.19,13.42v-3.2l1.6,1.6L9.19,13.42zM4.03,9.29c-0.44,0.44 -1.15,0.44 -1.58,0C2.02,8.86 2.02,8.16 2.45,7.72l0.01,-0.01C2.89,7.27 3.59,7.27 4.02,7.7l0.01,0.01C4.47,8.15 4.47,8.85 4.03,9.29zM14.44,7.71c0.44,0.44 0.44,1.15 0,1.58c-0.44,0.44 -1.15,0.44 -1.58,0c-0.44,-0.43 -0.44,-1.13 -0.01,-1.57l0.01,-0.01C13.3,7.28 14,7.27 14.43,7.7C14.44,7.7 14.44,7.71 14.44,7.71z"
- android:fillColor="#FFFFFF"/>
- </group>
-</vector>
diff --git a/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml b/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml
deleted file mode 100644
index 656e94ae348b..000000000000
--- a/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?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"
- xmlns:aapt="http://schemas.android.com/aapt">
- <item android:gravity="center"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size">
- <aapt:attr name="android:drawable">
- <shape android:shape="oval">
- <size
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"/>
- <solid
- android:color="@color/hvac_temperature_adjust_button_color"/>
- </shape>
- </aapt:attr>
- </item>
- <item android:gravity="center"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size">
- <aapt:attr name="android:drawable">
- <vector android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="@color/hvac_temperature_decrease_arrow_color"
- android:pathData="M14,7l-5,5 5,5V7z"/>
- </vector>
- </aapt:attr>
- </item>
- <item>
- <aapt:attr name="android:drawable">
- <ripple android:color="?android:attr/colorControlHighlight"/>
- </aapt:attr>
- </item>
-</layer-list> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/hvac_increase_button.xml b/packages/CarSystemUI/res/drawable/hvac_increase_button.xml
deleted file mode 100644
index 57c07c873d76..000000000000
--- a/packages/CarSystemUI/res/drawable/hvac_increase_button.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?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"
- xmlns:aapt="http://schemas.android.com/aapt">
- <item android:gravity="center"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size">
- <aapt:attr name="android:drawable">
- <shape android:shape="oval">
- <size
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"/>
- <solid
- android:color="@color/hvac_temperature_adjust_button_color"/>
- </shape>
- </aapt:attr>
- </item>
- <item android:gravity="center"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size">
- <aapt:attr name="android:drawable">
- <vector android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="@color/hvac_temperature_increase_arrow_color"
- android:pathData="M10,17l5,-5 -5,-5v10z"/>
- </vector>
- </aapt:attr>
- </item>
- <item>
- <aapt:attr name="android:drawable">
- <ripple android:color="?android:attr/colorControlHighlight"/>
- </aapt:attr>
- </item>
-</layer-list> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/ic_mic_white.xml b/packages/CarSystemUI/res/drawable/ic_mic_white.xml
deleted file mode 100644
index 71fcc5302d75..000000000000
--- a/packages/CarSystemUI/res/drawable/ic_mic_white.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="44"
- android:viewportHeight="44">
-<path
- android:pathData="M22 25.6666667C25.0433333 25.6666667 27.4816667 23.21 27.4816667 20.1666667L27.5 9.16666667C27.5 6.12333333 25.0433333 3.66666667 22 3.66666667C18.9566667 3.66666667 16.5 6.12333333 16.5 9.16666667L16.5 20.1666667C16.5 23.21 18.9566667 25.6666667 22 25.6666667ZM31.7166667 20.1666667C31.7166667 25.6666667 27.06 29.5166667 22 29.5166667C16.94 29.5166667 12.2833333 25.6666667 12.2833333 20.1666667L9.16666667 20.1666667C9.16666667 26.4183333 14.1533333 31.5883333 20.1666667 32.4866667L20.1666667 38.5L23.8333333 38.5L23.8333333 32.4866667C29.8466667 31.6066667 34.8333333 26.4366667 34.8333333 20.1666667L31.7166667 20.1666667Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/notification_handle_bar.xml b/packages/CarSystemUI/res/drawable/notification_handle_bar.xml
deleted file mode 100644
index 5ed7499952ed..000000000000
--- a/packages/CarSystemUI/res/drawable/notification_handle_bar.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<ripple
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@android:color/white">
- <item>
- <shape android:shape="rectangle">
- <corners android:radius="@dimen/clear_all_button_radius"/>
- <solid android:color="@android:color/white"/>
- </shape>
- </item>
-</ripple> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/notification_material_bg.xml b/packages/CarSystemUI/res/drawable/notification_material_bg.xml
deleted file mode 100644
index 03746c8bfe4d..000000000000
--- a/packages/CarSystemUI/res/drawable/notification_material_bg.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/notification_ripple_untinted_color">
- <item>
- <shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/notification_material_background_color"/>
- <corners
- android:radius="@dimen/notification_shadow_radius"/>
- </shape>
- </item>
-</ripple>
diff --git a/packages/CarSystemUI/res/drawable/notification_material_bg_dim.xml b/packages/CarSystemUI/res/drawable/notification_material_bg_dim.xml
deleted file mode 100644
index 03746c8bfe4d..000000000000
--- a/packages/CarSystemUI/res/drawable/notification_material_bg_dim.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/notification_ripple_untinted_color">
- <item>
- <shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="@color/notification_material_background_color"/>
- <corners
- android:radius="@dimen/notification_shadow_radius"/>
- </shape>
- </item>
-</ripple>
diff --git a/packages/CarSystemUI/res/drawable/system_bar_background_pill.xml b/packages/CarSystemUI/res/drawable/system_bar_background_pill.xml
deleted file mode 100644
index 51d2b9d3e1e0..000000000000
--- a/packages/CarSystemUI/res/drawable/system_bar_background_pill.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?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"
- xmlns:aapt="http://schemas.android.com/aapt">
- <item>
- <aapt:attr name="android:drawable">
- <shape android:shape="rectangle">
- <solid android:color="@color/system_bar_background_pill_color"/>
- <corners android:radius="30dp"/>
- </shape>
- </aapt:attr>
- </item>
- <item>
- <aapt:attr name="android:drawable">
- <ripple android:color="?android:attr/colorControlHighlight"/>
- </aapt:attr>
- </item>
-</layer-list>
diff --git a/packages/CarSystemUI/res/drawable/volume_dialog_background.xml b/packages/CarSystemUI/res/drawable/volume_dialog_background.xml
deleted file mode 100644
index fa3ca8f27fc9..000000000000
--- a/packages/CarSystemUI/res/drawable/volume_dialog_background.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="?android:attr/colorBackgroundFloating"/>
- <padding
- android:bottom="5dp"
- android:left="5dp"
- android:right="5dp"
- android:top="5dp"/>
- <corners android:bottomLeftRadius="20dp"
- android:bottomRightRadius="20dp"/>
-</shape>
diff --git a/packages/CarSystemUI/res/layout/adjustable_temperature_view.xml b/packages/CarSystemUI/res/layout/adjustable_temperature_view.xml
deleted file mode 100644
index d19740932aa4..000000000000
--- a/packages/CarSystemUI/res/layout/adjustable_temperature_view.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?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.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center_vertical"
- android:paddingEnd="@dimen/hvac_container_padding"
- android:paddingStart="@dimen/hvac_container_padding">
-
- <ImageView
- android:id="@+id/hvac_decrease_button"
- android:layout_width="@dimen/hvac_temperature_button_size"
- android:layout_height="@dimen/hvac_temperature_button_size"
- android:scaleType="center"
- android:src="@drawable/hvac_decrease_button"/>
-
- <TextView
- android:id="@+id/hvac_temperature_text"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:textSize="@dimen/hvac_temperature_text_size"
- android:textColor="@color/system_bar_text_color"
- android:paddingStart="@dimen/hvac_temperature_text_padding"
- android:paddingEnd="@dimen/hvac_temperature_text_padding"
- android:gravity="center"/>
-
- <ImageView
- android:id="@+id/hvac_increase_button"
- android:layout_width="@dimen/hvac_temperature_button_size"
- android:layout_height="@dimen/hvac_temperature_button_size"
- android:scaleType="center"
- android:src="@drawable/hvac_increase_button" />
-</LinearLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/CarSystemUI/res/layout/car_fullscreen_user_pod.xml
deleted file mode 100644
index a2a628d7319e..000000000000
--- a/packages/CarSystemUI/res/layout/car_fullscreen_user_pod.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:clipChildren="false"
- android:alpha="0"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:gravity="center">
-
- <ImageView
- android:id="@+id/user_avatar"
- android:layout_width="@dimen/car_user_switcher_image_avatar_size"
- android:layout_height="@dimen/car_user_switcher_image_avatar_size"
- android:background="?android:attr/selectableItemBackground"
- android:gravity="center"/>
-
- <TextView
- android:id="@+id/user_name"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/car_user_switcher_vertical_spacing_between_name_and_avatar"
- android:textSize="@dimen/car_user_switcher_name_text_size"
- android:textColor="@color/car_user_switcher_name_text_color"
- android:ellipsize="end"
- android:singleLine="true"
- android:gravity="center"/>
-
-</LinearLayout>
diff --git a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
deleted file mode 100644
index 534c51e0febe..000000000000
--- a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<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:background="@color/car_user_switcher_background_color">
-
- <LinearLayout
- android:id="@+id/container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentTop="true"
- android:orientation="vertical">
-
- <include
- layout="@layout/car_status_bar_header"
- android:layout_alignParentTop="true"
- android:theme="@android:style/Theme"/>
-
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <com.android.systemui.car.userswitcher.UserGridRecyclerView
- android:id="@+id/user_grid"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginTop="@dimen/car_user_switcher_margin_top"/>
- </FrameLayout>
-
- </LinearLayout>
-</FrameLayout>
diff --git a/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
deleted file mode 100644
index 94816f81a4c5..000000000000
--- a/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:background="@drawable/system_bar_background">
-
- <LinearLayout
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:id="@+id/nav_buttons"
- android:orientation="vertical"
- android:gravity="top"
- android:paddingTop="30dp"
- android:layout_weight="1"
- android:animateLayoutChanges="true">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- android:src="@drawable/car_ic_overview"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="30dp"
- android:paddingBottom="30dp"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/grid"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- systemui:intent="intent:#Intent;component=com.android.car.home/.AppGridActivity;end"
- systemui:longIntent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- android:src="@drawable/car_ic_apps"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="30dp"
- android:paddingBottom="30dp"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvac"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- systemui:broadcast="true"
- android:src="@drawable/car_ic_hvac"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="30dp"
- android:paddingBottom="30dp"
- />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="bottom"
- android:orientation="vertical">
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/note"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:src="@drawable/car_ic_notification"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="20dp"
- android:paddingBottom="20dp"
- android:alpha="0.7"
- />
-
-
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:singleLine="true"
- android:paddingStart="@dimen/status_bar_clock_starting_padding"
- android:paddingEnd="@dimen/status_bar_clock_end_padding"
- android:gravity="center_horizontal"
- android:paddingBottom="20dp"
- />
-
- <Space
- android:layout_height="10dp"
- android:layout_width="match_parent"/>
-
- </LinearLayout>
-
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml
deleted file mode 100644
index 9e6dd113eeba..000000000000
--- a/packages/CarSystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:background="@drawable/system_bar_background">
-
- <LinearLayout
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:id="@+id/nav_buttons"
- android:orientation="vertical"
- android:gravity="top"
- android:paddingTop="30dp"
- android:layout_weight="1"
- android:animateLayoutChanges="true">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- android:src="@drawable/car_ic_overview"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="30dp"
- android:paddingBottom="30dp"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvac"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- systemui:broadcast="true"
- android:src="@drawable/car_ic_hvac"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="30dp"
- android:paddingBottom="30dp"
- />
- </LinearLayout>
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
deleted file mode 100644
index 8314ba5600a9..000000000000
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ /dev/null
@@ -1,122 +0,0 @@
-<?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.
- -->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/system_bar_background"
- android:gravity="center"
- android:orientation="horizontal">
-
- <RelativeLayout
- android:id="@+id/nav_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layoutDirection="ltr">
-
- <com.android.systemui.car.hvac.AdjustableTemperatureView
- android:id="@+id/driver_hvac"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- systemui:hvacAreaId="49"
- systemui:hvacTempFormat="%.0f\u00B0" />
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_centerInParent="true"
- android:layout_weight="1"
- android:gravity="center"
- android:layoutDirection="ltr"
- android:paddingEnd="@dimen/system_bar_button_group_padding"
- android:paddingStart="@dimen/system_bar_button_group_padding">
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:highlightWhenSelected="true"
- systemui:icon="@drawable/car_ic_home"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/phone_nav"
- style="@style/NavigationBarButton"
- systemui:highlightWhenSelected="true"
- systemui:icon="@drawable/car_ic_phone"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
- systemui:packages="com.android.car.dialer"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/grid_nav"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
- systemui:highlightWhenSelected="true"
- systemui:icon="@drawable/car_ic_apps"
- systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvac"
- style="@style/NavigationBarButton"
- systemui:highlightWhenSelected="true"
- systemui:icon="@drawable/car_ic_hvac"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- systemui:broadcast="true"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/notifications"
- style="@style/NavigationBarButton"
- systemui:highlightWhenSelected="true"
- systemui:icon="@drawable/car_ic_notification"
- systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"/>
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
- </LinearLayout>
-
- <com.android.systemui.car.hvac.AdjustableTemperatureView
- android:id="@+id/passenger_hvac"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentEnd="true"
- android:gravity="center_vertical"
- systemui:hvacAreaId="68"
- systemui:hvacTempFormat="%.0f\u00B0" />
- </RelativeLayout>
-
- <LinearLayout
- android:id="@+id/lock_screen_nav_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:layoutDirection="ltr"
- android:paddingEnd="@dimen/car_keyline_1"
- android:paddingStart="@dimen/car_keyline_1"
- android:visibility="gone"
- />
-</com.android.systemui.car.navigationbar.CarNavigationBarView> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml
deleted file mode 100644
index a040e800cbfc..000000000000
--- a/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/system_bar_background"
- android:orientation="vertical">
-
- <LinearLayout
- android:id="@+id/nav_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingStart="@*android:dimen/car_padding_5"
- android:paddingEnd="@*android:dimen/car_padding_5">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- android:layout_width="@*android:dimen/car_touch_target_size"
- android:layout_height="match_parent"
- android:background="?android:attr/selectableItemBackground"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_overview_selected"
- systemui:highlightWhenSelected="true"
- />
- </LinearLayout>
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
-
diff --git a/packages/CarSystemUI/res/layout/car_navigation_button.xml b/packages/CarSystemUI/res/layout/car_navigation_button.xml
deleted file mode 100644
index 9f79023b0f31..000000000000
--- a/packages/CarSystemUI/res/layout/car_navigation_button.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/car_nav_button_icon"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:animateLayoutChanges="true"
- android:orientation="vertical">
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/car_nav_button_icon_image"
- android:layout_height="@dimen/car_navigation_button_icon_height"
- android:layout_width="match_parent"
- android:layout_gravity="center"
- android:animateLayoutChanges="true"
- android:background="@android:color/transparent"
- android:scaleType="fitCenter"
- android:tintMode="src_in"
- android:tint="@color/car_nav_icon_fill_color_selected"
- android:clickable="false"
- />
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/car_nav_button_more_icon"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:layout_gravity="center"
- android:animateLayoutChanges="true"
- android:src="@drawable/car_ic_arrow"
- android:background="@android:color/transparent"
- android:scaleType="fitCenter"
- android:clickable="false"
- android:visibility="gone"
- />
-
- <ImageView
- android:id="@+id/car_nav_button_unseen_icon"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:layout_gravity="center"
- android:src="@drawable/car_ic_unseen_indicator"
- android:background="@android:color/transparent"
- android:scaleType="fitCenter"
- android:clickable="false"
- />
-
- </FrameLayout>
-</merge>
diff --git a/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
deleted file mode 100644
index dc9583382921..000000000000
--- a/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
+++ /dev/null
@@ -1,115 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:background="@drawable/system_bar_background">
-
- <!-- phone.NavigationBarView has rot0 and rot90 but we expect the car head unit to have a fixed
- rotation so skip this level of the hierarchy.
- -->
- <LinearLayout
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:id="@+id/nav_buttons"
- android:orientation="vertical"
- android:gravity="top"
- android:paddingTop="30dp"
- android:layout_weight="1"
- android:animateLayoutChanges="true">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- android:src="@drawable/car_ic_overview"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="30dp"
- android:paddingBottom="30dp"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/grid"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- systemui:intent="intent:#Intent;component=com.android.car.home/.AppGridActivity;launchFlags=0x14000000;end"
- systemui:longIntent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- android:src="@drawable/car_ic_apps"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="30dp"
- android:paddingBottom="30dp"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvac"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- systemui:broadcast="true"
- android:src="@drawable/car_ic_hvac"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="30dp"
- android:paddingBottom="30dp"
- />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="bottom"
- android:orientation="vertical">
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/note"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:src="@drawable/car_ic_notification"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="20dp"
- android:paddingBottom="20dp"
- android:alpha="0.7"
- />
-
-
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:singleLine="true"
- android:paddingStart="@dimen/status_bar_clock_starting_padding"
- android:paddingEnd="@dimen/status_bar_clock_end_padding"
- android:gravity="center_horizontal"
- android:paddingBottom="20dp"
- />
-
- <Space
- android:layout_height="10dp"
- android:layout_width="match_parent"/>
-
- </LinearLayout>
-
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml
deleted file mode 100644
index 9e6dd113eeba..000000000000
--- a/packages/CarSystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:background="@drawable/system_bar_background">
-
- <LinearLayout
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:id="@+id/nav_buttons"
- android:orientation="vertical"
- android:gravity="top"
- android:paddingTop="30dp"
- android:layout_weight="1"
- android:animateLayoutChanges="true">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- android:src="@drawable/car_ic_overview"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="30dp"
- android:paddingBottom="30dp"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvac"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- systemui:broadcast="true"
- android:src="@drawable/car_ic_hvac"
- android:background="?android:attr/selectableItemBackground"
- android:paddingTop="30dp"
- android:paddingBottom="30dp"
- />
- </LinearLayout>
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/res/layout/car_status_bar_header.xml b/packages/CarSystemUI/res/layout/car_status_bar_header.xml
deleted file mode 100644
index 12c9f11b3064..000000000000
--- a/packages/CarSystemUI/res/layout/car_status_bar_header.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<!-- Extends LinearLayout -->
-<com.android.systemui.car.userswitcher.CarStatusBarHeader
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/header"
- android:layout_width="match_parent"
- android:layout_height="@dimen/status_bar_height">
-
- <include layout="@layout/car_top_navigation_bar"
- android:id="@+id/qs_car_top_bar"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- />
-</com.android.systemui.car.userswitcher.CarStatusBarHeader>
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
deleted file mode 100644
index 7994b19242cd..000000000000
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ /dev/null
@@ -1,135 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:id="@+id/car_top_bar"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/system_bar_background"
- android:orientation="vertical">
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layoutDirection="ltr">
-
- <FrameLayout
- android:id="@+id/system_icon_area"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentStart="true"
- android:layout_marginTop="@dimen/car_padding_2"
- android:layout_marginStart="@dimen/car_padding_2"
- android:layout_centerVertical="true"
- android:gravity="center_vertical"
- >
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:background="@drawable/system_bar_background_pill"
- android:layout_weight="1"
- android:gravity="center_vertical"
- systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$QuickSettingActivity;launchFlags=0x24000000;end">
-
- <include
- layout="@layout/system_icons"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginStart="@dimen/car_padding_2"
- android:layout_marginEnd="@dimen/car_padding_2"
- android:gravity="center_vertical"
- />
- </com.android.systemui.car.navigationbar.CarNavigationButton>
- </FrameLayout>
-
- <FrameLayout
- android:id="@+id/clock_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_centerInParent="true"
- >
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/qs"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"
- systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$QuickSettingActivity;launchFlags=0x24000000;end"
- />
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:elevation="5dp"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.SystemBar.Clock"
- systemui:amPmStyle="normal"
- />
- </FrameLayout>
-
- <FrameLayout
- android:id="@+id/user_name_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentEnd="true"
- android:layout_centerVertical="true"
- android:layout_marginTop="@dimen/car_padding_2"
- >
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/user_name"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/car_padding_2"
- android:background="@drawable/system_bar_background_pill"
- android:gravity="center_vertical"
- systemui:intent="intent:#Intent;component=com.android.car.settings/.users.UserSwitcherActivity;launchFlags=0x24000000;end"
- >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:layout_marginStart="@dimen/car_padding_2"
- android:layout_marginEnd="@dimen/car_padding_2"
- android:gravity="center_vertical"
- >
- <ImageView
- android:id="@+id/user_avatar"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:src="@drawable/car_ic_user_icon"
- android:layout_marginEnd="@dimen/system_bar_user_icon_padding"
- />
- <TextView
- android:id="@+id/user_name_text"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:textAppearance="@style/TextAppearance.SystemBar.Username"
- android:maxLines="1"
- android:maxLength="10"
- android:layout_marginEnd="@dimen/system_bar_user_icon_padding"
- />
- </LinearLayout>
- </com.android.systemui.car.navigationbar.CarNavigationButton>
- </FrameLayout>
- </RelativeLayout>
-
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml
deleted file mode 100644
index b8ac2b43b047..000000000000
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml
+++ /dev/null
@@ -1,135 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:id="@+id/car_top_bar"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/system_bar_background"
- android:orientation="vertical">
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1">
-
- <FrameLayout
- android:id="@+id/left_hvac_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentStart="true"
- >
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvacleft"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"
- systemui:broadcast="true"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- />
-
- <com.android.systemui.car.hvac.AnimatedTemperatureView
- android:id="@+id/lefttext"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="@*android:dimen/car_padding_4"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:minEms="4"
- android:textAppearance="@style/TextAppearance.CarStatus"
- systemui:hvacAreaId="49"
- systemui:hvacPivotOffset="60dp"
- />
- </FrameLayout>
-
- <FrameLayout
- android:id="@+id/clock_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_centerInParent="true">
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/qs"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"/>
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:elevation="5dp"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"/>
- </FrameLayout>
-
- <LinearLayout
- android:id="@+id/system_icon_area"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_centerHorizontal="true"
- android:layout_centerVertical="true"
- android:layout_toEndOf="@+id/clock_container"
- android:paddingStart="@*android:dimen/car_padding_1"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- >
-
- <include
- layout="@layout/system_icons"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingStart="4dp"
- android:gravity="center_vertical"
- />
- </LinearLayout>
-
- <FrameLayout
- android:id="@+id/right_hvac_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentEnd="true"
- >
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvacright"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"
- systemui:broadcast="true"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- />
-
- <com.android.systemui.car.hvac.AnimatedTemperatureView
- android:id="@+id/righttext"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="16dp"
- android:paddingEnd="@*android:dimen/car_padding_4"
- android:gravity="center_vertical|end"
- android:minEms="4"
- android:textAppearance="@style/TextAppearance.CarStatus"
- systemui:hvacAreaId="68"
- systemui:hvacPivotOffset="60dp"
- />
- </FrameLayout>
- </RelativeLayout>
-
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/res/layout/car_user_switching_dialog.xml b/packages/CarSystemUI/res/layout/car_user_switching_dialog.xml
deleted file mode 100644
index 09fbf7a59a8c..000000000000
--- a/packages/CarSystemUI/res/layout/car_user_switching_dialog.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?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="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:background="@color/car_user_switching_dialog_background_color">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_gravity="center"
- android:gravity="center_horizontal">
- <ImageView
- android:id="@+id/user_loading_avatar"
- android:layout_width="@dimen/car_fullscreen_user_pod_image_avatar_width"
- android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height"/>
-
- <TextView
- android:id="@+id/user_loading"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/car_user_switching_dialog_loading_text_margin_top"
- android:textSize="@dimen/car_user_switching_dialog_loading_text_font_size"
- android:textColor="@color/car_user_switching_dialog_loading_text_color"
- android:layout_below="@id/user_loading_avatar"/>
- </LinearLayout>
-</FrameLayout>
diff --git a/packages/CarSystemUI/res/layout/car_volume_dialog.xml b/packages/CarSystemUI/res/layout/car_volume_dialog.xml
deleted file mode 100644
index 35551eabfaed..000000000000
--- a/packages/CarSystemUI/res/layout/car_volume_dialog.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<androidx.recyclerview.widget.RecyclerView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/volume_list"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minWidth="@dimen/volume_dialog_panel_width"/>
diff --git a/packages/CarSystemUI/res/layout/car_volume_item.xml b/packages/CarSystemUI/res/layout/car_volume_item.xml
deleted file mode 100644
index 0b429040fc86..000000000000
--- a/packages/CarSystemUI/res/layout/car_volume_item.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@color/car_volume_dialog_background_color"
- android:paddingStart="@dimen/car_volume_item_padding_start"
- android:paddingEnd="@dimen/car_volume_item_padding_end"
- android:minHeight="@dimen/car_volume_item_height">
-
- <!-- Primary Action. -->
- <ImageView
- android:id="@+id/primary_icon"
- android:layout_width="@dimen/car_volume_item_icon_size"
- android:layout_centerVertical="true"
- android:layout_alignParentStart="true"
- android:layout_height="@dimen/car_volume_item_icon_size"/>
-
- <!-- Note: the horizontal padding and offset are set to 0 so that the track and thumb
- aligns with the proper keylines. -->
- <SeekBar
- android:id="@+id/seek_bar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/car_volume_item_seekbar_margin_vertical"
- android:layout_marginTop="@dimen/car_volume_item_seekbar_margin_vertical"
- android:min="0"
- android:paddingBottom="@dimen/car_volume_item_seekbar_padding_vertical"
- android:layout_centerVertical="true"
- android:paddingEnd="0dp"
- android:paddingStart="0dp"
- android:paddingTop="@dimen/car_volume_item_seekbar_padding_vertical"
- android:splitTrack="false"
- android:layout_toStartOf="@id/supplemental_icon_divider"
- android:layout_marginStart="@dimen/car_volume_item_seekbar_margin_start"
- android:layout_marginEnd="@dimen/car_volume_item_seekbar_margin_end"
- android:thumbOffset="0dp"/>
-
- <!-- Supplemental action. -->
- <View
- android:id="@+id/supplemental_icon_divider"
- android:layout_width="@dimen/car_volume_item_divider_width"
- android:layout_height="@dimen/car_volume_item_divider_height"
- android:layout_marginEnd="@dimen/car_volume_item_divider_margin_end"
- android:layout_centerVertical="true"
- android:layout_toStartOf="@id/supplemental_icon"
- android:background="@color/car_volume_item_divider_color"/>
- <ImageView
- android:id="@+id/supplemental_icon"
- android:layout_width="@dimen/car_volume_item_icon_size"
- android:layout_height="@dimen/car_volume_item_icon_size"
- android:background="?android:attr/selectableItemBackground"
- android:layout_centerVertical="true"
- android:layout_alignParentEnd="true"
- android:scaleType="fitCenter"/>
-</RelativeLayout>
diff --git a/packages/CarSystemUI/res/layout/headsup_container_bottom.xml b/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
deleted file mode 100644
index 5aab0a172b99..000000000000
--- a/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?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.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/notification_headsup"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/gradient_edge"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- app:layout_constraintGuide_begin="@dimen/headsup_scrim_height"/>
-
- <!-- Include a FocusParkingView at the beginning. The rotary controller "parks" the focus here
- when the user navigates to another window. This is also used to prevent wrap-around. -->
- <com.android.car.ui.FocusParkingView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"/>
-
- <View
- android:id="@+id/scrim"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:background="@drawable/headsup_scrim_bottom"
- app:layout_constraintBottom_toBottomOf="@+id/gradient_edge"
- app:layout_constraintTop_toTopOf="parent"/>
-
- <FrameLayout
- android:id="@+id/headsup_content"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/headsup_notification_top_margin"
- app:layout_constraintEnd_toStartOf="parent"
- app:layout_constraintStart_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- />
-
-</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/notification_center_activity.xml b/packages/CarSystemUI/res/layout/notification_center_activity.xml
deleted file mode 100644
index 0e45e43132de..000000000000
--- a/packages/CarSystemUI/res/layout/notification_center_activity.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.car.notification.CarNotificationView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/notification_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/notification_shade_background_color">
-
- <com.android.car.ui.FocusParkingView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <View
- android:id="@+id/glass_pane"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:translationZ="2dp"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- />
-
- <com.android.car.ui.FocusArea
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:orientation="vertical"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent">
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/notifications"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/notification_shade_list_padding_bottom"/>
- </com.android.car.ui.FocusArea>
-
- <include layout="@layout/notification_handle_bar"/>
-
-</com.android.car.notification.CarNotificationView>
diff --git a/packages/CarSystemUI/res/layout/notification_handle_bar.xml b/packages/CarSystemUI/res/layout/notification_handle_bar.xml
deleted file mode 100644
index 99c3a02091db..000000000000
--- a/packages/CarSystemUI/res/layout/notification_handle_bar.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2019, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <View
- android:id="@+id/handle_bar"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_shade_handle_bar_height"
- android:layout_marginBottom="@dimen/notification_shade_handle_bar_margin_bottom"
- android:layout_marginEnd="@dimen/notification_shade_handle_bar_margin_start"
- android:layout_marginStart="@dimen/notification_shade_handle_bar_margin_end"
- android:layout_marginTop="@dimen/notification_shade_handle_bar_margin_top"
- android:background="@drawable/notification_handle_bar"/>
-</merge> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/notification_panel_container.xml b/packages/CarSystemUI/res/layout/notification_panel_container.xml
deleted file mode 100644
index 3b53c6aaeac3..000000000000
--- a/packages/CarSystemUI/res/layout/notification_panel_container.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?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:id="@+id/notification_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="invisible"/>
diff --git a/packages/CarSystemUI/res/layout/rear_view_camera.xml b/packages/CarSystemUI/res/layout/rear_view_camera.xml
deleted file mode 100644
index 9b9898cf3f45..000000000000
--- a/packages/CarSystemUI/res/layout/rear_view_camera.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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.
- -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/rear_view_camera_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/transparent"
- android:orientation="vertical">
- <Button
- android:id="@+id/close_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@color/rear_view_camera_button_background"
- android:text="@string/rear_view_camera_close_button_text"
- android:textAppearance="?android:attr/textAppearanceLarge"/>
-</LinearLayout>
diff --git a/packages/CarSystemUI/res/layout/status_bar_wifi_group.xml b/packages/CarSystemUI/res/layout/status_bar_wifi_group.xml
deleted file mode 100644
index 531e57780817..000000000000
--- a/packages/CarSystemUI/res/layout/status_bar_wifi_group.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<com.android.systemui.statusbar.StatusBarWifiView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:id="@+id/wifi_combo"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical">
-
- <com.android.keyguard.AlphaOptimizedLinearLayout
- android:id="@+id/wifi_group"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="2dp"
- android:gravity="center_vertical"
- >
- <FrameLayout
- android:id="@+id/inout_container"
- android:layout_width="wrap_content"
- android:layout_height="17dp"
- android:gravity="center_vertical">
- <ImageView
- android:id="@+id/wifi_in"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingEnd="2dp"
- android:src="@drawable/ic_activity_down"
- android:visibility="gone"
- />
- <ImageView
- android:id="@+id/wifi_out"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingEnd="2dp"
- android:src="@drawable/ic_activity_up"
- android:visibility="gone"
- />
- </FrameLayout>
- <FrameLayout
- android:id="@+id/wifi_combo"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center_vertical">
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/wifi_signal"
- android:layout_width="@*android:dimen/status_bar_system_icon_size"
- android:layout_height="@*android:dimen/status_bar_system_icon_size"
- android:theme="?attr/lightIconTheme"/>
- </FrameLayout>
-
- <View
- android:id="@+id/wifi_signal_spacer"
- android:layout_width="@dimen/status_bar_wifi_signal_spacer_width"
- android:layout_height="4dp"
- android:visibility="gone"/>
-
- <ViewStub
- android:id="@+id/connected_device_signals_stub"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout="@layout/connected_device_signal"/>
-
- <View
- android:id="@+id/wifi_airplane_spacer"
- android:layout_width="@dimen/status_bar_airplane_spacer_width"
- android:layout_height="4dp"
- android:visibility="gone"
- />
- </com.android.keyguard.AlphaOptimizedLinearLayout>
-</com.android.systemui.statusbar.StatusBarWifiView>
diff --git a/packages/CarSystemUI/res/layout/system_icons.xml b/packages/CarSystemUI/res/layout/system_icons.xml
deleted file mode 100644
index f6ffcc8c16f0..000000000000
--- a/packages/CarSystemUI/res/layout/system_icons.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/system_icons"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:orientation="horizontal">
-
- <com.android.systemui.statusbar.phone.StatusIconContainer
- android:id="@+id/statusIcons"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:scaleType="fitCenter"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- />
-
- <ImageView
- android:id="@+id/settingsIcon"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="@dimen/car_padding_2"
- android:src="@drawable/car_ic_settings_icon"
- />
-</LinearLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
deleted file mode 100644
index 980265e84e54..000000000000
--- a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?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/notification_panel_stub"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout="@layout/notification_panel_container"/>
-
- <ViewStub android:id="@+id/keyguard_stub"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout="@layout/keyguard_container" />
-
- <ViewStub android:id="@+id/fullscreen_user_switcher_stub"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout="@layout/car_fullscreen_user_switcher"/>
-
- <ViewStub android:id="@+id/user_switching_dialog_stub"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout="@layout/car_user_switching_dialog"/>
-
- <!-- Should be at bottom to get the highest Z-order. -->
- <ViewStub android:id="@+id/rear_view_camera_stub"
- android:layout_width="@dimen/rear_view_camera_width"
- android:layout_height="@dimen/rear_view_camera_height"
- android:layout_gravity="center"
- android:layout="@layout/rear_view_camera"/>
-</FrameLayout>
diff --git a/packages/CarSystemUI/res/values-af/strings.xml b/packages/CarSystemUI/res/values-af/strings.xml
deleted file mode 100644
index cf288d74d61c..000000000000
--- a/packages/CarSystemUI/res/values-af/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Stemherkenning nou deur gekoppelde Bluetooth-toestel hanteer"</string>
- <string name="car_guest" msgid="318393171202663722">"Gas"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gas"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Voeg gebruiker by"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Nuwe gebruiker"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Wanneer jy \'n nuwe gebruiker byvoeg, moet daardie persoon hul spasie opstel."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Enige gebruiker kan programme vir al die ander gebruikers opdateer."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Laai tans"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Laai tans gebruiker (van <xliff:g id="FROM_USER">%1$d</xliff:g> na <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Maak toe"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-af/strings_car.xml b/packages/CarSystemUI/res/values-af/strings_car.xml
deleted file mode 100644
index a6b609396009..000000000000
--- a/packages/CarSystemUI/res/values-af/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gas"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gas"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Voeg gebruiker by"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Nuwe gebruiker"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Wanneer jy \'n nuwe gebruiker byvoeg, moet daardie persoon hul spasie opstel."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Enige gebruiker kan programme vir al die ander gebruikers opdateer."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-am/strings.xml b/packages/CarSystemUI/res/values-am/strings.xml
deleted file mode 100644
index 8281631312b7..000000000000
--- a/packages/CarSystemUI/res/values-am/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"ዝቅተኛ"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"ከፍተኛ"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"የድምፅ ለይቶ ማወቅ አሁን በተገናኘ የብሉቱዝ መሣሪያ ይስተናገዳል"</string>
- <string name="car_guest" msgid="318393171202663722">"እንግዳ"</string>
- <string name="start_guest_session" msgid="497784785761754874">"እንግዳ"</string>
- <string name="car_add_user" msgid="4067337059622483269">"ተጠቃሚ አክል"</string>
- <string name="car_new_user" msgid="6637442369728092473">"አዲስ ተጠቃሚ"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"አዲስ ተጠቃሚ ሲያክሉ ያ ሰው የራሳቸውን ቦታ ማቀናበር አለባቸው።"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"ማንኛውም ተጠቃሚ መተግበሪያዎችን ለሌሎች ተጠቃሚዎች ሁሉ ማዘመን ይችላል።"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"በመጫን ላይ"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ተጠቃሚን (ከ<xliff:g id="FROM_USER">%1$d</xliff:g> ወደ <xliff:g id="TO_USER">%2$d</xliff:g>) በመጫን ላይ"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"ዝጋ"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-am/strings_car.xml b/packages/CarSystemUI/res/values-am/strings_car.xml
deleted file mode 100644
index 7f5895ad8fc5..000000000000
--- a/packages/CarSystemUI/res/values-am/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"እንግዳ"</string>
- <string name="start_guest_session" msgid="548879769864070364">"እንግዳ"</string>
- <string name="car_add_user" msgid="9196649698797257695">"ተጠቃሚ አክል"</string>
- <string name="car_new_user" msgid="2994965724661108420">"አዲስ ተጠቃሚ"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"አዲስ ተጠቃሚ ሲያክሉ ያ ሰው የራሳቸውን ቦታ ማቀናበር አለባቸው።"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"ማንኛውም ተጠቃሚ መተግበሪያዎችን ለሌሎች ተጠቃሚዎች ሁሉ ማዘመን ይችላል።"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ar/strings.xml b/packages/CarSystemUI/res/values-ar/strings.xml
deleted file mode 100644
index d9abb0af5608..000000000000
--- a/packages/CarSystemUI/res/values-ar/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"حد أدنى"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"حد أقصى"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"تتم معالجة التعرّف على الصوت الآن من خلال جهاز بلوتوث متصل."</string>
- <string name="car_guest" msgid="318393171202663722">"ضيف"</string>
- <string name="start_guest_session" msgid="497784785761754874">"ضيف"</string>
- <string name="car_add_user" msgid="4067337059622483269">"إضافة مستخدم"</string>
- <string name="car_new_user" msgid="6637442369728092473">"مستخدم جديد"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"عند إضافة مستخدم جديد، على هذا المستخدم إعداد مساحته."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"يمكن لأي مستخدم تحديث التطبيقات لجميع المستخدمين الآخرين."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"جارٍ التحميل"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"جارٍ تحميل الملف الشخصي الجديد للمستخدم (من <xliff:g id="FROM_USER">%1$d</xliff:g> إلى <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"إغلاق"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-as/strings.xml b/packages/CarSystemUI/res/values-as/strings.xml
deleted file mode 100644
index d8710555149b..000000000000
--- a/packages/CarSystemUI/res/values-as/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"সর্বনিম্ন"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"সৰ্বাধিক"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"কণ্ঠস্বৰৰ চিনাক্তকৰণ এতিয়া সংযুক্ত ব্লুটুথ ডিভাইচে নিয়ন্ত্ৰণ কৰে"</string>
- <string name="car_guest" msgid="318393171202663722">"অতিথি"</string>
- <string name="start_guest_session" msgid="497784785761754874">"অতিথি"</string>
- <string name="car_add_user" msgid="4067337059622483269">"ব্যৱহাৰকাৰী যোগ দিয়ক"</string>
- <string name="car_new_user" msgid="6637442369728092473">"নতুন ব্যৱহাৰকাৰী"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"আপুনি যেতিয়া এজন নতুন ব্যৱহাৰকাৰীক যোগ কৰে, তেতিয়া তেওঁ নিজৰ ঠাই ছেট আপ কৰাটো প্ৰয়োজন হয়।"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"যিকোনো ব্যৱহাৰকাৰীয়ে অন্য ব্যৱহাৰকাৰীৰ বাবে এপ্‌সমূহ আপডে’ট কৰিব পাৰে।"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"ল’ড হৈ আছে"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ব্যৱহাৰকাৰী ল’ড হৈ আছে (<xliff:g id="FROM_USER">%1$d</xliff:g>ৰ পৰা to <xliff:g id="TO_USER">%2$d</xliff:g>লৈ)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"বন্ধ কৰক"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-as/strings_car.xml b/packages/CarSystemUI/res/values-as/strings_car.xml
deleted file mode 100644
index 6eabbd45d06d..000000000000
--- a/packages/CarSystemUI/res/values-as/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"অতিথি"</string>
- <string name="start_guest_session" msgid="548879769864070364">"অতিথি"</string>
- <string name="car_add_user" msgid="9196649698797257695">"ব্যৱহাৰকাৰী যোগ কৰক"</string>
- <string name="car_new_user" msgid="2994965724661108420">"নতুন ব্যৱহাৰকাৰী"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"আপুনি যেতিয়া এজন নতুন ব্যৱহাৰকাৰীক যোগ কৰে, তেতিয়া তেওঁ নিজৰ ঠাই ছেট আপ কৰাটো প্ৰয়োজন হয়।"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"অন্য সকলো ব্যৱহাৰকাৰীৰ বাবে যিকোনো এজন ব্যৱহাৰকাৰীয়ে এপ্‌সমূহ আপডে\'ট কৰিব পাৰে।"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-az/strings.xml b/packages/CarSystemUI/res/values-az/strings.xml
deleted file mode 100644
index 89c9eb4ee258..000000000000
--- a/packages/CarSystemUI/res/values-az/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Səs tanınması qoşulmuş Bluetooth cihazı ilə icra edilir"</string>
- <string name="car_guest" msgid="318393171202663722">"Qonaq"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Qonaq"</string>
- <string name="car_add_user" msgid="4067337059622483269">"İstifadəçi əlavə edin"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Yeni İstifadəçi"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Yeni istifadəçi əlavə etdiyinizdə həmin şəxs öz yerini təyin etməlidir."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"İstənilən istifadəçi digər bütün istifadəçilər üçün tətbiqləri güncəlləyə bilər."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Yüklənir"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"İstifadəçi yüklənir (<xliff:g id="FROM_USER">%1$d</xliff:g>-<xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Qapadın"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-az/strings_car.xml b/packages/CarSystemUI/res/values-az/strings_car.xml
deleted file mode 100644
index aeee105dd1c9..000000000000
--- a/packages/CarSystemUI/res/values-az/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Qonaq"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Qonaq"</string>
- <string name="car_add_user" msgid="9196649698797257695">"İstifadəçi əlavə edin"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Yeni istifadəçi"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Yeni istifadəçi əlavə etdiyinizdə həmin şəxs öz yerini təyin etməlidir."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"İstənilən istifadəçi digər bütün istifadəçilər üçün tətbiqləri güncəlləyə bilər."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-b+sr+Latn/strings.xml b/packages/CarSystemUI/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index 6aee01321ade..000000000000
--- a/packages/CarSystemUI/res/values-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Prepoznavanjem glasa sada upravlja povezani Bluetooth uređaj"</string>
- <string name="car_guest" msgid="318393171202663722">"Gost"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gost"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Dodaj korisnika"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Novi korisnik"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kada dodate novog korisnika, ta osoba treba da podesi svoj prostor."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Svaki korisnik može da ažurira aplikacije za sve ostale korisnike."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Učitava se"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Profil korisnika se učitava (iz<xliff:g id="FROM_USER">%1$d</xliff:g> u <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Zatvori"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-b+sr+Latn/strings_car.xml b/packages/CarSystemUI/res/values-b+sr+Latn/strings_car.xml
deleted file mode 100644
index f3b53a542979..000000000000
--- a/packages/CarSystemUI/res/values-b+sr+Latn/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gost"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gost"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Dodaj korisnika"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Novi korisnik"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Kada dodate novog korisnika, ta osoba treba da podesi svoj prostor."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Svaki korisnik može da ažurira aplikacije za sve ostale korisnike."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-be/strings.xml b/packages/CarSystemUI/res/values-be/strings.xml
deleted file mode 100644
index fde42732283f..000000000000
--- a/packages/CarSystemUI/res/values-be/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Мін"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Макс"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Распазнаванне голасу выконвае падключаная прылада Bluetooth"</string>
- <string name="car_guest" msgid="318393171202663722">"Госць"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Госць"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Дадаць карыстальніка"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Новы карыстальнік"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Калі вы дадаяце новага карыстальніка, яму трэба наладзіць свой профіль."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Кожны карыстальнік прылады можа абнаўляць праграмы для ўсіх іншых карыстальнікаў."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Ідзе загрузка"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Ідзе загрузка профілю карыстальніка (ад <xliff:g id="FROM_USER">%1$d</xliff:g> да <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Закрыць"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-be/strings_car.xml b/packages/CarSystemUI/res/values-be/strings_car.xml
deleted file mode 100644
index 1215af2a82a1..000000000000
--- a/packages/CarSystemUI/res/values-be/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Госць"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Госць"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Дадаць карыстальніка"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Новы карыстальнік"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Калі вы дадаяце новага карыстальніка, яму трэба наладзіць свой профіль."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Кожны карыстальнік прылады можа абнаўляць праграмы для ўсіх іншых карыстальнікаў."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-bg/strings.xml b/packages/CarSystemUI/res/values-bg/strings.xml
deleted file mode 100644
index 25f284515b9f..000000000000
--- a/packages/CarSystemUI/res/values-bg/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Гл. разпознаване се обработва от свързаното у-во с Bluetooth"</string>
- <string name="car_guest" msgid="318393171202663722">"Гост"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Гост"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Добавяне на потребител"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Нов потребител"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Когато добавите нов потребител, той трябва да настрои работната си област."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Всеки потребител може да актуализира приложенията за всички останали потребители."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Зарежда се"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Потребителят се зарежда (от <xliff:g id="FROM_USER">%1$d</xliff:g> до <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Затваряне"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-bg/strings_car.xml b/packages/CarSystemUI/res/values-bg/strings_car.xml
deleted file mode 100644
index d95b18ef7289..000000000000
--- a/packages/CarSystemUI/res/values-bg/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Гост"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Гост"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Добавяне на потребител"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Нов потребител"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Когато добавите нов потребител, той трябва да настрои работното си пространство."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Всеки потребител може да актуализира приложенията за всички останали потребители."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-bn/strings.xml b/packages/CarSystemUI/res/values-bn/strings.xml
deleted file mode 100644
index 5664cc12e109..000000000000
--- a/packages/CarSystemUI/res/values-bn/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"সর্বনিম্ন"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"সর্বাধিক"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"কানেক্ট করা ব্লুটুথ ডিভাইস এখন ভয়েস শনাক্তকরণ ম্যানেজ করছে"</string>
- <string name="car_guest" msgid="318393171202663722">"অতিথি"</string>
- <string name="start_guest_session" msgid="497784785761754874">"অতিথি"</string>
- <string name="car_add_user" msgid="4067337059622483269">"ব্যবহারকারীকে যোগ করুন"</string>
- <string name="car_new_user" msgid="6637442369728092473">"নতুন ব্যবহারকারী"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"নতুন ব্যবহারকারী যোগ করলে, তার স্পেস তাকে সেট-আপ করে নিতে হবে।"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"যেকোনও ব্যবহারকারী বাকি সব ব্যবহারকারীর জন্য অ্যাপ আপডেট করতে পারবেন।"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"লোড হচ্ছে"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ব্যবহারকারীর প্রোফাইল লোড করা হচ্ছে (<xliff:g id="FROM_USER">%1$d</xliff:g> থেকে <xliff:g id="TO_USER">%2$d</xliff:g>-এ)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"বন্ধ করুন"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-bn/strings_car.xml b/packages/CarSystemUI/res/values-bn/strings_car.xml
deleted file mode 100644
index f44ba6e027c1..000000000000
--- a/packages/CarSystemUI/res/values-bn/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"অতিথি"</string>
- <string name="start_guest_session" msgid="548879769864070364">"অতিথি সেশন শুরু করুন"</string>
- <string name="car_add_user" msgid="9196649698797257695">"ব্যবহারকারী যোগ করুন"</string>
- <string name="car_new_user" msgid="2994965724661108420">"নতুন ব্যবহারকারী"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"নতুন ব্যবহারকারী যোগ করলে, তার স্পেস তাকে সেট-আপ করে নিতে হবে।"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"যেকোনও ব্যবহারকারী বাকি সব ব্যবহারকারীর জন্য অ্যাপ আপডেট করতে পারবেন।"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-bs/strings.xml b/packages/CarSystemUI/res/values-bs/strings.xml
deleted file mode 100644
index 588771e41740..000000000000
--- a/packages/CarSystemUI/res/values-bs/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Prepoznavanjem glasa sada upravlja povezani Bluetooth uređaj"</string>
- <string name="car_guest" msgid="318393171202663722">"Gost"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gost"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Dodaj korisnika"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Novi korisnik"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kada dodate novog korisnika, ta osoba treba postaviti svoj prostor."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Bilo koji korisnik može ažurirati aplikacije za sve druge korisnike."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Učitavanje"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Učitavanje korisnika (od korisnika <xliff:g id="FROM_USER">%1$d</xliff:g> do korisnika <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Zatvori"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-bs/strings_car.xml b/packages/CarSystemUI/res/values-bs/strings_car.xml
deleted file mode 100644
index e56f861483ae..000000000000
--- a/packages/CarSystemUI/res/values-bs/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gost"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gost"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Dodaj korisnika"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Novi korisnik"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Kada dodate novog korisnika, ta osoba treba postaviti svoj prostor."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Svaki korisnik može ažurirati aplikacije za sve druge korisnike."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ca/strings.xml b/packages/CarSystemUI/res/values-ca/strings.xml
deleted file mode 100644
index cbd469b68a62..000000000000
--- a/packages/CarSystemUI/res/values-ca/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Mín."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Màx."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Reconeixement de veu gestionat per disp. Bluetooth connectat"</string>
- <string name="car_guest" msgid="318393171202663722">"Convidat"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Convidat"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Afegeix un usuari"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Usuari nou"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Quan s\'afegeix un usuari nou, aquest usuari ha de configurar el seu espai."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Qualsevol usuari pot actualitzar les aplicacions de la resta d\'usuaris."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"S\'està carregant"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"S\'està carregant l\'usuari (de <xliff:g id="FROM_USER">%1$d</xliff:g> a <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Tanca"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ca/strings_car.xml b/packages/CarSystemUI/res/values-ca/strings_car.xml
deleted file mode 100644
index 89725a2ee93a..000000000000
--- a/packages/CarSystemUI/res/values-ca/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Convidat"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Convidat"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Afegeix un usuari"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Usuari nou"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Quan s\'afegeix un usuari nou, aquest usuari ha de configurar el seu espai."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Qualsevol usuari pot actualitzar les aplicacions de la resta d\'usuaris."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-cs/strings.xml b/packages/CarSystemUI/res/values-cs/strings.xml
deleted file mode 100644
index 7657e32b0223..000000000000
--- a/packages/CarSystemUI/res/values-cs/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Rozpoznávání hlasu teď provádí připojené zařízení Bluetooth"</string>
- <string name="car_guest" msgid="318393171202663722">"Host"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Host"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Přidat uživatele"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Nový uživatel"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Každý nově přidaný uživatel si musí nastavit vlastní prostor."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Každý uživatel může aktualizovat aplikace všech ostatních uživatelů."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Načítání"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Načítání uživatele (předchozí: <xliff:g id="FROM_USER">%1$d</xliff:g>, následující: <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Zavřít"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-cs/strings_car.xml b/packages/CarSystemUI/res/values-cs/strings_car.xml
deleted file mode 100644
index 1043950077ed..000000000000
--- a/packages/CarSystemUI/res/values-cs/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Host"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Host"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Přidat uživatele"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Nový uživatel"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Každý nově přidaný uživatel si musí nastavit vlastní prostor."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Každý uživatel může aktualizovat aplikace všech ostatních uživatelů."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-da/strings.xml b/packages/CarSystemUI/res/values-da/strings.xml
deleted file mode 100644
index 120929e34347..000000000000
--- a/packages/CarSystemUI/res/values-da/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Talegenkendelse sker nu med den forbundne Blutetooth-enhed"</string>
- <string name="car_guest" msgid="318393171202663722">"Gæst"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gæst"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Tilføj bruger"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Ny bruger"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Når du tilføjer en ny bruger, skal vedkommende konfigurere sit område."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Alle brugere kan opdatere apps for alle andre brugere."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Indlæser"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Indlæser bruger (fra <xliff:g id="FROM_USER">%1$d</xliff:g> til <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Luk"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-da/strings_car.xml b/packages/CarSystemUI/res/values-da/strings_car.xml
deleted file mode 100644
index 7a63ec1a8351..000000000000
--- a/packages/CarSystemUI/res/values-da/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gæst"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gæst"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Tilføj bruger"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Ny bruger"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Når du tilføjer en ny bruger, skal vedkommende konfigurere sit område."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Alle brugere kan opdatere apps for alle andre brugere."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-de/strings.xml b/packages/CarSystemUI/res/values-de/strings.xml
deleted file mode 100644
index e2437f0c55cb..000000000000
--- a/packages/CarSystemUI/res/values-de/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Spracherkennung jetzt über das verbundene Bluetooth-Gerät"</string>
- <string name="car_guest" msgid="318393171202663722">"Gast"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gast"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Nutzer hinzufügen"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Neuer Nutzer"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Wenn du einen neuen Nutzer hinzufügst, muss dieser seinen Bereich einrichten."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Jeder Nutzer kann Apps für alle anderen Nutzer aktualisieren."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Wird geladen"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Nutzer wird geladen (von <xliff:g id="FROM_USER">%1$d</xliff:g> bis <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Schließen"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-de/strings_car.xml b/packages/CarSystemUI/res/values-de/strings_car.xml
deleted file mode 100644
index c1acc65ed663..000000000000
--- a/packages/CarSystemUI/res/values-de/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gast"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gast"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Nutzer hinzufügen"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Neuer Nutzer"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Wenn du einen neuen Nutzer hinzufügst, muss dieser seinen Bereich einrichten."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Jeder Nutzer kann Apps für alle anderen Nutzer aktualisieren."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-el/strings.xml b/packages/CarSystemUI/res/values-el/strings.xml
deleted file mode 100644
index 9b24fa488923..000000000000
--- a/packages/CarSystemUI/res/values-el/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Ελάχ."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Μεγ."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Φωνητική αναγνωση από συνδεδεμένη συσκευή Bluetooth"</string>
- <string name="car_guest" msgid="318393171202663722">"Επισκέπτης"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Επισκέπτης"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Προσθήκη χρήστη"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Νέος χρήστης"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Κατά την προσθήκη ενός νέου χρήστη, αυτός θα πρέπει να ρυθμίσει τον χώρο του."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Οποιοσδήποτε χρήστης μπορεί να ενημερώσει τις εφαρμογές για όλους τους άλλους χρήστες."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Φόρτωση"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Φόρτωση χρήστη (από <xliff:g id="FROM_USER">%1$d</xliff:g> έως <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Κλείσιμο"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-el/strings_car.xml b/packages/CarSystemUI/res/values-el/strings_car.xml
deleted file mode 100644
index 48c5c3e58b8a..000000000000
--- a/packages/CarSystemUI/res/values-el/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Επισκέπτης"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Επισκέπτης"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Προσθήκη χρήστη"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Νέος χρήστης"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Κατά την προσθήκη ενός νέου χρήστη, αυτός θα πρέπει να ρυθμίσει τον χώρο του."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Οποιοσδήποτε χρήστης μπορεί να ενημερώσει τις εφαρμογές για όλους τους άλλους χρήστες."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rAU/strings.xml b/packages/CarSystemUI/res/values-en-rAU/strings.xml
deleted file mode 100644
index 8eb76c20d8a2..000000000000
--- a/packages/CarSystemUI/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Voice recognition now handled by connected Bluetooth device"</string>
- <string name="car_guest" msgid="318393171202663722">"Guest"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Guest"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Add user"</string>
- <string name="car_new_user" msgid="6637442369728092473">"New user"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"When you add a new user, that person needs to set up their space."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Any user can update apps for all other users."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Loading"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Loading user (from <xliff:g id="FROM_USER">%1$d</xliff:g> to <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Close"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rAU/strings_car.xml b/packages/CarSystemUI/res/values-en-rAU/strings_car.xml
deleted file mode 100644
index 55dc48c50bb5..000000000000
--- a/packages/CarSystemUI/res/values-en-rAU/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Guest"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Guest"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Add user"</string>
- <string name="car_new_user" msgid="2994965724661108420">"New user"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"When you add a new user, that person needs to set up their space."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Any user can update apps for all other users."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rCA/strings.xml b/packages/CarSystemUI/res/values-en-rCA/strings.xml
deleted file mode 100644
index 8eb76c20d8a2..000000000000
--- a/packages/CarSystemUI/res/values-en-rCA/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Voice recognition now handled by connected Bluetooth device"</string>
- <string name="car_guest" msgid="318393171202663722">"Guest"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Guest"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Add user"</string>
- <string name="car_new_user" msgid="6637442369728092473">"New user"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"When you add a new user, that person needs to set up their space."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Any user can update apps for all other users."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Loading"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Loading user (from <xliff:g id="FROM_USER">%1$d</xliff:g> to <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Close"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rCA/strings_car.xml b/packages/CarSystemUI/res/values-en-rCA/strings_car.xml
deleted file mode 100644
index 55dc48c50bb5..000000000000
--- a/packages/CarSystemUI/res/values-en-rCA/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Guest"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Guest"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Add user"</string>
- <string name="car_new_user" msgid="2994965724661108420">"New user"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"When you add a new user, that person needs to set up their space."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Any user can update apps for all other users."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rGB/strings.xml b/packages/CarSystemUI/res/values-en-rGB/strings.xml
deleted file mode 100644
index 8eb76c20d8a2..000000000000
--- a/packages/CarSystemUI/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Voice recognition now handled by connected Bluetooth device"</string>
- <string name="car_guest" msgid="318393171202663722">"Guest"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Guest"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Add user"</string>
- <string name="car_new_user" msgid="6637442369728092473">"New user"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"When you add a new user, that person needs to set up their space."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Any user can update apps for all other users."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Loading"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Loading user (from <xliff:g id="FROM_USER">%1$d</xliff:g> to <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Close"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rGB/strings_car.xml b/packages/CarSystemUI/res/values-en-rGB/strings_car.xml
deleted file mode 100644
index 55dc48c50bb5..000000000000
--- a/packages/CarSystemUI/res/values-en-rGB/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Guest"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Guest"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Add user"</string>
- <string name="car_new_user" msgid="2994965724661108420">"New user"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"When you add a new user, that person needs to set up their space."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Any user can update apps for all other users."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rIN/strings.xml b/packages/CarSystemUI/res/values-en-rIN/strings.xml
deleted file mode 100644
index 8eb76c20d8a2..000000000000
--- a/packages/CarSystemUI/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Voice recognition now handled by connected Bluetooth device"</string>
- <string name="car_guest" msgid="318393171202663722">"Guest"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Guest"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Add user"</string>
- <string name="car_new_user" msgid="6637442369728092473">"New user"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"When you add a new user, that person needs to set up their space."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Any user can update apps for all other users."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Loading"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Loading user (from <xliff:g id="FROM_USER">%1$d</xliff:g> to <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Close"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rIN/strings_car.xml b/packages/CarSystemUI/res/values-en-rIN/strings_car.xml
deleted file mode 100644
index 55dc48c50bb5..000000000000
--- a/packages/CarSystemUI/res/values-en-rIN/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Guest"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Guest"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Add user"</string>
- <string name="car_new_user" msgid="2994965724661108420">"New user"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"When you add a new user, that person needs to set up their space."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Any user can update apps for all other users."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rXC/strings.xml b/packages/CarSystemUI/res/values-en-rXC/strings.xml
deleted file mode 100644
index 37a568bf3e5a..000000000000
--- a/packages/CarSystemUI/res/values-en-rXC/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎Min‎‏‎‎‏‎"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎Max‎‏‎‎‏‎"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‎‎Voice recognition now handled by connected Bluetooth device‎‏‎‎‏‎"</string>
- <string name="car_guest" msgid="318393171202663722">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎Guest‎‏‎‎‏‎"</string>
- <string name="start_guest_session" msgid="497784785761754874">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎Guest‎‏‎‎‏‎"</string>
- <string name="car_add_user" msgid="4067337059622483269">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎Add User‎‏‎‎‏‎"</string>
- <string name="car_new_user" msgid="6637442369728092473">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎New User‎‏‎‎‏‎"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‎‎‏‏‎When you add a new user, that person needs to set up their space.‎‏‎‎‏‎"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‏‏‎Any user can update apps for all other users.‎‏‎‎‏‎"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‎‏‎‎Loading‎‏‎‎‏‎"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎Loading user (from ‎‏‎‎‏‏‎<xliff:g id="FROM_USER">%1$d</xliff:g>‎‏‎‎‏‏‏‎ to ‎‏‎‎‏‏‎<xliff:g id="TO_USER">%2$d</xliff:g>‎‏‎‎‏‏‏‎)‎‏‎‎‏‎"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎Close‎‏‎‎‏‎"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-en-rXC/strings_car.xml b/packages/CarSystemUI/res/values-en-rXC/strings_car.xml
deleted file mode 100644
index 17ad62cc8bae..000000000000
--- a/packages/CarSystemUI/res/values-en-rXC/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎Guest‎‏‎‎‏‎"</string>
- <string name="start_guest_session" msgid="548879769864070364">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‏‏‎‎‎Guest‎‏‎‎‏‎"</string>
- <string name="car_add_user" msgid="9196649698797257695">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎Add User‎‏‎‎‏‎"</string>
- <string name="car_new_user" msgid="2994965724661108420">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‎‏‎‎‎New User‎‏‎‎‏‎"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‎‏‏‏‎‎When you add a new user, that person needs to set up their space.‎‏‎‎‏‎"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎Any user can update apps for all other users.‎‏‎‎‏‎"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-es-rUS/strings.xml b/packages/CarSystemUI/res/values-es-rUS/strings.xml
deleted file mode 100644
index 16aba86f3c3f..000000000000
--- a/packages/CarSystemUI/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Mín."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Máx."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"El dispositivo Bluetooth administra el reconocimiento de voz"</string>
- <string name="car_guest" msgid="318393171202663722">"Invitado"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Invitado"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Agregar usuario"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Usuario nuevo"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Cuando agregues un usuario nuevo, esa persona deberá configurar su espacio."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Cualquier usuario podrá actualizar las apps de otras personas."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Cargando"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Cargando usuario (de <xliff:g id="FROM_USER">%1$d</xliff:g> a <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Cerrar"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-es-rUS/strings_car.xml b/packages/CarSystemUI/res/values-es-rUS/strings_car.xml
deleted file mode 100644
index cc31ae4920a9..000000000000
--- a/packages/CarSystemUI/res/values-es-rUS/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Invitado"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Invitado"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Agregar usuario"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Usuario nuevo"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Cuando agregues un usuario nuevo, esa persona deberá configurar su espacio."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Cualquier usuario podrá actualizar las apps de otras personas."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-es/strings.xml b/packages/CarSystemUI/res/values-es/strings.xml
deleted file mode 100644
index 8aad2cad9cf2..000000000000
--- a/packages/CarSystemUI/res/values-es/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Mín."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Máx."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"El dispositivo Bluetooth gestiona el reconocimiento de voz"</string>
- <string name="car_guest" msgid="318393171202663722">"Invitado"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Invitado"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Añadir usuario"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Nuevo usuario"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Cuando añades un usuario, esa persona debe configurar su espacio."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Cualquier usuario puede actualizar las aplicaciones del resto de los usuarios."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Cargando"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Cargando usuario (de <xliff:g id="FROM_USER">%1$d</xliff:g> a <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Cerrar"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-es/strings_car.xml b/packages/CarSystemUI/res/values-es/strings_car.xml
deleted file mode 100644
index 26ce2f1fbe13..000000000000
--- a/packages/CarSystemUI/res/values-es/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Invitado"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Invitado"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Añadir usuario"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Nuevo usuario"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Al añadir un usuario, esta persona debe configurar su espacio."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Cualquier usuario puede actualizar las aplicaciones del resto de los usuarios."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-et/strings.xml b/packages/CarSystemUI/res/values-et/strings.xml
deleted file mode 100644
index 14ec9df45c2d..000000000000
--- a/packages/CarSystemUI/res/values-et/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Häältuvastust haldab nüüd ühendatud Bluetoothi seade"</string>
- <string name="car_guest" msgid="318393171202663722">"Külaline"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Külaline"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Lisa kasutaja"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Uus kasutaja"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kui lisate uue kasutaja, siis peab ta seadistama oma ruumi."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Iga kasutaja saab rakendusi värskendada kõigi teiste kasutajate jaoks."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Laadimine"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Kasutaja laadimine (<xliff:g id="FROM_USER">%1$d</xliff:g> &gt; <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Sule"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-et/strings_car.xml b/packages/CarSystemUI/res/values-et/strings_car.xml
deleted file mode 100644
index ce475b194876..000000000000
--- a/packages/CarSystemUI/res/values-et/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Külaline"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Külaline"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Lisa kasutaja"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Uus kasutaja"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Kui lisate uue kasutaja, siis peab ta seadistama oma ruumi."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Iga kasutaja saab rakendusi värskendada kõigi teiste kasutajate jaoks."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-eu/strings.xml b/packages/CarSystemUI/res/values-eu/strings.xml
deleted file mode 100644
index 9139e650187e..000000000000
--- a/packages/CarSystemUI/res/values-eu/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Konektatutako Bluetooth bidezko gailuak kudeatzen du ahotsa ezagutzeko eginbidea"</string>
- <string name="car_guest" msgid="318393171202663722">"Gonbidatua"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gonbidatua"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Gehitu erabiltzaile bat"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Erabiltzaile berria"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Erabiltzaile bat gehitzen duzunean, bere eremua konfiguratu beharko du."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Edozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Kargatzen"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Erabiltzailea kargatzen (<xliff:g id="FROM_USER">%1$d</xliff:g> izatetik<xliff:g id="TO_USER">%2$d</xliff:g> izatera igaroko da)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Itxi"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-eu/strings_car.xml b/packages/CarSystemUI/res/values-eu/strings_car.xml
deleted file mode 100644
index be7c6dc0370e..000000000000
--- a/packages/CarSystemUI/res/values-eu/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gonbidatua"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gonbidatua"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Gehitu erabiltzaile bat"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Erabiltzaile berria"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Erabiltzaile bat gehitzen duzunean, bere eremua konfiguratu beharko du."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Edozein erabiltzailek egunera ditzake beste erabiltzaile guztien aplikazioak."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fa/strings.xml b/packages/CarSystemUI/res/values-fa/strings.xml
deleted file mode 100644
index 3f53b1145b96..000000000000
--- a/packages/CarSystemUI/res/values-fa/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"حداقل"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"حداکثر"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"اکنون تشخیص صدا را دستگاه بلوتوث متصل کنترل می‌کند"</string>
- <string name="car_guest" msgid="318393171202663722">"مهمان"</string>
- <string name="start_guest_session" msgid="497784785761754874">"مهمان"</string>
- <string name="car_add_user" msgid="4067337059622483269">"افزودن کاربر"</string>
- <string name="car_new_user" msgid="6637442369728092473">"کاربر جدید"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"وقتی کاربر جدیدی اضافه می‌کنید، آن فرد باید فضای خود را تنظیم کند."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"هر کاربری می‌تواند برنامه‌ها را برای همه کاربران دیگر به‌روزرسانی کند."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"درحال بارگیری"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"بارگیری کاربر (از <xliff:g id="FROM_USER">%1$d</xliff:g> تا <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"بستن"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fa/strings_car.xml b/packages/CarSystemUI/res/values-fa/strings_car.xml
deleted file mode 100644
index 5138d5fec43d..000000000000
--- a/packages/CarSystemUI/res/values-fa/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"مهمان"</string>
- <string name="start_guest_session" msgid="548879769864070364">"مهمان"</string>
- <string name="car_add_user" msgid="9196649698797257695">"افزودن کاربر"</string>
- <string name="car_new_user" msgid="2994965724661108420">"کاربر جدید"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"وقتی کاربری جدید اضافه می‌کنید، آن فرد باید فضای خود را تنظیم کند."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"هر کاربری می‌تواند برنامه‌ها را برای همه کاربران دیگر به‌روزرسانی کند."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fi/strings.xml b/packages/CarSystemUI/res/values-fi/strings.xml
deleted file mode 100644
index 79b53f6daa2c..000000000000
--- a/packages/CarSystemUI/res/values-fi/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Alin"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Ylin"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Äänentunnistus tehdään nyt yhdistetyllä Bluetooth-laitteella"</string>
- <string name="car_guest" msgid="318393171202663722">"Vieras"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Vieras"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Lisää käyttäjä"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Uusi käyttäjä"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kun lisäät uuden käyttäjän, hänen on valittava oman tilansa asetukset."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Kaikki käyttäjät voivat päivittää muiden käyttäjien sovelluksia."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Ladataan"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Ladataan käyttäjäprofiilia (<xliff:g id="FROM_USER">%1$d</xliff:g>–<xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Sulje"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fi/strings_car.xml b/packages/CarSystemUI/res/values-fi/strings_car.xml
deleted file mode 100644
index 5963b52182be..000000000000
--- a/packages/CarSystemUI/res/values-fi/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Vieras"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Vieras"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Lisää käyttäjä"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Uusi käyttäjä"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Kun lisäät uuden käyttäjän, hänen on valittava oman tilansa asetukset."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Kaikki käyttäjät voivat päivittää muiden käyttäjien sovelluksia."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fr-rCA/strings.xml b/packages/CarSystemUI/res/values-fr-rCA/strings.xml
deleted file mode 100644
index b1905490f229..000000000000
--- a/packages/CarSystemUI/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"La reconn. voc. est gérée par l\'appareil Bluetooth connecté"</string>
- <string name="car_guest" msgid="318393171202663722">"Invité"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Invité"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Ajouter un utilisateur"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Nouvel utilisateur"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Tout utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Chargement en cours…"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Chargement de l\'utilisateur (de <xliff:g id="FROM_USER">%1$d</xliff:g> vers <xliff:g id="TO_USER">%2$d</xliff:g>) en cours…"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Fermer"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fr-rCA/strings_car.xml b/packages/CarSystemUI/res/values-fr-rCA/strings_car.xml
deleted file mode 100644
index ab0a3028aff1..000000000000
--- a/packages/CarSystemUI/res/values-fr-rCA/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Invité"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Invité"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Ajouter un utilisateur"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Nouvel utilisateur"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Tout utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fr/strings.xml b/packages/CarSystemUI/res/values-fr/strings.xml
deleted file mode 100644
index 5a905a000c42..000000000000
--- a/packages/CarSystemUI/res/values-fr/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"L\'appareil Bluetooth connecté gère la reconnaissance vocale"</string>
- <string name="car_guest" msgid="318393171202663722">"Invité"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Invité"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Ajouter un utilisateur"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Nouvel utilisateur"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"N\'importe quel utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Chargement…"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Chargement de l\'utilisateur (de <xliff:g id="FROM_USER">%1$d</xliff:g> à <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Fermer"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-fr/strings_car.xml b/packages/CarSystemUI/res/values-fr/strings_car.xml
deleted file mode 100644
index b072eccbe406..000000000000
--- a/packages/CarSystemUI/res/values-fr/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Invité"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Invité"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Ajouter un utilisateur"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Nouvel utilisateur"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Lorsque vous ajoutez un utilisateur, celui-ci doit configurer son espace."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"N\'importe quel utilisateur peut mettre à jour les applications pour tous les autres utilisateurs."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-gl/strings.xml b/packages/CarSystemUI/res/values-gl/strings.xml
deleted file mode 100644
index e77df4f50272..000000000000
--- a/packages/CarSystemUI/res/values-gl/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Mín."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Máx."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"O dispositivo Bluetooth xestionará o recoñecemento de voz"</string>
- <string name="car_guest" msgid="318393171202663722">"Convidado"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Convidado"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Engadir usuario"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Novo usuario"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Cando engadas un novo usuario, este deberá configurar o seu espazo."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Calquera usuario pode actualizar as aplicacións para o resto dos usuarios."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Cargando"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Cargando usuario (do <xliff:g id="FROM_USER">%1$d</xliff:g> ao <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Pechar"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-gl/strings_car.xml b/packages/CarSystemUI/res/values-gl/strings_car.xml
deleted file mode 100644
index fc4af284dad6..000000000000
--- a/packages/CarSystemUI/res/values-gl/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Convidado"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Convidado"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Engadir usuario"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Novo usuario"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Cando engadas un usuario novo, este deberá configurar o seu espazo."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Calquera usuario pode actualizar as aplicacións para o resto dos usuarios."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-gu/strings.xml b/packages/CarSystemUI/res/values-gu/strings.xml
deleted file mode 100644
index 174d7a724240..000000000000
--- a/packages/CarSystemUI/res/values-gu/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"ન્યૂનતમ"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"મહત્તમ"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"અવાજની ઓળખ હવે કનેક્ટેડ બ્લૂટૂથ ડિવાઇસ વડે નિયંત્રિત થશે"</string>
- <string name="car_guest" msgid="318393171202663722">"અતિથિ"</string>
- <string name="start_guest_session" msgid="497784785761754874">"અતિથિ"</string>
- <string name="car_add_user" msgid="4067337059622483269">"વપરાશકર્તા ઉમેરો"</string>
- <string name="car_new_user" msgid="6637442369728092473">"નવા વપરાશકર્તા"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"જ્યારે તમે કોઈ નવા વપરાશકર્તાને ઉમેરો છો, ત્યારે તે વ્યક્તિએ તેમની સ્પેસ સેટ કરવાની જરૂર રહે છે."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"કોઈપણ વપરાશકર્તા અન્ય બધા વપરાશકર્તાઓ માટે ઍપને અપડેટ કરી શકે છે."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"લોડ કરી રહ્યાં છીએ"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"વપરાશકર્તાને લોડ કરી રહ્યાં છીએ (<xliff:g id="FROM_USER">%1$d</xliff:g>માંથી <xliff:g id="TO_USER">%2$d</xliff:g>માં)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"બંધ કરો"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-gu/strings_car.xml b/packages/CarSystemUI/res/values-gu/strings_car.xml
deleted file mode 100644
index 48a9dacaeea1..000000000000
--- a/packages/CarSystemUI/res/values-gu/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"અતિથિ"</string>
- <string name="start_guest_session" msgid="548879769864070364">"અતિથિ"</string>
- <string name="car_add_user" msgid="9196649698797257695">"વપરાશકર્તા ઉમેરો"</string>
- <string name="car_new_user" msgid="2994965724661108420">"નવા વપરાશકર્તા"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"જ્યારે તમે કોઈ નવા વપરાશકર્તાને ઉમેરો છો, ત્યારે તે વ્યક્તિએ તેમની સ્પેસ સેટ કરવાની જરૂર રહે છે."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"કોઈપણ વપરાશકર્તા અન્ય બધા વપરાશકર્તાઓ માટે ઍપને અપડેટ કરી શકે છે."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hi/strings.xml b/packages/CarSystemUI/res/values-hi/strings.xml
deleted file mode 100644
index 83321fd630b9..000000000000
--- a/packages/CarSystemUI/res/values-hi/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"कम से कम"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"ज़्यादा से ज़्यादा"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"अब आवाज़ पहचानने का काम, कनेक्ट किए गए ब्लूटूथ डिवाइस करते हैं"</string>
- <string name="car_guest" msgid="318393171202663722">"मेहमान प्रोफ़ाइल"</string>
- <string name="start_guest_session" msgid="497784785761754874">"मेहमान के तौर पर सेशन शुरू करें"</string>
- <string name="car_add_user" msgid="4067337059622483269">"उपयोगकर्ता जोड़ें"</string>
- <string name="car_new_user" msgid="6637442369728092473">"नया उपयोगकर्ता"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं, तब उसे अपनी जगह सेट करनी होती है."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"कोई भी उपयोगकर्ता, बाकी सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"लोड हो रही है"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"उपयोगकर्ता को लोड किया जा रहा है (<xliff:g id="FROM_USER">%1$d</xliff:g> से <xliff:g id="TO_USER">%2$d</xliff:g> पर)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"बंद करें"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hi/strings_car.xml b/packages/CarSystemUI/res/values-hi/strings_car.xml
deleted file mode 100644
index ec83e95093e3..000000000000
--- a/packages/CarSystemUI/res/values-hi/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"मेहमान"</string>
- <string name="start_guest_session" msgid="548879769864070364">"मेहमान"</string>
- <string name="car_add_user" msgid="9196649698797257695">"उपयोगकर्ता जोड़ें"</string>
- <string name="car_new_user" msgid="2994965724661108420">"नया उपयोगकर्ता"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"जब आप कोई नया उपयोगकर्ता जोड़ते हैं, तब उसे अपनी जगह सेट करनी होती है."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"कोई भी उपयोगकर्ता बाकी सभी उपयोगकर्ताओं के लिए ऐप्लिकेशन अपडेट कर सकता है."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hr/strings.xml b/packages/CarSystemUI/res/values-hr/strings.xml
deleted file mode 100644
index 872fc69d8cfb..000000000000
--- a/packages/CarSystemUI/res/values-hr/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Prepoznavanjem glasa rukuje se s povezanog Bluetooth uređaja"</string>
- <string name="car_guest" msgid="318393171202663722">"Gost"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gost"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Dodajte korisnika"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Novi korisnik"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kada dodate novog korisnika, ta osoba mora postaviti vlastiti prostor."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Svaki korisnik može ažurirati aplikacije za ostale korisnike."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Učitavanje"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Učitavanje korisnika (od <xliff:g id="FROM_USER">%1$d</xliff:g> do <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Zatvori"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hr/strings_car.xml b/packages/CarSystemUI/res/values-hr/strings_car.xml
deleted file mode 100644
index d707145ad569..000000000000
--- a/packages/CarSystemUI/res/values-hr/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gost"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gost"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Dodajte korisnika"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Novi korisnik"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Kada dodate novog korisnika, ta osoba mora postaviti vlastiti prostor."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Svaki korisnik može ažurirati aplikacije za ostale korisnike."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hu/strings.xml b/packages/CarSystemUI/res/values-hu/strings.xml
deleted file mode 100644
index 63328f370ed3..000000000000
--- a/packages/CarSystemUI/res/values-hu/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"A hangfelismerést a csatlakoztatott Bluetooth-eszköz kezeli"</string>
- <string name="car_guest" msgid="318393171202663722">"Vendég"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Vendég"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Felhasználó hozzáadása"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Új felhasználó"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Ha új felhasználót ad hozzá, az illetőnek be kell állítania saját felületét."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Bármely felhasználó frissítheti az alkalmazásokat az összes felhasználó számára."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Betöltés"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Felhasználó betöltése (<xliff:g id="FROM_USER">%1$d</xliff:g> → <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Bezárás"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hu/strings_car.xml b/packages/CarSystemUI/res/values-hu/strings_car.xml
deleted file mode 100644
index 4f11ec2ff029..000000000000
--- a/packages/CarSystemUI/res/values-hu/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Vendég"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Vendég"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Felhasználó hozzáadása"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Új felhasználó"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Ha új felhasználót ad hozzá, az illetőnek be kell állítania saját felületét."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Bármely felhasználó frissítheti az alkalmazásokat az összes felhasználó számára."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hy/strings.xml b/packages/CarSystemUI/res/values-hy/strings.xml
deleted file mode 100644
index 778f6954da3d..000000000000
--- a/packages/CarSystemUI/res/values-hy/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Նվազ․"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Առավ․"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Ձայնի ճանաչումը մշակվում է միացված Bluetooth սարքի կողմից"</string>
- <string name="car_guest" msgid="318393171202663722">"Հյուր"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Հյուրի ռեժիմ"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Ավելացնել օգտատեր"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Նոր օգտատեր"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Երբ դուք նոր օգտատեր եք ավելացնում, նա պետք է կարգավորի իր պրոֆիլը։"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Ցանկացած օգտատեր կարող է թարմացնել հավելվածները բոլոր մյուս հաշիվների համար։"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Բեռնում"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Օգտատերը բեռնվում է (<xliff:g id="FROM_USER">%1$d</xliff:g> – <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Փակել"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-hy/strings_car.xml b/packages/CarSystemUI/res/values-hy/strings_car.xml
deleted file mode 100644
index 555999961c26..000000000000
--- a/packages/CarSystemUI/res/values-hy/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Հյուր"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Հյուրի ռեժիմ"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Ավելացնել օգտատեր"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Նոր օգտատեր"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Երբ դուք նոր օգտատեր եք ավելացնում, նա պետք է կարգավորի իր պրոֆիլը։"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Ցանկացած օգտատեր կարող է թարմացնել հավելվածները բոլոր մյուս հաշիվների համար։"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-in/strings.xml b/packages/CarSystemUI/res/values-in/strings.xml
deleted file mode 100644
index 386d79e0e88b..000000000000
--- a/packages/CarSystemUI/res/values-in/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Pengenalan suara ditangani perangkat Bluetooth terhubung"</string>
- <string name="car_guest" msgid="318393171202663722">"Tamu"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Tamu"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Tambahkan Pengguna"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Pengguna Baru"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Saat Anda menambahkan pengguna baru, orang tersebut perlu menyiapkan ruangnya sendiri."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Setiap pengguna dapat mengupdate aplikasi untuk semua pengguna lain."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Memuat"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Memuat pengguna (dari <xliff:g id="FROM_USER">%1$d</xliff:g> menjadi <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Tutup"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-in/strings_car.xml b/packages/CarSystemUI/res/values-in/strings_car.xml
deleted file mode 100644
index 69f23ce22d58..000000000000
--- a/packages/CarSystemUI/res/values-in/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Tamu"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Tamu"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Tambahkan Pengguna"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Pengguna Baru"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Saat Anda menambahkan pengguna baru, orang tersebut perlu menyiapkan ruangnya sendiri."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Setiap pengguna dapat mengupdate aplikasi untuk semua pengguna lain."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-is/strings.xml b/packages/CarSystemUI/res/values-is/strings.xml
deleted file mode 100644
index 5a927aa0928a..000000000000
--- a/packages/CarSystemUI/res/values-is/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Lágm."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Hám."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Raddgreiningu er nú stjórnað af tengdu Bluetooth-tæki"</string>
- <string name="car_guest" msgid="318393171202663722">"Gestur"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gestur"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Bæta notanda við"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Nýr notandi"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Þegar þú bætir nýjum notanda við þarf viðkomandi að setja upp sitt eigið svæði."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Allir notendur geta uppfært forrit fyrir alla aðra notendur."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Hleður"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Hleður notanda (frá <xliff:g id="FROM_USER">%1$d</xliff:g> til <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Loka"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-is/strings_car.xml b/packages/CarSystemUI/res/values-is/strings_car.xml
deleted file mode 100644
index 430e902be918..000000000000
--- a/packages/CarSystemUI/res/values-is/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gestur"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gestur"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Bæta notanda við"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Nýr notandi"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Þegar þú bætir nýjum notanda við þarf viðkomandi að setja upp sitt eigið svæði."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Allir notendur geta uppfært forrit fyrir alla aðra notendur."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-it/strings.xml b/packages/CarSystemUI/res/values-it/strings.xml
deleted file mode 100644
index 41d7ad4f70ee..000000000000
--- a/packages/CarSystemUI/res/values-it/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Riconoscimento vocale gestito da dispos. Bluetooth connesso"</string>
- <string name="car_guest" msgid="318393171202663722">"Ospite"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Ospite"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Aggiungi utente"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Nuovo utente"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Il nuovo utente, una volta aggiunto, dovrà configurare il suo spazio."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Qualsiasi utente può aggiornare le app per tutti gli altri."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Caricamento"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Caricamento dell\'utente (da <xliff:g id="FROM_USER">%1$d</xliff:g> a <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Chiudi"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-it/strings_car.xml b/packages/CarSystemUI/res/values-it/strings_car.xml
deleted file mode 100644
index 9c498dfe1e0b..000000000000
--- a/packages/CarSystemUI/res/values-it/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Ospite"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Ospite"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Aggiungi utente"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Nuovo utente"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Il nuovo utente, una volta aggiunto, dovrà configurare il suo spazio."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Qualsiasi utente può aggiornare le app per tutti gli altri."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-iw/strings.xml b/packages/CarSystemUI/res/values-iw/strings.xml
deleted file mode 100644
index f419cac56d48..000000000000
--- a/packages/CarSystemUI/res/values-iw/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"מינ\'"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"מקס\'"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"הזיהוי הקולי מתבצע עכשיו במכשיר Bluetooth מחובר"</string>
- <string name="car_guest" msgid="318393171202663722">"אורח"</string>
- <string name="start_guest_session" msgid="497784785761754874">"אורח"</string>
- <string name="car_add_user" msgid="4067337059622483269">"הוספת משתמש"</string>
- <string name="car_new_user" msgid="6637442369728092473">"משתמש חדש"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"בעת הוספת משתמש חדש, על משתמש זה להגדיר את המרחב שלו."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"כל משתמש יכול לעדכן אפליקציות לכל שאר המשתמשים."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"בטעינה"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"המשתמש בטעינה (מהמשתמש <xliff:g id="FROM_USER">%1$d</xliff:g> אל <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"סגירה"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ja/strings.xml b/packages/CarSystemUI/res/values-ja/strings.xml
deleted file mode 100644
index 9cf056fdf7c6..000000000000
--- a/packages/CarSystemUI/res/values-ja/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"最小"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"最大"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Bluetooth 接続デバイスで音声認識が処理されるようになりました"</string>
- <string name="car_guest" msgid="318393171202663722">"ゲスト"</string>
- <string name="start_guest_session" msgid="497784785761754874">"ゲスト"</string>
- <string name="car_add_user" msgid="4067337059622483269">"ユーザーを追加"</string>
- <string name="car_new_user" msgid="6637442369728092473">"新しいユーザー"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"新しいユーザーを追加したら、そのユーザーは自分のスペースをセットアップする必要があります。"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"どのユーザーも他のすべてのユーザーに代わってアプリを更新できます。"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"読み込んでいます"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ユーザーを読み込んでいます(<xliff:g id="FROM_USER">%1$d</xliff:g>~<xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"閉じる"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ja/strings_car.xml b/packages/CarSystemUI/res/values-ja/strings_car.xml
deleted file mode 100644
index d59b267117b8..000000000000
--- a/packages/CarSystemUI/res/values-ja/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"ゲスト"</string>
- <string name="start_guest_session" msgid="548879769864070364">"ゲスト"</string>
- <string name="car_add_user" msgid="9196649698797257695">"ユーザーを追加"</string>
- <string name="car_new_user" msgid="2994965724661108420">"新しいユーザー"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"新しいユーザーを追加したら、そのユーザーは自分のスペースをセットアップする必要があります。"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"どのユーザーも他のすべてのユーザーに代わってアプリを更新できます。"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ka/strings.xml b/packages/CarSystemUI/res/values-ka/strings.xml
deleted file mode 100644
index 7d62c62a8abe..000000000000
--- a/packages/CarSystemUI/res/values-ka/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"მინ"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"მაქს"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"ხმის ამოცნობა დამუშავდება დაკავშირებული Bluetooth-მოწყობილობით"</string>
- <string name="car_guest" msgid="318393171202663722">"სტუმარი"</string>
- <string name="start_guest_session" msgid="497784785761754874">"სტუმარი"</string>
- <string name="car_add_user" msgid="4067337059622483269">"მომხმარებლის დამატება"</string>
- <string name="car_new_user" msgid="6637442369728092473">"ახალი მომხმარებელი"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"ახალი მომხმარებლის დამატებისას, ამ მომხმარებელს საკუთარი სივრცის გამართვა მოუწევს."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"ნებისმიერ მომხმარებელს შეუძლია აპები ყველა სხვა მომხმარებლისათვის განაახლოს."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"იტვირთება"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"იტვირთება მომხმარებელი (<xliff:g id="FROM_USER">%1$d</xliff:g>-დან <xliff:g id="TO_USER">%2$d</xliff:g>-მდე)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"დახურვა"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ka/strings_car.xml b/packages/CarSystemUI/res/values-ka/strings_car.xml
deleted file mode 100644
index cb0e8fda43cf..000000000000
--- a/packages/CarSystemUI/res/values-ka/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"სტუმარი"</string>
- <string name="start_guest_session" msgid="548879769864070364">"სტუმარი"</string>
- <string name="car_add_user" msgid="9196649698797257695">"მომხმარებლის დამატება"</string>
- <string name="car_new_user" msgid="2994965724661108420">"ახალი მომხმარებელი"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"ახალი მომხმარებლის დამატებისას, ამ მომხმარებელს საკუთარი სივრცის შექმნა მოუწევს."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"ნებისმიერ მომხმარებელს შეუძლია აპები ყველა სხვა მომხმარებლისათვის განაახლოს."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-kk/strings.xml b/packages/CarSystemUI/res/values-kk/strings.xml
deleted file mode 100644
index 2dd1b66f1778..000000000000
--- a/packages/CarSystemUI/res/values-kk/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Дауысты тану үшін Bluetooth құрылғысы пайдаланылады."</string>
- <string name="car_guest" msgid="318393171202663722">"Қонақ"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Қонақ"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Пайдаланушыны енгізу"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Жаңа пайдаланушы"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Енгізілген жаңа пайдаланушы өз профилін реттеуі керек."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Кез келген пайдаланушы қолданбаларды басқа пайдаланушылар үшін жаңарта алады."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Жүктелуде"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Пайдаланушы профилі жүктелуде (<xliff:g id="FROM_USER">%1$d</xliff:g> – <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Жабу"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-km/strings.xml b/packages/CarSystemUI/res/values-km/strings.xml
deleted file mode 100644
index 709cfe572ce9..000000000000
--- a/packages/CarSystemUI/res/values-km/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"អប្បបរមា"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"អតិបរិមា"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"ឥឡូវនេះ ការសម្គាល់សំឡេងត្រូវបានចាត់ចែងដោយឧបករណ៍ដែលបានភ្ជាប់ប៊្លូធូស"</string>
- <string name="car_guest" msgid="318393171202663722">"ភ្ញៀវ"</string>
- <string name="start_guest_session" msgid="497784785761754874">"ភ្ញៀវ"</string>
- <string name="car_add_user" msgid="4067337059622483269">"បញ្ចូល​អ្នក​ប្រើប្រាស់"</string>
- <string name="car_new_user" msgid="6637442369728092473">"អ្នក​ប្រើប្រាស់​ថ្មី"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"នៅពេលដែល​អ្នក​បញ្ចូល​អ្នក​ប្រើប្រាស់​ថ្មី បុគ្គល​នោះ​ត្រូវតែ​រៀបចំ​ទំហំ​ផ្ទុក​របស់គេ។"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"អ្នកប្រើប្រាស់​ណាក៏​អាច​ដំឡើងកំណែ​កម្មវិធី​សម្រាប់​អ្នកប្រើប្រាស់ទាំងអស់​ផ្សេងទៀត​បានដែរ។"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"កំពុងផ្ទុក"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"កំពុងផ្ទុក​អ្នកប្រើប្រាស់ (ពី <xliff:g id="FROM_USER">%1$d</xliff:g> ដល់ <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"បិទ"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-km/strings_car.xml b/packages/CarSystemUI/res/values-km/strings_car.xml
deleted file mode 100644
index b6a9864aba86..000000000000
--- a/packages/CarSystemUI/res/values-km/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"ភ្ញៀវ"</string>
- <string name="start_guest_session" msgid="548879769864070364">"ភ្ញៀវ"</string>
- <string name="car_add_user" msgid="9196649698797257695">"បញ្ចូល​អ្នក​ប្រើប្រាស់"</string>
- <string name="car_new_user" msgid="2994965724661108420">"អ្នក​ប្រើប្រាស់​ថ្មី"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"នៅពេលដែល​អ្នកបញ្ចូល​អ្នក​ប្រើប្រាស់ថ្មី បុគ្គល​នោះ​ត្រូវរៀបចំ​ទំហំផ្ទុក​របស់គេ។"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"អ្នកប្រើប្រាស់​ណាក៏​អាច​ដំឡើងកំណែ​កម្មវិធី​សម្រាប់​អ្នកប្រើប្រាស់ទាំងអស់​ផ្សេងទៀត​បានដែរ។"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-kn/strings.xml b/packages/CarSystemUI/res/values-kn/strings.xml
deleted file mode 100644
index b9667df3afb3..000000000000
--- a/packages/CarSystemUI/res/values-kn/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"ಕನಿಷ್ಠ"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"ಗರಿಷ್ಠ"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"ಇದೀಗ ಕನೆಕ್ಟ್ ಆದ ಬ್ಲೂಟೂತ್ ಸಾಧನ ಧ್ವನಿ ಗುರುತಿಸುವಿಕೆ ನಿರ್ವಹಿಸಿದೆ"</string>
- <string name="car_guest" msgid="318393171202663722">"ಅತಿಥಿ"</string>
- <string name="start_guest_session" msgid="497784785761754874">"ಅತಿಥಿ"</string>
- <string name="car_add_user" msgid="4067337059622483269">"ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿ"</string>
- <string name="car_new_user" msgid="6637442369728092473">"ಹೊಸ ಬಳಕೆದಾರ"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"ನೀವು ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿದಾಗ, ಆ ವ್ಯಕ್ತಿಯು ಅವರ ಸ್ಥಳವನ್ನು ಸೆಟಪ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"ಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗಾಗಿ ಆ್ಯಪ್‌ಗಳನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಬಹುದು."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"ಲೋಡ್ ಆಗುತ್ತಿದೆ"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ಬಳಕೆದಾರರನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ (<xliff:g id="FROM_USER">%1$d</xliff:g> ನಿಂದ <xliff:g id="TO_USER">%2$d</xliff:g> ವರೆಗೆ)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"ಮುಚ್ಚಿರಿ"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-kn/strings_car.xml b/packages/CarSystemUI/res/values-kn/strings_car.xml
deleted file mode 100644
index 23e5415baa73..000000000000
--- a/packages/CarSystemUI/res/values-kn/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"ಅತಿಥಿ"</string>
- <string name="start_guest_session" msgid="548879769864070364">"ಅತಿಥಿ"</string>
- <string name="car_add_user" msgid="9196649698797257695">"ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿ"</string>
- <string name="car_new_user" msgid="2994965724661108420">"ಹೊಸ ಬಳಕೆದಾರ"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"ನೀವು ಹೊಸ ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿದಾಗ, ಆ ವ್ಯಕ್ತಿಯು ಅವರ ಸ್ಥಳವನ್ನು ಸೆಟಪ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"ಯಾವುದೇ ಬಳಕೆದಾರರು ಎಲ್ಲಾ ಇತರೆ ಬಳಕೆದಾರರಿಗಾಗಿ ಆ್ಯಪ್‌ಗಳನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡಬಹುದು."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ko/strings.xml b/packages/CarSystemUI/res/values-ko/strings.xml
deleted file mode 100644
index 17a24667b547..000000000000
--- a/packages/CarSystemUI/res/values-ko/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"최소"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"최대"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"이제 연결된 블루투스 기기에서 음성 인식이 처리됩니다."</string>
- <string name="car_guest" msgid="318393171202663722">"게스트"</string>
- <string name="start_guest_session" msgid="497784785761754874">"게스트"</string>
- <string name="car_add_user" msgid="4067337059622483269">"사용자 추가"</string>
- <string name="car_new_user" msgid="6637442369728092473">"신규 사용자"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"추가된 신규 사용자는 자신만의 공간을 설정해야 합니다."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"누구나 다른 모든 사용자를 위해 앱을 업데이트할 수 있습니다."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"로드 중"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"사용자 로드 중(<xliff:g id="FROM_USER">%1$d</xliff:g>님에서 <xliff:g id="TO_USER">%2$d</xliff:g>님으로)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"닫기"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ko/strings_car.xml b/packages/CarSystemUI/res/values-ko/strings_car.xml
deleted file mode 100644
index 3997c0f43c26..000000000000
--- a/packages/CarSystemUI/res/values-ko/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"게스트"</string>
- <string name="start_guest_session" msgid="548879769864070364">"게스트"</string>
- <string name="car_add_user" msgid="9196649698797257695">"사용자 추가"</string>
- <string name="car_new_user" msgid="2994965724661108420">"신규 사용자"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"추가된 신규 사용자는 자신만의 공간을 설정해야 합니다."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"누구나 다른 모든 사용자를 위해 앱을 업데이트할 수 있습니다."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ky/strings.xml b/packages/CarSystemUI/res/values-ky/strings.xml
deleted file mode 100644
index dd9225a1aa0b..000000000000
--- a/packages/CarSystemUI/res/values-ky/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Үндү эми туташкан Bluetooth түзмөгү менен тааныса болот"</string>
- <string name="car_guest" msgid="318393171202663722">"Конок"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Конок"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Колдонуучу кошуу"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Жаңы колдонуучу"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Жаңы колдонуучу кошулганда, ал өзүнүн профилин жөндөп алышы керек."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Колдонмолорду бир колдонуучу калган бардык колдонуучулар үчүн да жаңырта алат."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Жүктөлүүдө"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Колдонуучу тууралуу маалымат жүктөлүүдө (<xliff:g id="FROM_USER">%1$d</xliff:g> – <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Жабуу"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-lo/strings.xml b/packages/CarSystemUI/res/values-lo/strings.xml
deleted file mode 100644
index bc94a5104c6b..000000000000
--- a/packages/CarSystemUI/res/values-lo/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"ນທ"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"ສູງສຸດ"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"ການຈຳແນກສຽງເວົ້າດຽວນີ້ຈັດການໂດຍອຸປະກອນ Bluetooth ທີ່ເຊື່ອມຕໍ່"</string>
- <string name="car_guest" msgid="318393171202663722">"ແຂກ"</string>
- <string name="start_guest_session" msgid="497784785761754874">"ແຂກ"</string>
- <string name="car_add_user" msgid="4067337059622483269">"ເພີ່ມຜູ້ໃຊ້"</string>
- <string name="car_new_user" msgid="6637442369728092473">"ຜູ້ໃຊ້ໃໝ່"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"ເມື່ອທ່ານເພີ່ມຜູ້ໃຊ້ໃໝ່, ບຸກຄົນນັ້ນຈຳເປັນຕ້ອງຕັ້ງຄ່າພື້ນທີ່ຂອງເຂົາເຈົ້າ."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"ຜູ້ໃຊ້ຕ່າງໆສາມາດອັບເດດແອັບສຳລັບຜູ້ໃຊ້ອື່ນທັງໝົດໄດ້."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"ກຳລັງໂຫຼດ"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ກຳລັງໂຫຼດຜູ້ໃຊ້ (ຈາກ <xliff:g id="FROM_USER">%1$d</xliff:g> ໄປຍັງ <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"ປິດ"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-lt/strings.xml b/packages/CarSystemUI/res/values-lt/strings.xml
deleted file mode 100644
index a47ad5909f12..000000000000
--- a/packages/CarSystemUI/res/values-lt/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Didž."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Balso atpažinimą dabar tvarko susietas „Bluetooth“ įrenginys"</string>
- <string name="car_guest" msgid="318393171202663722">"Svečias"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Svečias"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Pridėti naudotoją"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Naujas naudotojas"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kai pridedate naują naudotoją, šis asmuo turi nustatyti savo vietą."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Bet kuris naudotojas gali atnaujinti visų kitų naudotojų programas."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Įkeliama"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Įkeliamas naudotojo profilis (<xliff:g id="FROM_USER">%1$d</xliff:g> – <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Uždaryti"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-lt/strings_car.xml b/packages/CarSystemUI/res/values-lt/strings_car.xml
deleted file mode 100644
index a8cf0a7cd25d..000000000000
--- a/packages/CarSystemUI/res/values-lt/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Svečias"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Svečias"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Pridėti naudotoją"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Naujas naudotojas"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Kai pridedate naują naudotoją, šis asmuo turi nustatyti savo vietą."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Bet kuris naudotojas gali atnaujinti visų kitų naudotojų programas."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-lv/strings.xml b/packages/CarSystemUI/res/values-lv/strings.xml
deleted file mode 100644
index cb7c8b9f1575..000000000000
--- a/packages/CarSystemUI/res/values-lv/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Balss atpazīšanu tagad nodrošina pievienotā Bluetooth ierīce"</string>
- <string name="car_guest" msgid="318393171202663722">"Viesis"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Viesis"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Pievienot lietotāju"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Jauns lietotājs"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kad pievienojat jaunu lietotāju, viņam ir jāizveido savs profils."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Ikviens lietotājs var atjaunināt lietotnes visu lietotāju vārdā."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Notiek ielāde…"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Notiek lietotāja profila ielāde (<xliff:g id="FROM_USER">%1$d</xliff:g>–<xliff:g id="TO_USER">%2$d</xliff:g>)…"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Aizvērt"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-lv/strings_car.xml b/packages/CarSystemUI/res/values-lv/strings_car.xml
deleted file mode 100644
index 3b7f386c58be..000000000000
--- a/packages/CarSystemUI/res/values-lv/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Viesis"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Viesis"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Pievienot lietotāju"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Jauns lietotājs"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Kad pievienojat jaunu lietotāju, viņam ir jāizveido savs profils."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Ikviens lietotājs var atjaunināt lietotnes visu lietotāju vārdā."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-mk/strings.xml b/packages/CarSystemUI/res/values-mk/strings.xml
deleted file mode 100644
index cd2ae973a078..000000000000
--- a/packages/CarSystemUI/res/values-mk/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Поврзаниот уред со Bluetooth управува со препознавањето глас"</string>
- <string name="car_guest" msgid="318393171202663722">"Гостин"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Гостин"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Додај корисник"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Нов корисник"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Кога додавате нов корисник, тоа лице треба да го постави својот простор."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Секој корисник може да ажурира апликации за сите други корисници."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Се вчитува"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Се вчитува корисникот (од <xliff:g id="FROM_USER">%1$d</xliff:g> до <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Затвори"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-mk/strings_car.xml b/packages/CarSystemUI/res/values-mk/strings_car.xml
deleted file mode 100644
index c19414679d6c..000000000000
--- a/packages/CarSystemUI/res/values-mk/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Гостин"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Гостин"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Додај корисник"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Нов корисник"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Кога додавате нов корисник, тоа лице треба да го постави својот простор."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Секој корисник може да ажурира апликации за сите други корисници."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ml/strings.xml b/packages/CarSystemUI/res/values-ml/strings.xml
deleted file mode 100644
index 613ea59874bc..000000000000
--- a/packages/CarSystemUI/res/values-ml/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"മിനിമം"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"മാക്സിമം"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"കണക്റ്റ് ചെയ്ത Bluetooth ഉപകരണം വഴി ഇപ്പോൾ വോയ്‌സ് തിരിച്ചറിയൽ കെെകാര്യം ചെയ്യുന്നു"</string>
- <string name="car_guest" msgid="318393171202663722">"അതിഥി"</string>
- <string name="start_guest_session" msgid="497784785761754874">"അതിഥി"</string>
- <string name="car_add_user" msgid="4067337059622483269">"ഉപയോക്താവിനെ ചേർക്കുക"</string>
- <string name="car_new_user" msgid="6637442369728092473">"പുതിയ ഉപയോക്താവ്"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"നിങ്ങളൊരു പുതിയ ഉപയോക്താവിനെ ചേർക്കുമ്പോൾ, ആ വ്യക്തി സ്വന്തം ഇടം സജ്ജീകരിക്കേണ്ടതുണ്ട്."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"ഏതൊരു ഉപയോക്താവിനും മറ്റെല്ലാ ഉപയോക്താക്കൾക്കുമായി ആപ്പുകൾ അപ്‌ഡേറ്റ് ചെയ്യാനാവും."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"ലോഡ് ചെയ്യുന്നു"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ഉപയോക്തൃ പ്രൊഫൈൽ ലോഡ് ചെയ്യുന്നു (<xliff:g id="FROM_USER">%1$d</xliff:g> എന്നതിൽ നിന്ന് <xliff:g id="TO_USER">%2$d</xliff:g> എന്നതിലേക്ക്)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"അടയ്ക്കുക"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ml/strings_car.xml b/packages/CarSystemUI/res/values-ml/strings_car.xml
deleted file mode 100644
index 3ce44f7b62dd..000000000000
--- a/packages/CarSystemUI/res/values-ml/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"അതിഥി"</string>
- <string name="start_guest_session" msgid="548879769864070364">"അതിഥി"</string>
- <string name="car_add_user" msgid="9196649698797257695">"ഉപയോക്താവിനെ ചേർക്കുക"</string>
- <string name="car_new_user" msgid="2994965724661108420">"പുതിയ ഉപയോക്താവ്"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"നിങ്ങളൊരു പുതിയ ഉപയോക്താവിനെ ചേർക്കുമ്പോൾ, ആ വ്യക്തി സ്വന്തം ഇടം സജ്ജീകരിക്കേണ്ടതുണ്ട്."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"മറ്റെല്ലാ ഉപയോക്താക്കൾക്കുമായി ആപ്പുകൾ അപ്‌ഡേറ്റ് ചെയ്യാൻ ഏതൊരു ഉപയോക്താവിനും കഴിയും."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-mn/strings.xml b/packages/CarSystemUI/res/values-mn/strings.xml
deleted file mode 100644
index 33bcd275117d..000000000000
--- a/packages/CarSystemUI/res/values-mn/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Бага"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Их"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Одоо дуугаар танихыг холбогдсон Bluetooth төхөөрөмж удирдана"</string>
- <string name="car_guest" msgid="318393171202663722">"Зочин"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Зочин"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Хэрэглэгч нэмэх"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Шинэ хэрэглэгч"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Та шинэ хэрэглэгч нэмэх үед тухайн хэрэглэгч хувийн орон зайгаа тохируулах шаардлагатай."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Бусад бүх хэрэглэгчийн аппыг дурын хэрэглэгч шинэчлэх боломжтой."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Ачаалж байна"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Хэрэглэгчийг ачаалж байна (<xliff:g id="FROM_USER">%1$d</xliff:g>-с <xliff:g id="TO_USER">%2$d</xliff:g> хүртэл)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Хаах"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-mn/strings_car.xml b/packages/CarSystemUI/res/values-mn/strings_car.xml
deleted file mode 100644
index 9628f7b67294..000000000000
--- a/packages/CarSystemUI/res/values-mn/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Зочин"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Зочин"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Хэрэглэгч нэмэх"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Шинэ хэрэглэгч"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Та шинэ хэрэглэгчийг нэмэх үед тухайн хэрэглэгч хувийн орон зайгаа тохируулах шаардлагатай."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Дурын хэрэглэгч бусад бүх хэрэглэгчийн аппуудыг шинэчлэх боломжтой."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-mr/strings.xml b/packages/CarSystemUI/res/values-mr/strings.xml
deleted file mode 100644
index b1c8a72a04df..000000000000
--- a/packages/CarSystemUI/res/values-mr/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"मि"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"कमाल"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"आता कनेक्ट केलेले ब्लूटूथ डिव्हाइस व्हॉइस रेकग्निशन हाताळते"</string>
- <string name="car_guest" msgid="318393171202663722">"अतिथी"</string>
- <string name="start_guest_session" msgid="497784785761754874">"अतिथी"</string>
- <string name="car_add_user" msgid="4067337059622483269">"वापरकर्ता जोडा"</string>
- <string name="car_new_user" msgid="6637442369728092473">"नवीन वापरकर्ता"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"तुम्ही नवीन वापरकर्ता जोडता तेव्हा त्या व्यक्तीने त्यांची जागा सेट करणे आवश्यक असते."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"कोणताही वापरकर्ता इतर सर्व वापरकर्त्यांसाठी अ‍ॅप्स अपडेट करू शकतो."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"लोड करत आहे"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"वापरकर्ता लोड करत आहे (<xliff:g id="FROM_USER">%1$d</xliff:g> पासून <xliff:g id="TO_USER">%2$d</xliff:g> पर्यंत)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"बंद करा"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-mr/strings_car.xml b/packages/CarSystemUI/res/values-mr/strings_car.xml
deleted file mode 100644
index cf2ad5e344a0..000000000000
--- a/packages/CarSystemUI/res/values-mr/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"अतिथी"</string>
- <string name="start_guest_session" msgid="548879769864070364">"अतिथी"</string>
- <string name="car_add_user" msgid="9196649698797257695">"वापरकर्ता जोडा"</string>
- <string name="car_new_user" msgid="2994965724661108420">"नवीन वापरकर्ता"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"तुम्ही नवीन वापरकर्ता जोडल्यावर, त्या व्यक्तीने त्यांची जागा सेट करणे आवश्यक असते."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"कोणत्याही वापरकर्त्याला इतर सर्व वापरकर्त्यांसाठी अ‍ॅप्स अपडेट करता येतात."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ms/strings.xml b/packages/CarSystemUI/res/values-ms/strings.xml
deleted file mode 100644
index 0bb683b0a58d..000000000000
--- a/packages/CarSystemUI/res/values-ms/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Pengecaman suara kini dikendalikan peranti Bluetooth tersmbg"</string>
- <string name="car_guest" msgid="318393171202663722">"Tetamu"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Tetamu"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Tambah Pengguna"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Pengguna Baharu"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Apabila anda menambahkan pengguna baharu, orang itu perlu menyediakan ruang mereka."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Mana-mana pengguna boleh mengemas kini apl untuk semua pengguna lain."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Memuatkan"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Memuatkan pengguna (daripada <xliff:g id="FROM_USER">%1$d</xliff:g> hingga <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Tutup"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ms/strings_car.xml b/packages/CarSystemUI/res/values-ms/strings_car.xml
deleted file mode 100644
index e846b62465c6..000000000000
--- a/packages/CarSystemUI/res/values-ms/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Tetamu"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Tetamu"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Tambah Pengguna"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Pengguna Baharu"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Apabila anda menambahkan pengguna baharu, orang itu perlu menyediakan ruang mereka."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Mana-mana pengguna boleh mengemas kini apl untuk semua pengguna lain."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-my/strings.xml b/packages/CarSystemUI/res/values-my/strings.xml
deleted file mode 100644
index 4e7ca39a2b12..000000000000
--- a/packages/CarSystemUI/res/values-my/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"နိမ့်"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"မြင့်"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"ချိတ်ထားသော ဘလူးတုသ်စက်ဖြင့် အသံမှတ်သားမှုကို ထိန်းချုပ်သည်"</string>
- <string name="car_guest" msgid="318393171202663722">"ဧည့်သည်"</string>
- <string name="start_guest_session" msgid="497784785761754874">"ဧည့်သည်"</string>
- <string name="car_add_user" msgid="4067337059622483269">"အသုံးပြုသူ ထည့်ရန်"</string>
- <string name="car_new_user" msgid="6637442369728092473">"အသုံးပြုသူ အသစ်"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"အသုံးပြုသူအသစ် ထည့်သည့်အခါ ထိုသူသည် မိမိ၏ နေရာကို စနစ်ထည့်သွင်းရပါမည်။"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"မည်သူမဆို အသုံးပြုသူအားလုံးအတွက် အက်ပ်များကို အပ်ဒိတ်လုပ်နိုင်သည်။"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"ဖွင့်နေသည်"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"အသုံးပြုသူကို ဖွင့်နေသည် (<xliff:g id="FROM_USER">%1$d</xliff:g> မှ <xliff:g id="TO_USER">%2$d</xliff:g> သို့)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"ပိတ်ရန်"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-my/strings_car.xml b/packages/CarSystemUI/res/values-my/strings_car.xml
deleted file mode 100644
index e5e67d146f56..000000000000
--- a/packages/CarSystemUI/res/values-my/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"ဧည့်သည်"</string>
- <string name="start_guest_session" msgid="548879769864070364">"ဧည့်သည်"</string>
- <string name="car_add_user" msgid="9196649698797257695">"အသုံးပြုသူ ထည့်ရန်"</string>
- <string name="car_new_user" msgid="2994965724661108420">"အသုံးပြုသူ အသစ်"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"အသုံးပြုသူအသစ် ထည့်သည့်အခါ ထိုသူသည် မိမိ၏ နေရာကို စနစ်ထည့်သွင်းရပါမည်။"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"အခြားအသုံးပြုသူ အားလုံးအတွက် အက်ပ်များကို မည်သူမဆို အပ်ဒိတ်လုပ်နိုင်သည်။"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-nb/strings.xml b/packages/CarSystemUI/res/values-nb/strings.xml
deleted file mode 100644
index 0b2856f0d7b2..000000000000
--- a/packages/CarSystemUI/res/values-nb/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Talegjenkjenning håndteres nå av tilkoblet Bluetooth-enhet"</string>
- <string name="car_guest" msgid="318393171202663722">"Gjest"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gjest"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Legg til bruker"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Ny bruker"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Når du legger til en ny bruker, må vedkommende konfigurere sitt eget område."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Alle brukere kan oppdatere apper for alle andre brukere."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Laster inn"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Laster inn brukeren (fra <xliff:g id="FROM_USER">%1$d</xliff:g> til <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Lukk"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-nb/strings_car.xml b/packages/CarSystemUI/res/values-nb/strings_car.xml
deleted file mode 100644
index 2c10092d26e7..000000000000
--- a/packages/CarSystemUI/res/values-nb/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gjest"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gjest"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Legg til en bruker"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Ny bruker"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Når du legger til en ny bruker, må vedkommende konfigurere sitt eget område."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Alle brukere kan oppdatere apper for alle andre brukere."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ne/strings.xml b/packages/CarSystemUI/res/values-ne/strings.xml
deleted file mode 100644
index 3a25d6e05db6..000000000000
--- a/packages/CarSystemUI/res/values-ne/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"न्यूनतम"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"अधिकतम"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"अब ब्लुटुथ मार्फत जोडिएको यन्त्रले आवाज पहिचान गर्ने कार्य सम्हाल्छ"</string>
- <string name="car_guest" msgid="318393171202663722">"अतिथि"</string>
- <string name="start_guest_session" msgid="497784785761754874">"अतिथि"</string>
- <string name="car_add_user" msgid="4067337059622483269">"प्रयोगकर्ता थप्नुहोस्"</string>
- <string name="car_new_user" msgid="6637442369728092473">"नयाँ प्रयोगकर्ता"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"तपाईंले नयाँ प्रयोगकर्ता थप्दा ती व्यक्तिले आफ्नो स्थान सेटअप गर्नु पर्छ।"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"सबै प्रयोगकर्ताले अन्य प्रयोगकर्ताका अनुप्रयोगहरू अद्यावधिक गर्न सक्छन्।"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"लोड गरिँदै"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"प्रयोगकर्तासम्बन्धी जानकारी लोड गरिँदै (<xliff:g id="FROM_USER">%1$d</xliff:g> बाट <xliff:g id="TO_USER">%2$d</xliff:g> मा)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"बन्द गर्नुहोस्"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-night/colors.xml b/packages/CarSystemUI/res/values-night/colors.xml
deleted file mode 100644
index a2edd7dc5b4e..000000000000
--- a/packages/CarSystemUI/res/values-night/colors.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <color name="car_accent">#356FE5</color>
- <color name="status_bar_background_color">#ff000000</color>
- <color name="system_bar_background_opaque">#ff0c1013</color>
-
- <!-- The background color of the notification shade -->
- <color name="notification_shade_background_color">#E0000000</color>
-
- <!-- The color of the ripples on the untinted notifications -->
- <color name="notification_ripple_untinted_color">@color/ripple_material_dark</color>
-</resources>
diff --git a/packages/CarSystemUI/res/values-nl/strings.xml b/packages/CarSystemUI/res/values-nl/strings.xml
deleted file mode 100644
index 4765f71b8b61..000000000000
--- a/packages/CarSystemUI/res/values-nl/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Spraakherkenning actief via een verbonden bluetooth-apparaat"</string>
- <string name="car_guest" msgid="318393171202663722">"Gast"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gast"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Gebruiker toevoegen"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Nieuwe gebruiker"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Als je een nieuwe gebruiker toevoegt, moet die persoon een eigen profiel instellen."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Elke gebruiker kan apps updaten voor alle andere gebruikers"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Laden"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Gebruiker laden (van <xliff:g id="FROM_USER">%1$d</xliff:g> naar <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Sluiten"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-nl/strings_car.xml b/packages/CarSystemUI/res/values-nl/strings_car.xml
deleted file mode 100644
index 8f008a621d67..000000000000
--- a/packages/CarSystemUI/res/values-nl/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gast"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gast"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Gebruiker toevoegen"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Nieuwe gebruiker"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Als je een nieuwe gebruiker toevoegt, moet die persoon een eigen profiel instellen."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Elke gebruiker kan apps updaten voor alle andere gebruikers"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-or/strings.xml b/packages/CarSystemUI/res/values-or/strings.xml
deleted file mode 100644
index 4168d5a109b8..000000000000
--- a/packages/CarSystemUI/res/values-or/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"ସର୍ବନିମ୍ନ"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"ସର୍ବାଧିକ"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"ଭଏସ ଚିହ୍ନଟକରଣ ଏବେ ସଂଯୁକ୍ତ ଥିବା ବ୍ଲୁଟୁଥ ଡିଭାଇସ ଦ୍ୱାରା ପରିଚାଳିତ"</string>
- <string name="car_guest" msgid="318393171202663722">"ଅତିଥି"</string>
- <string name="start_guest_session" msgid="497784785761754874">"ଅତିଥି"</string>
- <string name="car_add_user" msgid="4067337059622483269">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କରନ୍ତୁ"</string>
- <string name="car_new_user" msgid="6637442369728092473">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"ଜଣେ ନୂଆ ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କରିବା ବେଳେ ସେହି ବ୍ୟକ୍ତିଙ୍କୁ ତାଙ୍କ ସ୍ଥାନ ସେଟ୍ ଅପ୍ କରିବାର ଆବଶ୍ୟକତା ଅଛି।"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"ଯେ କୌଣସି ଉପଯୋଗକର୍ତ୍ତା ଅନ୍ୟ ସମସ୍ତ ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ ଆପଗୁଡ଼ିକୁ ଅପଡେଟ୍ କରିପାରିବେ।"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"ଲୋଡ୍ କରାଯାଉଛି"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଲୋଡ୍ କରାଯାଉଛି (<xliff:g id="FROM_USER">%1$d</xliff:g>ଙ୍କ ଠାରୁ <xliff:g id="TO_USER">%2$d</xliff:g> ପର୍ଯ୍ୟନ୍ତ)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"ବନ୍ଦ କରନ୍ତୁ"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pa/strings.xml b/packages/CarSystemUI/res/values-pa/strings.xml
deleted file mode 100644
index 3d9d3a597c07..000000000000
--- a/packages/CarSystemUI/res/values-pa/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"ਨਿਊਨਤਮ"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"ਅਧਿਕਤਮ"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"ਅਵਾਜ਼ ਦੀ ਪਛਾਣ ਨੂੰ ਹੁਣ ਕਨੈਕਟ ਕੀਤਾ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸ ਸੰਭਾਲਦਾ ਹੈ"</string>
- <string name="car_guest" msgid="318393171202663722">"ਮਹਿਮਾਨ"</string>
- <string name="start_guest_session" msgid="497784785761754874">"ਮਹਿਮਾਨ"</string>
- <string name="car_add_user" msgid="4067337059622483269">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <string name="car_new_user" msgid="6637442369728092473">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"ਜਦੋਂ ਤੁਸੀਂ ਕੋਈ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਉਸ ਵਿਅਕਤੀ ਨੂੰ ਆਪਣੀ ਜਗ੍ਹਾ ਸੈੱਟਅੱਪ ਕਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"ਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਹੋਰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"ਵਰਤੋਂਕਾਰ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ (<xliff:g id="FROM_USER">%1$d</xliff:g> ਤੋਂ <xliff:g id="TO_USER">%2$d</xliff:g> ਤੱਕ)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"ਬੰਦ ਕਰੋ"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pa/strings_car.xml b/packages/CarSystemUI/res/values-pa/strings_car.xml
deleted file mode 100644
index a15a6a52e9bb..000000000000
--- a/packages/CarSystemUI/res/values-pa/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"ਮਹਿਮਾਨ"</string>
- <string name="start_guest_session" msgid="548879769864070364">"ਮਹਿਮਾਨ"</string>
- <string name="car_add_user" msgid="9196649698797257695">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <string name="car_new_user" msgid="2994965724661108420">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"ਜਦੋਂ ਤੁਸੀਂ ਇੱਕ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਉਸ ਵਿਅਕਤੀ ਨੂੰ ਆਪਣੀ ਜਗ੍ਹਾ ਸੈੱਟਅੱਪ ਕਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"ਕੋਈ ਵੀ ਵਰਤੋਂਕਾਰ ਹੋਰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦਾ ਹੈ।"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pl/strings.xml b/packages/CarSystemUI/res/values-pl/strings.xml
deleted file mode 100644
index 52b90f1b5b96..000000000000
--- a/packages/CarSystemUI/res/values-pl/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Rozpoznawanie mowy przez połączone urządzenie Bluetooth"</string>
- <string name="car_guest" msgid="318393171202663722">"Gość"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gość"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Dodaj użytkownika"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Nowy użytkownik"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Gdy dodasz nowego użytkownika, musi on skonfigurować swój profil."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Każdy użytkownik może aktualizować aplikacje wszystkich innych użytkowników."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Ładuję"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Ładuję użytkownika (od <xliff:g id="FROM_USER">%1$d</xliff:g> do <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Zamknij"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pl/strings_car.xml b/packages/CarSystemUI/res/values-pl/strings_car.xml
deleted file mode 100644
index 0c48dcf6e026..000000000000
--- a/packages/CarSystemUI/res/values-pl/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gość"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gość"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Dodaj użytkownika"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Nowy użytkownik"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Gdy dodasz nowego użytkownika, musi on skonfigurować swój profil."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Każdy użytkownik może aktualizować aplikacje wszystkich innych użytkowników."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pt-rPT/strings.xml b/packages/CarSystemUI/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 2dffa17e8f1c..000000000000
--- a/packages/CarSystemUI/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Mín."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Máx."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Reconhecimento de voz agora através do disp. Bluetooth lig."</string>
- <string name="car_guest" msgid="318393171202663722">"Convidado"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Convidado"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Adicionar utilizador"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Novo utilizador"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Ao adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Qualquer utilizador pode atualizar apps para todos os outros utilizadores."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"A carregar…"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"A carregar o utilizador (de <xliff:g id="FROM_USER">%1$d</xliff:g> para <xliff:g id="TO_USER">%2$d</xliff:g>)…"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Fechar"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pt-rPT/strings_car.xml b/packages/CarSystemUI/res/values-pt-rPT/strings_car.xml
deleted file mode 100644
index 640e5359c371..000000000000
--- a/packages/CarSystemUI/res/values-pt-rPT/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Convidado"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Convidado"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Adicionar utilizador"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Novo utilizador"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Ao adicionar um novo utilizador, essa pessoa tem de configurar o respetivo espaço."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Qualquer utilizador pode atualizar apps para todos os outros utilizadores."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pt/strings.xml b/packages/CarSystemUI/res/values-pt/strings.xml
deleted file mode 100644
index a7c44d2522d6..000000000000
--- a/packages/CarSystemUI/res/values-pt/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Mín"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Máx"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Reconhecimento de voz com dispositivo Bluetooth conectado"</string>
- <string name="car_guest" msgid="318393171202663722">"Convidado"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Convidado"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Adicionar usuário"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Novo usuário"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Quando você adiciona um usuário novo, essa pessoa precisa configurar o espaço dela."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Qualquer usuário pode atualizar apps para os demais usuários."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Carregando"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Carregando usuário (de <xliff:g id="FROM_USER">%1$d</xliff:g> para <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Fechar"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-pt/strings_car.xml b/packages/CarSystemUI/res/values-pt/strings_car.xml
deleted file mode 100644
index 6b53b5be4ea6..000000000000
--- a/packages/CarSystemUI/res/values-pt/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Convidado"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Convidado"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Adicionar usuário"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Novo usuário"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Quando você adiciona um usuário novo, essa pessoa precisa configurar o espaço dela."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Qualquer usuário pode atualizar apps para os demais usuários."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ro/strings.xml b/packages/CarSystemUI/res/values-ro/strings.xml
deleted file mode 100644
index 1a4e71d9eea8..000000000000
--- a/packages/CarSystemUI/res/values-ro/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Recunoașterea vocală acum gestionată de dispozitivul Bluetooth conectat"</string>
- <string name="car_guest" msgid="318393171202663722">"Invitat"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Invitat"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Adăugați un utilizator"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Utilizator nou"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Când adăugați un utilizator nou, acesta trebuie să-și configureze spațiul."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Orice utilizator poate actualiza aplicațiile pentru toți ceilalți utilizatori."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Se încarcă"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Se încarcă utilizatorul (de la <xliff:g id="FROM_USER">%1$d</xliff:g> la <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Închideți"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ro/strings_car.xml b/packages/CarSystemUI/res/values-ro/strings_car.xml
deleted file mode 100644
index 7f4fe7ad7b1d..000000000000
--- a/packages/CarSystemUI/res/values-ro/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Invitat"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Invitat"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Adăugați un utilizator"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Utilizator nou"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Când adăugați un utilizator nou, acesta trebuie să-și configureze spațiul."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Orice utilizator poate actualiza aplicațiile pentru toți ceilalți utilizatori."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ru/strings.xml b/packages/CarSystemUI/res/values-ru/strings.xml
deleted file mode 100644
index 330ba2f0bdbd..000000000000
--- a/packages/CarSystemUI/res/values-ru/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Для распознавания речи используется Bluetooth-устройство."</string>
- <string name="car_guest" msgid="318393171202663722">"Гость"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Гость"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Добавить пользователя"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Новый пользователь"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Когда вы добавите пользователя, ему потребуется настроить профиль."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Любой пользователь устройства может обновлять приложения для всех аккаунтов."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Загрузка…"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Загрузка профиля пользователя (с <xliff:g id="FROM_USER">%1$d</xliff:g> по <xliff:g id="TO_USER">%2$d</xliff:g>)…"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Закрыть"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ru/strings_car.xml b/packages/CarSystemUI/res/values-ru/strings_car.xml
deleted file mode 100644
index 99819dd89d87..000000000000
--- a/packages/CarSystemUI/res/values-ru/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Гость"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Гость"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Добавить пользователя"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Новый пользователь"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Когда вы добавите пользователя, ему потребуется настроить профиль."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Любой пользователь устройства может обновлять приложения для всех аккаунтов."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-si/strings.xml b/packages/CarSystemUI/res/values-si/strings.xml
deleted file mode 100644
index 6391d28e9568..000000000000
--- a/packages/CarSystemUI/res/values-si/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"අවම"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"උපරිම"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"හඬ හැඳුනුම දැන් සම්බන්ධ බ්ලූටූත් උපාංගය මගින් හසුරුවනු ලැබේ"</string>
- <string name="car_guest" msgid="318393171202663722">"අමුත්තා"</string>
- <string name="start_guest_session" msgid="497784785761754874">"අමුත්තා"</string>
- <string name="car_add_user" msgid="4067337059622483269">"පරිශීලක එක් කරන්න"</string>
- <string name="car_new_user" msgid="6637442369728092473">"නව පරිශීලක"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"ඔබ අලුත් පරිශීලකයෙකු එක් කරන විට, එම පුද්ගලයා තමන්ගේ ඉඩ සකසා ගැනීමට අවශ්‍ය වේ."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"සියලුම අනෙක් පරිශීලකයින් සඳහා ඕනෑම පරිශීලකයෙකුට යෙදුම් යාවත්කාලීන කළ හැක."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"පූරණය වෙමින්"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"පරිශීලකයා පූරණය වෙමින් (<xliff:g id="FROM_USER">%1$d</xliff:g> සිට <xliff:g id="TO_USER">%2$d</xliff:g> වෙත)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"වසන්න"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-si/strings_car.xml b/packages/CarSystemUI/res/values-si/strings_car.xml
deleted file mode 100644
index 6444e91f9a2e..000000000000
--- a/packages/CarSystemUI/res/values-si/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"අමුත්තා"</string>
- <string name="start_guest_session" msgid="548879769864070364">"අමුත්තා"</string>
- <string name="car_add_user" msgid="9196649698797257695">"පරිශීලක එක් කරන්න"</string>
- <string name="car_new_user" msgid="2994965724661108420">"නව පරිශීලක"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"ඔබ අලුත් පරිශීලකයෙක් එක් කරන විට, එම පුද්ගලයාට තමන්ගේ ඉඩ සකසා ගැනීමට අවශ්‍ය වේ."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"සියලුම අනෙක් පරිශීලකයින් සඳහා ඕනෑම පරිශීලකයෙකුට යෙදුම් යාවත්කාලීන කළ හැක."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sk/strings.xml b/packages/CarSystemUI/res/values-sk/strings.xml
deleted file mode 100644
index b100a5d4cf5d..000000000000
--- a/packages/CarSystemUI/res/values-sk/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"max."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Rozpoznávanie hlasu teraz prebieha v pripoj. zar. Bluetooth"</string>
- <string name="car_guest" msgid="318393171202663722">"Hosť"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Hosť"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Pridať používateľa"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Nový používateľ"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Keď pridáte nového používateľa, musí si nastaviť vlastný priestor."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Ktorýkoľvek používateľ môže aktualizovať aplikácie všetkých ostatných používateľov."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Načítava sa"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Načítava sa používateľ (predchádzajúci: <xliff:g id="FROM_USER">%1$d</xliff:g>, nasledujúci: <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Zavrieť"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sk/strings_car.xml b/packages/CarSystemUI/res/values-sk/strings_car.xml
deleted file mode 100644
index c058a32c1669..000000000000
--- a/packages/CarSystemUI/res/values-sk/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Hosť"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Hosť"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Pridať používateľa"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Nový používateľ"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Keď pridáte nového používateľa, musí si nastaviť vlastný priestor."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Akýkoľvek používateľ môže aktualizovať aplikácie všetkých ostatných používateľov."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sl/strings.xml b/packages/CarSystemUI/res/values-sl/strings.xml
deleted file mode 100644
index b67002bec7d4..000000000000
--- a/packages/CarSystemUI/res/values-sl/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Najn."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Najv."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Prepoznavanje glasu zdaj izvaja povezana naprava Bluetooth"</string>
- <string name="car_guest" msgid="318393171202663722">"Gost"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gost"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Dodaj uporabnika"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Nov uporabnik"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Ko dodate novega uporabnika, mora ta nastaviti svoj prostor."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Vsak uporabnik lahko posodobi aplikacije za vse druge uporabnike."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Nalaganje"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Nalaganje uporabnika (od uporabnika <xliff:g id="FROM_USER">%1$d</xliff:g> do uporabnika <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Zapri"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sl/strings_car.xml b/packages/CarSystemUI/res/values-sl/strings_car.xml
deleted file mode 100644
index b8324e0211d2..000000000000
--- a/packages/CarSystemUI/res/values-sl/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gost"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gost"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Dodaj uporabnika"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Nov uporabnik"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Ko dodate novega uporabnika, mora ta nastaviti svoj prostor."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Vsak uporabnik lahko posodobi aplikacije za vse druge uporabnike."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sq/strings.xml b/packages/CarSystemUI/res/values-sq/strings.xml
deleted file mode 100644
index d19e1583664b..000000000000
--- a/packages/CarSystemUI/res/values-sq/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Njohja zanore trajtohet nga pajisja me Bluetooth-in e lidhur"</string>
- <string name="car_guest" msgid="318393171202663722">"I ftuar"</string>
- <string name="start_guest_session" msgid="497784785761754874">"I ftuar"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Shto përdorues"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Përdorues i ri"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kur shton një përdorues të ri, ai person duhet të konfigurojë hapësirën e vet."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Çdo përdorues mund t\'i përditësojë aplikacionet për të gjithë përdoruesit e tjerë."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Po ngarkohet"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Përdoruesi po ngarkohet (nga <xliff:g id="FROM_USER">%1$d</xliff:g> te <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Mbyll"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sq/strings_car.xml b/packages/CarSystemUI/res/values-sq/strings_car.xml
deleted file mode 100644
index 7e676ba03641..000000000000
--- a/packages/CarSystemUI/res/values-sq/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"I ftuar"</string>
- <string name="start_guest_session" msgid="548879769864070364">"I ftuar"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Shto përdorues"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Përdorues i ri"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Kur shton një përdorues të ri, ai person duhet të konfigurojë hapësirën e vet."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Çdo përdorues mund t\'i përditësojë aplikacionet për të gjithë përdoruesit e tjerë."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sr/strings.xml b/packages/CarSystemUI/res/values-sr/strings.xml
deleted file mode 100644
index a5fb5b4f6ad6..000000000000
--- a/packages/CarSystemUI/res/values-sr/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Мин."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maкс."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Препознавањем гласа сада управља повезани Bluetooth уређај"</string>
- <string name="car_guest" msgid="318393171202663722">"Гост"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Гост"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Додај корисника"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Нови корисник"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Када додате новог корисника, та особа треба да подеси свој простор."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Сваки корисник може да ажурира апликације за све остале кориснике."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Учитава се"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Профил корисника се учитава (из<xliff:g id="FROM_USER">%1$d</xliff:g> у <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Затвори"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sr/strings_car.xml b/packages/CarSystemUI/res/values-sr/strings_car.xml
deleted file mode 100644
index 4d23fdbb7ca3..000000000000
--- a/packages/CarSystemUI/res/values-sr/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Гост"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Гост"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Додај корисника"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Нови корисник"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Када додате новог корисника, та особа треба да подеси свој простор."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Сваки корисник може да ажурира апликације за све остале кориснике."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sv/strings.xml b/packages/CarSystemUI/res/values-sv/strings.xml
deleted file mode 100644
index 8a942d6af080..000000000000
--- a/packages/CarSystemUI/res/values-sv/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Nu hanteras röstigenkänning via en anstluten Bluetooth-enhet"</string>
- <string name="car_guest" msgid="318393171202663722">"Gäst"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Gäst"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Lägg till användare"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Ny användare"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"När du lägger till en ny användare måste den personen konfigurera sitt utrymme."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Alla användare kan uppdatera appar för andra användare."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Läser in"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Läser in användare (från <xliff:g id="FROM_USER">%1$d</xliff:g> till <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Stäng"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sv/strings_car.xml b/packages/CarSystemUI/res/values-sv/strings_car.xml
deleted file mode 100644
index 36fcdaa6f92e..000000000000
--- a/packages/CarSystemUI/res/values-sv/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Gäst"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Gäst"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Lägg till användare"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Ny användare"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"När du lägger till en ny användare måste den personen konfigurera sitt utrymme."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Alla användare kan uppdatera appar för andra användare."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sw/strings.xml b/packages/CarSystemUI/res/values-sw/strings.xml
deleted file mode 100644
index be03373c48a1..000000000000
--- a/packages/CarSystemUI/res/values-sw/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Chini"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Juu"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Utambuzi wa sauti sasa unashughulikiwa na kifaa kilichounganishwa cha Bluetooth"</string>
- <string name="car_guest" msgid="318393171202663722">"Mgeni"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Mgeni"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Ongeza Mtumiaji"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Mtumiaji Mpya"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Ukiongeza mtumiaji mpya, ni lazima aweke kikundi chake."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Mtumiaji yeyote anaweza kusasisha programu za watumiaji wengine."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Inapakia"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Inapakia wasifu wa mtumiaji (kutoka <xliff:g id="FROM_USER">%1$d</xliff:g> kuwa <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Funga"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-sw/strings_car.xml b/packages/CarSystemUI/res/values-sw/strings_car.xml
deleted file mode 100644
index 75573d7ed19d..000000000000
--- a/packages/CarSystemUI/res/values-sw/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Mgeni"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Mgeni"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Weka Mtumiaji"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Mtumiaji Mpya"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Ukiongeza mtumiaji mpya, ni lazima aweke kikundi chake."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Mtumiaji yeyote anaweza kusasisha programu za watumiaji wengine wote."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ta/strings.xml b/packages/CarSystemUI/res/values-ta/strings.xml
deleted file mode 100644
index a82a2f856bd4..000000000000
--- a/packages/CarSystemUI/res/values-ta/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"குறைந்தபட்சம்"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"அதிகபட்சம்"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"இணைக்கப்பட்ட புளூடூத் சாதனத்தால் \'குரல் அறிதல்\' கையாளப்படுகிறது"</string>
- <string name="car_guest" msgid="318393171202663722">"கெஸ்ட்"</string>
- <string name="start_guest_session" msgid="497784785761754874">"கெஸ்ட்"</string>
- <string name="car_add_user" msgid="4067337059622483269">"பயனரைச் சேருங்கள்"</string>
- <string name="car_new_user" msgid="6637442369728092473">"புதிய பயனர்"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"புதிய பயனரைச் சேர்க்கும்போது அவர் தனக்கான சேமிப்பிடத்தை அமைக்க வேண்டும்."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"எந்தப் பயனரும் பிற பயனர்கள் சார்பாக ஆப்ஸைப் புதுப்பிக்க முடியும்."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"ஏற்றுகிறது"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"பயனர் தகவலை ஏற்றுகிறது (<xliff:g id="FROM_USER">%1$d</xliff:g>லிருந்து <xliff:g id="TO_USER">%2$d</xliff:g> வரை)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"மூடுக"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-te/strings.xml b/packages/CarSystemUI/res/values-te/strings.xml
deleted file mode 100644
index cf74f8053349..000000000000
--- a/packages/CarSystemUI/res/values-te/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"కని."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"గరి."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"నేడు వాయిస్ గుర్తింపును కనెక్ట్ అయిన బ్లూటూత్ నిర్వహిస్తోంది"</string>
- <string name="car_guest" msgid="318393171202663722">"గెస్ట్"</string>
- <string name="start_guest_session" msgid="497784785761754874">"గెస్ట్"</string>
- <string name="car_add_user" msgid="4067337059622483269">"యూజర్‌ను జోడించండి"</string>
- <string name="car_new_user" msgid="6637442369728092473">"కొత్త యూజర్"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"మీరు కొత్త యూజర్‌ను జోడించినప్పుడు, ఆ వ్యక్తి తన స్పేస్‌ను సెటప్ చేసుకోవాలి."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"ఏ యూజర్ అయినా మిగతా యూజర్‌ల కోసం యాప్‌లను అప్‌డేట్ చేయవచ్చు."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"లోడ్ అవుతోంది"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"యూజర్‌ను లోడ్ చేస్తోంది (<xliff:g id="FROM_USER">%1$d</xliff:g> నుండి <xliff:g id="TO_USER">%2$d</xliff:g> వరకు)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"మూసివేయి"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-te/strings_car.xml b/packages/CarSystemUI/res/values-te/strings_car.xml
deleted file mode 100644
index 7f0d090c9438..000000000000
--- a/packages/CarSystemUI/res/values-te/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"గెస్ట్"</string>
- <string name="start_guest_session" msgid="548879769864070364">"గెస్ట్"</string>
- <string name="car_add_user" msgid="9196649698797257695">"యూజర్‌ను జోడించండి"</string>
- <string name="car_new_user" msgid="2994965724661108420">"కొత్త యూజర్"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"మీరు కొత్త యూజర్‌ను జోడించినప్పుడు, ఆ వ్యక్తి తన ప్రదేశాన్ని సెటప్ చేసుకోవాలి."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"ఏ యూజర్ అయినా మిగతా అందరు యూజర్‌ల కోసం యాప్‌లను అప్‌డేట్ చేయవచ్చు."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-th/strings.xml b/packages/CarSystemUI/res/values-th/strings.xml
deleted file mode 100644
index dacf605888f5..000000000000
--- a/packages/CarSystemUI/res/values-th/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"ตอนนี้อุปกรณ์บลูทูธที่เชื่อมต่อจะจัดการการจดจำเสียง"</string>
- <string name="car_guest" msgid="318393171202663722">"ผู้ใช้ชั่วคราว"</string>
- <string name="start_guest_session" msgid="497784785761754874">"ผู้ใช้ชั่วคราว"</string>
- <string name="car_add_user" msgid="4067337059622483269">"เพิ่มผู้ใช้"</string>
- <string name="car_new_user" msgid="6637442369728092473">"ผู้ใช้ใหม่"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"เมื่อคุณเพิ่มผู้ใช้ใหม่ ผู้ใช้ดังกล่าวจะต้องตั้งค่าพื้นที่ของตนเอง"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"ผู้ใช้ทุกคนจะอัปเดตแอปให้แก่ผู้ใช้คนอื่นๆ ได้"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"กำลังโหลด"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"กำลังโหลดผู้ใช้ (จาก <xliff:g id="FROM_USER">%1$d</xliff:g> ถึง <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"ปิด"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-th/strings_car.xml b/packages/CarSystemUI/res/values-th/strings_car.xml
deleted file mode 100644
index 8e47499509b6..000000000000
--- a/packages/CarSystemUI/res/values-th/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"ผู้ใช้ชั่วคราว"</string>
- <string name="start_guest_session" msgid="548879769864070364">"ผู้ใช้ชั่วคราว"</string>
- <string name="car_add_user" msgid="9196649698797257695">"เพิ่มผู้ใช้"</string>
- <string name="car_new_user" msgid="2994965724661108420">"ผู้ใช้ใหม่"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"เมื่อคุณเพิ่มผู้ใช้ใหม่ ผู้ใช้ดังกล่าวจะต้องตั้งค่าพื้นที่ของตนเอง"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"ผู้ใช้ทุกคนจะอัปเดตแอปให้ผู้ใช้คนอื่นๆ ได้"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-tl/strings.xml b/packages/CarSystemUI/res/values-tl/strings.xml
deleted file mode 100644
index 89d8cd201e5f..000000000000
--- a/packages/CarSystemUI/res/values-tl/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Minuto"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Max"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Hawak na ngayon ng Bluetooth device ang Pagkilala ng boses"</string>
- <string name="car_guest" msgid="318393171202663722">"Bisita"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Bisita"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Magdagdag ng User"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Bagong User"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Kapag nagdagdag ka ng bagong user, kailangang i-set up ng taong iyon ang kanyang espasyo."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Puwedeng i-update ng sinumang user ang mga app para sa lahat ng iba pang user."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Naglo-load"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Nilo-load ang user (mula kay <xliff:g id="FROM_USER">%1$d</xliff:g> papunta kay <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Isara"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-tl/strings_car.xml b/packages/CarSystemUI/res/values-tl/strings_car.xml
deleted file mode 100644
index b8a44e671043..000000000000
--- a/packages/CarSystemUI/res/values-tl/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Bisita"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Bisita"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Magdagdag ng User"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Bagong User"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Kapag nagdagdag ka ng bagong user, kailangang i-set up ng taong iyon ang kanyang espasyo."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Puwedeng i-update ng sinumang user ang mga app para sa lahat ng iba pang user."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-tr/strings.xml b/packages/CarSystemUI/res/values-tr/strings.xml
deleted file mode 100644
index 36bf694f30ab..000000000000
--- a/packages/CarSystemUI/res/values-tr/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Min."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Artık ses tanıma, bağlı Bluetooth cihazı tarafından işleniyor"</string>
- <string name="car_guest" msgid="318393171202663722">"Misafir"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Misafir"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Kullanıcı Ekle"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Yeni Kullanıcı"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Yeni kullanıcı eklediğinizde, bu kişinin alanını ayarlaması gerekir."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Herhangi bir kullanıcı, diğer tüm kullanıcılar için uygulamaları güncelleyebilir."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Yükleniyor"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Kullanıcı yükleniyor (<xliff:g id="FROM_USER">%1$d</xliff:g> kullanıcısından <xliff:g id="TO_USER">%2$d</xliff:g> kullanıcısına)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Kapat"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-tr/strings_car.xml b/packages/CarSystemUI/res/values-tr/strings_car.xml
deleted file mode 100644
index c59aff84e0db..000000000000
--- a/packages/CarSystemUI/res/values-tr/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Misafir"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Misafir"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Kullanıcı Ekle"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Yeni Kullanıcı"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Yeni kullanıcı eklediğinizde, bu kişinin alanını ayarlaması gerekir."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Herhangi bir kullanıcı, diğer tüm kullanıcılar için uygulamaları güncelleyebilir."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-uk/strings.xml b/packages/CarSystemUI/res/values-uk/strings.xml
deleted file mode 100644
index 391513f1b57a..000000000000
--- a/packages/CarSystemUI/res/values-uk/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Мін."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Макс."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Голос розпізнається через підключений пристрій Bluetooth"</string>
- <string name="car_guest" msgid="318393171202663722">"Гість"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Гість"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Додати користувача"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Новий користувач"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Коли ви додаєте нового користувача, він має налаштувати свій профіль."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Усі користувачі можуть оновлювати додатки для решти людей."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Завантаження"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Завантаження профілю користувача (від <xliff:g id="FROM_USER">%1$d</xliff:g> до <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Закрити"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-uk/strings_car.xml b/packages/CarSystemUI/res/values-uk/strings_car.xml
deleted file mode 100644
index b1aee0d81258..000000000000
--- a/packages/CarSystemUI/res/values-uk/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Гість"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Гість"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Додати користувача"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Новий користувач"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Коли ви додаєте нового користувача, він має налаштувати свій профіль."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Будь-який користувач може оновлювати додатки для решти людей."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-ur/strings.xml b/packages/CarSystemUI/res/values-ur/strings.xml
deleted file mode 100644
index abe9214181a2..000000000000
--- a/packages/CarSystemUI/res/values-ur/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"کم از کم"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"زیادہ سے زیادہ"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"آواز کی شناخت اب منسلک کردہ بلوٹوتھ آلے سے ہوتی ہے"</string>
- <string name="car_guest" msgid="318393171202663722">"مہمان"</string>
- <string name="start_guest_session" msgid="497784785761754874">"مہمان"</string>
- <string name="car_add_user" msgid="4067337059622483269">"صارف شامل کریں"</string>
- <string name="car_new_user" msgid="6637442369728092473">"نیا صارف"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"جب آپ ایک نیا صارف شامل کرتے ہیں تو اس شخص کو اپنی جگہ سیٹ کرنی ہوتی ہے۔"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"کوئی بھی صارف دیگر سبھی صارفین کے لیے ایپس کو اپ ڈیٹ کر سکتا ہے۔"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"لوڈ ہو رہی ہے"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"صارف کی نئی پروفائل لوڈ ہو رہی ہے (<xliff:g id="FROM_USER">%1$d</xliff:g> سے <xliff:g id="TO_USER">%2$d</xliff:g> کو)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"بند کریں"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-uz/strings.xml b/packages/CarSystemUI/res/values-uz/strings.xml
deleted file mode 100644
index 398d1f5ce29e..000000000000
--- a/packages/CarSystemUI/res/values-uz/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Daq."</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Maks."</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Endi ovozni tanish Bluetooth qurilma ulanganda amalga oshadi"</string>
- <string name="car_guest" msgid="318393171202663722">"Mehmon"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Mehmon"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Foydalanuvchi kiritish"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Yangi foydalanuvchi"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Yangi profil kiritilgach, uni sozlash lozim."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Qurilmaning istalgan foydalanuvchisi ilovalarni barcha hisoblar uchun yangilashi mumkin."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Yuklanmoqda"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Foydalanuvchi profili yuklanmoqda (<xliff:g id="FROM_USER">%1$d</xliff:g> – <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Yopish"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-uz/strings_car.xml b/packages/CarSystemUI/res/values-uz/strings_car.xml
deleted file mode 100644
index eb4712cc96b4..000000000000
--- a/packages/CarSystemUI/res/values-uz/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Mehmon"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Mehmon"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Foydalanuvchi kiritish"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Yangi foydalanuvchi"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Yangi profil kiritilgach, uni sozlash lozim."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Qurilmaning istalgan foydalanuvchisi ilovalarni barcha hisoblar uchun yangilashi mumkin."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-vi/strings.xml b/packages/CarSystemUI/res/values-vi/strings.xml
deleted file mode 100644
index f15320fd1dcd..000000000000
--- a/packages/CarSystemUI/res/values-vi/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Tối thiểu"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Tối đa"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Thiết bị Bluetooth được kết nối đang xử lý vấn đề nhận dạng giọng nói"</string>
- <string name="car_guest" msgid="318393171202663722">"Khách"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Khách"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Thêm người dùng"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Người dùng mới"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Khi bạn thêm một người dùng mới, người đó cần thiết lập không gian của mình."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Bất kỳ người dùng nào cũng có thể cập nhật ứng dụng cho tất cả những người dùng khác."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Đang tải"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Đang tải hồ sơ người dùng (từ <xliff:g id="FROM_USER">%1$d</xliff:g> sang <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Đóng"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-vi/strings_car.xml b/packages/CarSystemUI/res/values-vi/strings_car.xml
deleted file mode 100644
index 452257a43b45..000000000000
--- a/packages/CarSystemUI/res/values-vi/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Khách"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Bắt đầu phiên khách"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Thêm người dùng"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Người dùng mới"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Khi bạn thêm một người dùng mới, họ cần thiết lập không gian của mình."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Bất kỳ người dùng nào cũng có thể cập nhật ứng dụng cho tất cả những người dùng khác."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zh-rCN/strings.xml b/packages/CarSystemUI/res/values-zh-rCN/strings.xml
deleted file mode 100644
index a91f48c8b378..000000000000
--- a/packages/CarSystemUI/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"最小"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"最大"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"现在由已连接的蓝牙设备处理语音识别操作"</string>
- <string name="car_guest" msgid="318393171202663722">"访客"</string>
- <string name="start_guest_session" msgid="497784785761754874">"访客"</string>
- <string name="car_add_user" msgid="4067337059622483269">"添加用户"</string>
- <string name="car_new_user" msgid="6637442369728092473">"新用户"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"当您添加新用户时,该用户需要自行设置个人空间。"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"任何用户均可为所有其他用户更新应用。"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"正在加载"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"正在加载用户(从 <xliff:g id="FROM_USER">%1$d</xliff:g> 到 <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"关闭"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zh-rCN/strings_car.xml b/packages/CarSystemUI/res/values-zh-rCN/strings_car.xml
deleted file mode 100644
index d8aea67993a2..000000000000
--- a/packages/CarSystemUI/res/values-zh-rCN/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"访客"</string>
- <string name="start_guest_session" msgid="548879769864070364">"访客"</string>
- <string name="car_add_user" msgid="9196649698797257695">"添加用户"</string>
- <string name="car_new_user" msgid="2994965724661108420">"新用户"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"当您添加新用户后,该用户需要自行设置个人空间。"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"任何用户都可以为所有其他用户更新应用。"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zh-rHK/strings.xml b/packages/CarSystemUI/res/values-zh-rHK/strings.xml
deleted file mode 100644
index 7aa611606274..000000000000
--- a/packages/CarSystemUI/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"最小"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"最大"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"現在由已連線的藍牙裝置處理語音辨識作業"</string>
- <string name="car_guest" msgid="318393171202663722">"訪客"</string>
- <string name="start_guest_session" msgid="497784785761754874">"訪客"</string>
- <string name="car_add_user" msgid="4067337059622483269">"新增使用者"</string>
- <string name="car_new_user" msgid="6637442369728092473">"新使用者"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"新增的使用者需要自行設定個人空間。"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"任何使用者都可以為所有其他使用者更新應用程式。"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"正在載入"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"正在載入使用者 (由 <xliff:g id="FROM_USER">%1$d</xliff:g> 至 <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"關閉"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zh-rHK/strings_car.xml b/packages/CarSystemUI/res/values-zh-rHK/strings_car.xml
deleted file mode 100644
index 1970ec96b276..000000000000
--- a/packages/CarSystemUI/res/values-zh-rHK/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"訪客"</string>
- <string name="start_guest_session" msgid="548879769864070364">"訪客"</string>
- <string name="car_add_user" msgid="9196649698797257695">"新增使用者"</string>
- <string name="car_new_user" msgid="2994965724661108420">"新使用者"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"你新增的使用者必須自行設定個人空間。"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"任何使用者皆可為所有其他使用者更新應用程式。"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zh-rTW/strings.xml b/packages/CarSystemUI/res/values-zh-rTW/strings.xml
deleted file mode 100644
index c062463905d7..000000000000
--- a/packages/CarSystemUI/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"最小"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"最大"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"現在由已連線的藍牙裝置處理語音辨識作業"</string>
- <string name="car_guest" msgid="318393171202663722">"訪客"</string>
- <string name="start_guest_session" msgid="497784785761754874">"訪客"</string>
- <string name="car_add_user" msgid="4067337059622483269">"新增使用者"</string>
- <string name="car_new_user" msgid="6637442369728092473">"新使用者"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"新使用者必須自行設定個人空間。"</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"任何使用者都能為所有其他使用者更新應用程式。"</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"載入中"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"正在載入使用者 (從 <xliff:g id="FROM_USER">%1$d</xliff:g> 到 <xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"關閉"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zh-rTW/strings_car.xml b/packages/CarSystemUI/res/values-zh-rTW/strings_car.xml
deleted file mode 100644
index 1970ec96b276..000000000000
--- a/packages/CarSystemUI/res/values-zh-rTW/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"訪客"</string>
- <string name="start_guest_session" msgid="548879769864070364">"訪客"</string>
- <string name="car_add_user" msgid="9196649698797257695">"新增使用者"</string>
- <string name="car_new_user" msgid="2994965724661108420">"新使用者"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"你新增的使用者必須自行設定個人空間。"</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"任何使用者皆可為所有其他使用者更新應用程式。"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zu/strings.xml b/packages/CarSystemUI/res/values-zu/strings.xml
deleted file mode 100644
index 2dd33d827324..000000000000
--- a/packages/CarSystemUI/res/values-zu/strings.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="hvac_min_text" msgid="8167124789068494624">"Okuncane"</string>
- <string name="hvac_max_text" msgid="3669693372074755551">"Okuningi"</string>
- <string name="voice_recognition_toast" msgid="1149934534584052842">"Ukubonwa kwezwi manje kuphethwe idivayisi exhunyiwe ye-Bluetooth"</string>
- <string name="car_guest" msgid="318393171202663722">"Isihambeli"</string>
- <string name="start_guest_session" msgid="497784785761754874">"Isihambeli"</string>
- <string name="car_add_user" msgid="4067337059622483269">"Engeza umsebenzisi"</string>
- <string name="car_new_user" msgid="6637442369728092473">"Umsebenzisi omusha"</string>
- <string name="user_add_user_message_setup" msgid="1035578846007352323">"Uma ungeza umsebenzisi omusha, loyo muntu udinga ukusetha izikhala zakhe."</string>
- <string name="user_add_user_message_update" msgid="7061671307004867811">"Noma yimuphi umsebenzisi angabuyekeza izinhlelo zokusebenza zabanye abasebenzisi."</string>
- <string name="car_loading_profile" msgid="4507385037552574474">"Iyalayisha"</string>
- <string name="car_loading_profile_developer_message" msgid="1660962766911529611">"Ilayisha umsebenzisi (kusuka ku-<xliff:g id="FROM_USER">%1$d</xliff:g> kuya ku-<xliff:g id="TO_USER">%2$d</xliff:g>)"</string>
- <string name="rear_view_camera_close_button_text" msgid="8430918817320533693">"Vala"</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values-zu/strings_car.xml b/packages/CarSystemUI/res/values-zu/strings_car.xml
deleted file mode 100644
index 1f8227d8622a..000000000000
--- a/packages/CarSystemUI/res/values-zu/strings_car.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="car_guest" msgid="1125545940563459016">"Isihambeli"</string>
- <string name="start_guest_session" msgid="548879769864070364">"Isihambeli"</string>
- <string name="car_add_user" msgid="9196649698797257695">"Engeza umsebenzisi"</string>
- <string name="car_new_user" msgid="2994965724661108420">"Umsebenzisi omusha"</string>
- <string name="user_add_user_message_setup" msgid="116571509380700718">"Uma ungeza umsebenzisi omusha, loyo muntu udinga ukusetha izikhala zakhe."</string>
- <string name="user_add_user_message_update" msgid="537998123816022363">"Noma yimuphi umsebenzisi angabuyekeza izinhlelo zokusebenza zabanye abasebenzisi."</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values/attrs.xml b/packages/CarSystemUI/res/values/attrs.xml
deleted file mode 100644
index 788376494032..000000000000
--- a/packages/CarSystemUI/res/values/attrs.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright 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.
- -->
-
-<resources>
- <attr name="icon" format="reference"/>
- <attr name="selectedIcon" format="reference"/>
- <attr name="intent" format="string"/>
- <attr name="longIntent" format="string"/>
- <attr name="selectedAlpha" format="float" />
- <attr name="unselectedAlpha" format="float" />
-
- <!-- Custom attributes to configure hvac values -->
- <declare-styleable name="AnimatedTemperatureView">
- <attr name="hvacAreaId" format="integer"/>
- <attr name="hvacPropertyId" format="integer"/>
- <attr name="hvacTempFormat" format="string"/>
- <!-- how far away the animations should center around -->
- <attr name="hvacPivotOffset" format="dimension"/>
- <attr name="hvacMinValue" format="float"/>
- <attr name="hvacMaxValue" format="float"/>
- <attr name="hvacMinText" format="string|reference"/>
- <attr name="hvacMaxText" format="string|reference"/>
- <attr name="android:gravity"/>
- <attr name="android:minEms"/>
- <attr name="android:textAppearance"/>
- </declare-styleable>
-
- <!-- Allow for custom attribs to be added to a nav button -->
- <declare-styleable name="CarNavigationButton">
- <!-- intent to start when button is click -->
- <attr name="intent" />
- <!-- intent to start when a long press has happened -->
- <attr name="longIntent" />
- <!-- start the intent as a broad cast instead of an activity if true-->
- <attr name="broadcast" format="boolean"/>
- <!-- Alpha value to used when in selected state. Defaults 1f -->
- <attr name="selectedAlpha" />
- <!-- Alpha value to used when in un-selected state. Defaults 0.7f -->
- <attr name="unselectedAlpha" />
- <!-- icon to be rendered when in selected state -->
- <attr name="selectedIcon" />
- <!-- icon to be rendered (drawable) -->
- <attr name="icon"/>
- <!-- categories that will be added as extras to the fired intents -->
- <attr name="categories" format="string"/>
- <!-- package names that will be added as extras to the fired intents -->
- <attr name="packages" format="string" />
- <!-- componentName names that will be used for detecting selected state -->
- <attr name="componentNames" format="string" />
- <!-- whether to highlight the button when selected. Defaults false -->
- <attr name="showMoreWhenSelected" format="boolean" />
- <!-- whether to highlight the button when selected. Defaults false -->
- <attr name="highlightWhenSelected" format="boolean" />
- <!-- whether to show the icon of the app currently associated this button's role. Only
- relevant for buttons associated to specific roles (e.g.: AssistantButton).
- Defaults false -->
- <attr name="useDefaultAppIconForRole" format="boolean"/>
- </declare-styleable>
-
- <!-- Custom attributes to configure hvac values -->
- <declare-styleable name="TemperatureView">
- <attr name="hvacAreaId" format="integer"/>
- <attr name="hvacPropertyId" format="integer"/>
- <attr name="hvacTempFormat" format="string"/>
- </declare-styleable>
-
- <declare-styleable name="carVolumeItems"/>
- <declare-styleable name="carVolumeItems_item">
- <!-- Align with AudioAttributes.USAGE_* -->
- <attr name="usage">
- <enum name="unknown" value="0"/>
- <enum name="media" value="1"/>
- <enum name="voice_communication" value="2"/>
- <enum name="voice_communication_signalling" value="3"/>
- <enum name="alarm" value="4"/>
- <enum name="notification" value="5"/>
- <enum name="notification_ringtone" value="6"/>
- <enum name="notification_communication_request" value="7"/>
- <enum name="notification_communication_instant" value="8"/>
- <enum name="notification_communication_delayed" value="9"/>
- <enum name="notification_event" value="10"/>
- <enum name="assistance_accessibility" value="11"/>
- <enum name="assistance_navigation_guidance" value="12"/>
- <enum name="assistance_sonification" value="13"/>
- <enum name="game" value="14"/>
- <!-- hidden, do not use -->
- <!-- enum name="virtual_source" value="15"/ -->
- <enum name="assistant" value="16"/>
- <enum name="call_assistant" value="17"/>
- <enum name="emergency" value="1000"/>
- <enum name="safety" value="1001"/>
- <enum name="vehicle_status" value="1002"/>
- <enum name="announcement" value="1003"/>
- </attr>
-
- <!-- Icon resource ids to render on UI -->
- <attr name="icon" />
- </declare-styleable>
-</resources>
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
deleted file mode 100644
index 91d416623538..000000000000
--- a/packages/CarSystemUI/res/values/colors.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- colors for user switcher -->
- <color name="car_user_switcher_background_color">#000000</color>
- <color name="car_user_switcher_name_text_color">@*android:color/car_body1_light</color>
- <color name="car_user_switcher_add_user_background_color">#131313</color>
- <color name="car_user_switcher_add_user_add_sign_color">@*android:color/car_body1_light</color>
- <color name="car_nav_icon_fill_color">#8F8F8F</color>
- <color name="car_nav_icon_fill_color_selected">#ffffff</color>
- <!-- colors for seekbar -->
- <color name="car_seekbar_track_background">#131315</color>
- <color name="car_seekbar_track_secondary_progress">@*android:color/car_accent</color>
- <!-- colors for volume dialog tint -->
- <color name="car_volume_dialog_tint">@*android:color/car_tint</color>
-
- <color name="docked_divider_background">@*android:color/car_grey_50</color>
- <color name="system_bar_background_opaque">#ff172026</color>
-
- <!-- colors for status bar -->
- <color name="system_bar_background_pill_color">#282A2D</color>
- <color name="system_bar_icon_color">#FFFFFF</color>
- <color name="system_bar_text_color">#FFFFFF</color>
- <color name="status_bar_background_color">#33000000</color>
- <drawable name="system_bar_background">@color/status_bar_background_color</drawable>
-
- <!-- colors for hvac temperature view -->
- <color name="hvac_temperature_adjust_button_color">#3C4043</color>
- <color name="hvac_temperature_decrease_arrow_color">#8AB4F8</color>
- <color name="hvac_temperature_increase_arrow_color">#F28B82</color>
-
- <!-- The background color of the notification shade -->
- <color name="notification_shade_background_color">#D6000000</color>
-
- <!-- The background color of the car volume dialog -->
- <color name="car_volume_dialog_background_color">@color/system_bar_background_opaque</color>
-
- <!-- The color of the dividing line between grouped notifications. -->
- <color name="notification_divider_color">@*android:color/notification_action_list</color>
-
- <!-- The color for the unseen indicator. -->
- <color name="car_nav_unseen_indicator_color">#e25142</color>
-
- <!-- The color of the ripples on the untinted notifications -->
- <color name="notification_ripple_untinted_color">@color/ripple_material_light</color>
-
- <color name="keyguard_button_text_color">@android:color/black</color>
-
- <color name="list_divider_color">@*android:color/car_list_divider_light</color>
- <color name="car_volume_item_divider_color">@*android:color/car_list_divider</color>
- <color name="car_volume_item_background_color">@*android:color/car_card_dark</color>
-
- <color name="car_user_switching_dialog_background_color">@android:color/black</color>
- <color name="car_user_switching_dialog_loading_text_color">@*android:color/car_body1</color>
-
- <color name="rear_view_camera_button_background">@*android:color/car_card_dark</color>
-</resources>
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
deleted file mode 100644
index b6179edfb063..000000000000
--- a/packages/CarSystemUI/res/values/config.xml
+++ /dev/null
@@ -1,166 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<resources>
- <string name="config_statusBarComponent" translatable="false">
- com.android.systemui.statusbar.car.CarStatusBar
- </string>
- <string name="config_systemUIFactoryComponent" translatable="false">
- com.android.systemui.CarSystemUIFactory
- </string>
-
- <bool name="config_enableFullscreenUserSwitcher">true</bool>
-
- <!-- Configure which system bars should be displayed. -->
- <bool name="config_enableTopNavigationBar">true</bool>
- <bool name="config_enableLeftNavigationBar">false</bool>
- <bool name="config_enableRightNavigationBar">false</bool>
- <bool name="config_enableBottomNavigationBar">true</bool>
-
- <!-- Configure the type of each system bar. Each system bar must have a unique type. -->
- <!-- STATUS_BAR = 0-->
- <!-- NAVIGATION_BAR = 1-->
- <!-- STATUS_BAR_EXTRA = 2-->
- <!-- NAVIGATION_BAR_EXTRA = 3-->
- <integer name="config_topSystemBarType">0</integer>
- <integer name="config_leftSystemBarType">2</integer>
- <integer name="config_rightSystemBarType">3</integer>
- <integer name="config_bottomSystemBarType">1</integer>
-
- <!-- Configure the relative z-order among the system bars. When two system bars overlap (e.g.
- if both top bar and left bar are enabled, it creates an overlapping space in the upper left
- corner), the system bar with the higher z-order takes the overlapping space and padding is
- applied to the other bar.-->
- <!-- NOTE: If two overlapping system bars have the same z-order, SystemBarConfigs will throw a
- RuntimeException, since their placing order cannot be determined. Bars that do not overlap
- are allowed to have the same z-order. -->
- <!-- NOTE: If the z-order of a bar is 10 or above, it will also appear on top of HUN's. -->
- <integer name="config_topSystemBarZOrder">1</integer>
- <integer name="config_leftSystemBarZOrder">0</integer>
- <integer name="config_rightSystemBarZOrder">0</integer>
- <integer name="config_bottomSystemBarZOrder">10</integer>
-
- <!-- If set to true, the corresponding system bar will be hidden when Keyboard (IME) appears.
- NOTE: hideBottomSystemBarKeyboard must not be overlaid directly here. To change its value,
- overlay config_automotiveHideNavBarForKeyboard in framework/base/core/res/res. -->
- <bool name="config_hideTopSystemBarForKeyboard">false</bool>
- <bool name="config_hideBottomSystemBarForKeyboard">@*android:bool/config_automotiveHideNavBarForKeyboard</bool>
- <bool name="config_hideLeftSystemBarForKeyboard">false</bool>
- <bool name="config_hideRightSystemBarForKeyboard">false</bool>
-
- <!-- Disable normal notification rendering; we handle that ourselves -->
- <bool name="config_renderNotifications">false</bool>
-
- <!-- Whether navigationBar touch events should be consumed before reaching the CarFacetButton \
- when the notification panel is open. -->
- <bool name="config_consumeNavigationBarTouchWhenNotificationPanelOpen">false</bool>
-
- <!-- Whether heads-up notifications should be shown when shade is open. -->
- <bool name="config_enableHeadsUpNotificationWhenNotificationShadeOpen">true</bool>
- <!-- Whether heads-up notifications should be shown on the bottom. If false, heads-up
- notifications will be shown pushed to the top of their parent container. If true, they will
- be shown pushed to the bottom of their parent container. If true, then should override
- config_headsUpNotificationAnimationHelper to use a different AnimationHelper, such as
- com.android.car.notification.headsup.animationhelper.
- CarHeadsUpNotificationBottomAnimationHelper. -->
- <bool name="config_showHeadsUpNotificationOnBottom">false</bool>
-
- <bool name="config_hideNavWhenKeyguardBouncerShown">true</bool>
- <bool name="config_enablePersistentDockedActivity">false</bool>
- <string name="config_persistentDockedActivityIntentUri" translatable="false"></string>
-
- <!-- How many icons may be shown at once in the system bar. Includes any
- slots that may be reused for things like IME control. -->
- <integer name="config_maxNotificationIcons">0</integer>
-
- <!--
- Initial alpha percent value for the background when the notification
- shade is open. Should be a number between, and inclusive, 0 and 100.
- If the number is 0, then the background alpha starts off fully
- transparent. If the number if 100, then the background alpha starts off
- fully opaque. -->
- <integer name="config_initialNotificationBackgroundAlpha">0</integer>
- <!--
- Final alpha percent value for the background when the notification
- shade is fully open. Should be a number between, and inclusive, 0 and
- 100. If this value is smaller than
- config_initialNotificationBackgroundAlpha, the background will default
- to a constant alpha percent value using the initial alpha. -->
- <integer name="config_finalNotificationBackgroundAlpha">100</integer>
-
- <!-- Car System UI's OverlayViewsMediator.
- Whenever a new class is added, make sure to also add that class to OverlayWindowModule. -->
- <string-array name="config_carSystemUIOverlayViewsMediators" translatable="false">
- <item>@string/config_notificationPanelViewMediator</item>
- <item>com.android.systemui.car.keyguard.CarKeyguardViewMediator</item>
- <item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item>
- <item>com.android.systemui.car.userswitcher.UserSwitchTransitionViewMediator</item>
- <item>com.android.systemui.car.rvc.RearViewCameraViewMediator</item>
- </string-array>
-
- <!--
- Car SystemUI's notification mediator. Replace with other notification mediators to have
- the notification panel show from another system bar. The system bar should be enabled to
- use the mediator with that system bar.
- Example: config_enableBottomNavigationBar=true
- config_notificationPanelViewMediator=
- com.android.systemui.car.notification.BottomNotificationPanelViewMediator -->
- <string name="config_notificationPanelViewMediator" translatable="false">
- com.android.systemui.car.notification.TopNotificationPanelViewMediator</string>
-
- <!-- List of package names that are allowed sources of app installation. -->
- <string-array name="config_allowedAppInstallSources" translatable="false">
- <item>com.android.vending</item>
- </string-array>
-
- <!-- The list of components to exclude from config_systemUIServiceComponents. -->
- <string-array name="config_systemUIServiceComponentsExclude" translatable="false">
- <item>com.android.systemui.recents.Recents</item>
- <item>com.android.systemui.volume.VolumeUI</item>
- <item>com.android.systemui.statusbar.phone.StatusBar</item>
- <item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
- <item>com.android.systemui.LatencyTester</item>
- <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
- <item>com.android.systemui.SliceBroadcastRelayHandler</item>
- <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
- <item>com.android.systemui.accessibility.WindowMagnification</item>
- <item>com.android.systemui.accessibility.SystemActions</item>
- </string-array>
-
- <!-- The list of components to append to config_systemUIServiceComponents. -->
- <string-array name="config_systemUIServiceComponentsInclude" translatable="false">
- <item>com.android.systemui.car.navigationbar.CarNavigationBar</item>
- <item>com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier</item>
- <item>com.android.systemui.car.window.SystemUIOverlayWindowManager</item>
- <item>com.android.systemui.car.volume.VolumeUI</item>
- </string-array>
-
- <!-- How many milliseconds to wait before force hiding the UserSwitchTransitionView -->
- <integer name="config_userSwitchTransitionViewShownTimeoutMs" translatable="false">5000</integer>
-
- <!-- The Activity name for the Rear View Camera, if empty, the feature will be disabled. -->
- <string name="config_rearViewCameraActivity" translatable="false"></string>
-
- <!-- Whether the Notification Panel should be inset by the top system bar. -->
- <bool name="config_notif_panel_inset_by_top_systembar" translatable="false">false</bool>
- <!-- Whether the Notification Panel should be inset by the bottom system bar. -->
- <bool name="config_notif_panel_inset_by_bottom_systembar" translatable="false">true</bool>
- <!-- Whether the Notification Panel should be inset by the left system bar. -->
- <bool name="config_notif_panel_inset_by_left_systembar" translatable="false">false</bool>
- <!-- Whether the Notification Panel should be inset by the right system bar. -->
- <bool name="config_notif_panel_inset_by_right_systembar" translatable="false">false</bool>
-</resources>
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
deleted file mode 100644
index a7d8ab5f2a4c..000000000000
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ /dev/null
@@ -1,234 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<resources>
- <!-- Text size for car -->
- <dimen name="car_title_size">32sp</dimen>
- <dimen name="car_title2_size">32sp</dimen>
- <dimen name="car_headline1_size">45sp</dimen>
- <dimen name="car_headline2_size">32sp</dimen>
- <dimen name="car_headline3_size">24sp</dimen>
- <dimen name="car_headline4_size">20sp</dimen>
- <dimen name="car_body1_size">32sp</dimen>
- <dimen name="car_body2_size">28sp</dimen>
- <dimen name="car_body3_size">26sp</dimen>
- <dimen name="car_body4_size">24sp</dimen>
- <!-- car_body5_size is deprecated -->
- <dimen name="car_body5_size">18sp</dimen>
- <dimen name="car_label1_size">26sp</dimen>
- <dimen name="car_label2_size">64sp</dimen>
- <dimen name="car_action1_size">26sp</dimen>
- <dimen name="car_action2_size">26sp</dimen>
- <!-- Paddings -->
- <dimen name="car_padding_0">4dp</dimen>
- <dimen name="car_padding_1">8dp</dimen>
- <dimen name="car_padding_2">16dp</dimen>
- <dimen name="car_padding_3">24dp</dimen>
- <dimen name="car_padding_4">32dp</dimen>
- <dimen name="car_padding_5">64dp</dimen>
- <dimen name="car_padding_6">96dp</dimen>
-
- <!--
- Note: status bar height and navigation bar heights are defined
- in frameworks/base/core package and thus will have no effect if
- set here. See car_product overlay for car specific defaults-->
-
- <!-- Overrides the space between each status icon in the system bar -->
- <dimen name="status_bar_system_icon_spacing">16dp</dimen>
- <!-- Overrides the size of the network signal icon -->
- <dimen name="signal_icon_size">32dp</dimen>
- <dimen name="system_bar_user_icon_padding">16dp</dimen>
- <dimen name="system_bar_user_icon_drawing_size">36dp</dimen>
- <!-- Padding on either side of the group of all system bar buttons -->
- <dimen name="system_bar_button_group_padding">64dp</dimen>
- <dimen name="system_bar_icon_drawing_size">44dp</dimen>
- <dimen name="system_bar_button_size">76dp</dimen>
- <!-- Margin between the system bar buttons -->
- <dimen name="system_bar_button_margin">32dp</dimen>
- <!-- Padding between the system bar button and the icon within it -->
- <dimen name="system_bar_button_padding">16dp</dimen>
-
- <!-- The amount by which to scale up the status bar icons. -->
- <item name="status_bar_icon_scale_factor" format="float" type="dimen">1.75</item>
-
- <dimen name="car_primary_icon_size">@*android:dimen/car_primary_icon_size</dimen>
-
- <dimen name="hvac_container_padding">16dp</dimen>
- <dimen name="hvac_temperature_text_size">56sp</dimen>
- <dimen name="hvac_temperature_text_padding">8dp</dimen>
- <dimen name="hvac_temperature_button_size">76dp</dimen>
- <!--These values represent MIN and MAX for hvac-->
- <item name="hvac_min_value_celsius" format="float" type="dimen">10</item>
- <item name="hvac_max_value_celsius" format="float" type="dimen">35</item>
-
- <!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
- quick settings header -->
- <dimen name="max_avatar_size">128dp</dimen>
-
- <!-- Standard image button size for volume dialog buttons -->
- <dimen name="volume_button_size">84dp</dimen>
- <!-- The maximum width allowed for the volume dialog. For auto, we allow this to span a good
- deal of the screen. This value accounts for the side margins. -->
- <dimen name="volume_dialog_panel_width">1920dp</dimen>
- <dimen name="volume_dialog_side_margin">@dimen/side_margin</dimen>
-
- <dimen name="volume_dialog_elevation">6dp</dimen>
-
- <dimen name="volume_dialog_row_margin_end">@*android:dimen/car_keyline_3</dimen>
-
- <dimen name="volume_dialog_row_padding_end">0dp</dimen>
-
- <dimen name="line_item_height">128dp</dimen>
- <dimen name="volume_icon_size">96dp</dimen>
- <dimen name="side_margin">148dp</dimen>
- <dimen name="car_keyline_1">24dp</dimen>
- <dimen name="car_keyline_2">96dp</dimen>
- <dimen name="car_keyline_3">128dp</dimen>
-
- <!-- Height of icons in Ongoing App Ops dialog. Both App Op icon and application icon -->
- <dimen name="ongoing_appops_dialog_icon_height">48dp</dimen>
- <!-- Margin between text lines in Ongoing App Ops dialog -->
- <dimen name="ongoing_appops_dialog_text_margin">15dp</dimen>
- <!-- Padding around Ongoing App Ops dialog content -->
- <dimen name="ongoing_appops_dialog_content_padding">24dp</dimen>
- <!-- Margins around the Ongoing App Ops chip. In landscape, the side margins are 0 -->
- <dimen name="ongoing_appops_chip_margin">12dp</dimen>
- <!-- Start and End padding for Ongoing App Ops chip -->
- <dimen name="ongoing_appops_chip_side_padding">6dp</dimen>
- <!-- Padding between background of Ongoing App Ops chip and content -->
- <dimen name="ongoing_appops_chip_bg_padding">4dp</dimen>
- <!-- Radius of Ongoing App Ops chip corners -->
- <dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen>
-
- <!-- Car volume dimens. -->
- <dimen name="car_volume_item_icon_size">@dimen/car_primary_icon_size</dimen>
- <dimen name="car_volume_item_height">@*android:dimen/car_single_line_list_item_height</dimen>
- <dimen name="car_volume_item_padding_start">@*android:dimen/car_keyline_1</dimen>
- <dimen name="car_volume_item_padding_end">@*android:dimen/car_keyline_1</dimen>
- <dimen name="car_volume_item_seekbar_margin_vertical">@*android:dimen/car_padding_1</dimen>
- <dimen name="car_volume_item_seekbar_margin_start">@*android:dimen/car_keyline_3</dimen>
- <dimen name="car_volume_item_seekbar_margin_end">@*android:dimen/car_padding_4</dimen>
- <dimen name="car_volume_item_seekbar_padding_vertical">@*android:dimen/car_seekbar_padding</dimen>
- <dimen name="car_volume_item_divider_height">60dp</dimen>
- <dimen name="car_volume_item_divider_width">1dp</dimen>
- <dimen name="car_volume_item_divider_margin_end">@*android:dimen/car_padding_4</dimen>
- <dimen name="car_volume_item_corner_radius">@*android:dimen/car_radius_3</dimen>
-
- <!-- Car notification shade-->
- <dimen name="notification_shade_handle_bar_height">10dp</dimen>
- <dimen name="notification_shade_handle_bar_radius">20dp</dimen>
- <dimen name="notification_shade_handle_bar_margin_start">200dp</dimen>
- <dimen name="notification_shade_handle_bar_margin_end">200dp</dimen>
- <dimen name="notification_shade_handle_bar_margin_top">20dp</dimen>
- <dimen name="notification_shade_handle_bar_margin_bottom">10dp</dimen>
- <dimen name="notification_shade_list_padding_bottom">50dp</dimen>
-
- <!-- The alpha for the scrim behind the notification shade. This value is 1 so that the
- scrim has no transparency. -->
- <item name="scrim_behind_alpha" format="float" type="dimen">1.0</item>
-
- <!-- The width of panel holding the notification card. -->
- <dimen name="notification_panel_width">522dp</dimen>
-
- <!-- Height of a small notification in the status bar-->
- <dimen name="notification_min_height">192dp</dimen>
-
- <!-- Height of a small notification in the status bar which was used before android N -->
- <dimen name="notification_min_height_legacy">192dp</dimen>
-
- <!-- Height of a large notification in the status bar -->
- <dimen name="notification_max_height">400dp</dimen>
-
- <!-- Height of a heads up notification in the status bar for legacy custom views -->
- <dimen name="notification_max_heads_up_height_legacy">400dp</dimen>
-
- <!-- Height of a heads up notification in the status bar -->
- <dimen name="notification_max_heads_up_height">400dp</dimen>
-
- <!-- Height of the status bar header bar -->
- <dimen name="status_bar_header_height">54dp</dimen>
-
- <!-- The height of the divider between the individual notifications. -->
- <dimen name="notification_divider_height">16dp</dimen>
-
- <!-- The height of the divider between the individual notifications when the notification
- wants it to be increased. This value is the same as notification_divider_height so that
- the spacing between all notifications will always be the same. -->
- <dimen name="notification_divider_height_increased">@dimen/notification_divider_height</dimen>
-
- <!-- The alpha of the dividing line between child notifications of a notification group. -->
- <item name="notification_divider_alpha" format="float" type="dimen">1.0</item>
-
- <!-- The width of each individual notification card. -->
- <dimen name="notification_child_width">522dp</dimen>
-
- <!-- The top margin of the notification panel. -->
- <dimen name="notification_panel_margin_top">32dp</dimen>
-
- <!-- The bottom margin of the panel that holds the list of notifications. -->
- <dimen name="notification_panel_margin_bottom">@dimen/notification_divider_height</dimen>
-
- <!-- The corner radius of the shadow behind the notification. -->
- <dimen name="notification_shadow_radius">16dp</dimen>
-
- <!-- The amount of space below the notification list. This value is 0 so the list scrolls
- all the way to the bottom. -->
- <dimen name="close_handle_underlap">0dp</dimen>
-
- <!-- The height of the divider between the individual notifications in a notification group. -->
- <dimen name="notification_children_container_divider_height">1dp</dimen>
-
- <!-- The height of the header for a container containing child notifications. -->
- <dimen name="notification_children_container_header_height">76dp</dimen>
-
- <!-- The top margin for the notification children container in its non-expanded form. This
- value is smaller than notification_children_container_header_height to bring the first
- child closer so there is less wasted space. -->
- <dimen name="notification_children_container_margin_top">68dp</dimen>
-
- <!-- dimensions for the car user switcher -->
- <dimen name="car_user_switcher_name_text_size">@*android:dimen/car_body1_size</dimen>
- <dimen name="car_user_switcher_image_avatar_size">@*android:dimen/car_large_avatar_size</dimen>
- <dimen name="car_user_switcher_vertical_spacing_between_users">@*android:dimen/car_padding_5</dimen>
- <dimen name="car_user_switcher_vertical_spacing_between_name_and_avatar">@*android:dimen/car_padding_4</dimen>
- <dimen name="car_user_switcher_margin_top">@*android:dimen/car_padding_4</dimen>
-
- <dimen name="car_navigation_button_width">64dp</dimen>
- <dimen name="car_navigation_button_icon_height">44dp</dimen>
- <dimen name="car_navigation_bar_width">760dp</dimen>
- <dimen name="car_left_navigation_bar_width">96dp</dimen>
- <dimen name="car_right_navigation_bar_width">96dp</dimen>
- <!-- In order to change the height of the bottom nav bar, overlay navigation_bar_height in
- frameworks/base/core/res/res instead. -->
- <dimen name="car_bottom_navigation_bar_height">@*android:dimen/navigation_bar_height</dimen>
- <!-- In order to change the height of the top nav bar, overlay status_bar_height in
- frameworks/base/core/res/res instead. -->
- <dimen name="car_top_navigation_bar_height">@*android:dimen/status_bar_height</dimen>
-
- <dimen name="car_user_switcher_container_height">420dp</dimen>
- <!-- This must be the negative of car_user_switcher_container_height for the animation. -->
- <dimen name="car_user_switcher_container_anim_height">-420dp</dimen>
-
- <!-- dimensions for car user switching dialog -->
- <dimen name="car_fullscreen_user_pod_image_avatar_width">96dp</dimen>
- <dimen name="car_fullscreen_user_pod_image_avatar_height">96dp</dimen>
- <dimen name="car_user_switching_dialog_loading_text_margin_top">@*android:dimen/car_padding_4</dimen>
- <dimen name="car_user_switching_dialog_loading_text_font_size">@*android:dimen/car_body1_size</dimen>
-
- <!-- dimensions for rear view camera -->
- <dimen name="rear_view_camera_width">600dp</dimen>
- <dimen name="rear_view_camera_height">500dp</dimen>
-</resources>
diff --git a/packages/CarSystemUI/res/values/ids.xml b/packages/CarSystemUI/res/values/ids.xml
deleted file mode 100644
index 05194a4d6279..000000000000
--- a/packages/CarSystemUI/res/values/ids.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<resources>
- <!-- Values used for finding elements on the system ui nav bars -->
- <item type="id" name="lock_screen_nav_buttons"/>
-</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/values/integers.xml b/packages/CarSystemUI/res/values/integers.xml
deleted file mode 100644
index 5ae5555a8092..000000000000
--- a/packages/CarSystemUI/res/values/integers.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (c) 2018, The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources>
- <!-- Full screen user switcher column number -->
- <integer name="user_fullscreen_switcher_num_col">3</integer>
-
- <!--Percentage of the screen height, from the bottom, that a notification panel being
- partially closed at will result in it remaining open if released-->
- <integer name="notification_settle_open_percentage">20</integer>
- <!--Percentage of the screen height, from the bottom, that a notification panel being peeked
- at will result in remaining closed the panel if released-->
- <integer name="notification_settle_close_percentage">80</integer>
-
- <!-- Timeout values in milliseconds for displaying volume dialog-->
- <integer name="car_volume_dialog_display_normal_timeout">3000</integer>
- <integer name="car_volume_dialog_display_hovering_timeout">16000</integer>
- <integer name="car_volume_dialog_display_expanded_normal_timeout">6000</integer>
- <integer name="car_volume_dialog_display_expanded_hovering_timeout">32000</integer>
-</resources>
diff --git a/packages/CarSystemUI/res/values/strings.xml b/packages/CarSystemUI/res/values/strings.xml
deleted file mode 100644
index 264456588c80..000000000000
--- a/packages/CarSystemUI/res/values/strings.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (c) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Format for HVAC temperature (No decimal and the degree symbol) -->
- <string name="hvac_temperature_format" translatable="false">%.0f\u00B0</string>
- <!-- String to represent lowest setting of an HVAC system [CHAR LIMIT=10]-->
- <string name="hvac_min_text">Min</string>
- <!-- String to represent largest setting of an HVAC system [CHAR LIMIT=10]-->
- <string name="hvac_max_text">Max</string>
- <!-- String to display when no HVAC temperature is available -->
- <string name="hvac_null_temp_text" translatable="false">--</string>
- <!-- Text for voice recognition toast. [CHAR LIMIT=60] -->
- <string name="voice_recognition_toast">Voice recognition now handled by connected Bluetooth device</string>
- <!-- Name of Guest Profile. [CHAR LIMIT=35] -->
- <string name="car_guest">Guest</string>
- <!-- Title for button that starts a guest session. [CHAR LIMIT=35] -->
- <string name="start_guest_session">Guest</string>
- <!-- Title for button that adds a new user. [CHAR LIMIT=30] -->
- <string name="car_add_user">Add User</string>
- <!-- Default name of the new user created. [CHAR LIMIT=30] -->
- <string name="car_new_user">New User</string>
- <!-- Message to inform user that creation of new user requires that user to set up their space. [CHAR LIMIT=100] -->
- <string name="user_add_user_message_setup">When you add a new user, that person needs to set up their space.</string>
- <!-- Message to inform user that the newly created user will have permissions to update apps for all other users. [CHAR LIMIT=100] -->
- <string name="user_add_user_message_update">Any user can update apps for all other users.</string>
- <!-- Message to inform user that the new user profile is loading. [CHAR LIMIT=20] -->
- <string name="car_loading_profile">Loading</string>
- <!-- Message to inform user that the new user profile is loading with additional information on the previous and the next user. [CHAR LIMIT=100] -->
- <string name="car_loading_profile_developer_message">Loading user (from <xliff:g id="from_user" example="10">%1$d</xliff:g> to <xliff:g id="to_user" example="12">%2$d</xliff:g>)</string>
- <!-- Text for the close button in Rear View Camera [CHAR LIMIT=30] -->
- <string name="rear_view_camera_close_button_text">Close</string>
-</resources>
diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml
deleted file mode 100644
index f5de2fde7b1a..000000000000
--- a/packages/CarSystemUI/res/values/styles.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-
- <!-- The style for the volume icons in the volume dialog. This style makes the icon scale to
- fit its container since auto wants the icon to be larger. The padding is added to make it
- so the icon does not press along the edges of the dialog. -->
- <style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless">
- <item name="android:background">@drawable/btn_borderless_rect</item>
- <item name="android:scaleType">fitCenter</item>
- <item name="android:padding">22dp</item>
- </style>
-
- <style name="TextAppearance.SystemBar.Clock"
- parent="@*android:style/TextAppearance.StatusBar.Icon">
- <item name="android:textSize">@dimen/car_body1_size</item>
- <item name="android:textColor">@*android:color/car_headline3</item>
- </style>
-
- <style name="TextAppearance.SystemBar.Username"
- parent="@android:style/TextAppearance.DeviceDefault">
- <item name="android:textSize">@dimen/car_body3_size</item>
- <item name="android:textColor">@color/system_bar_text_color</item>
- </style>
-
- <style name="TextAppearance.CarStatus" parent="@android:style/TextAppearance.DeviceDefault">
- <item name="android:textSize">@*android:dimen/car_body2_size</item>
- <item name="android:textColor">@color/system_bar_text_color</item>
- </style>
-
- <style name="NavigationBarButton">
- <item name="android:layout_height">@dimen/system_bar_button_size</item>
- <item name="android:layout_width">@dimen/system_bar_button_size</item>
- <item name="android:layout_marginEnd">@dimen/system_bar_button_margin</item>
- <item name="android:padding">@dimen/system_bar_button_padding</item>
- <item name="android:gravity">center</item>
- <item name="android:background">?android:attr/selectableItemBackground</item>
- <item name="unselectedAlpha">0.56</item>
- </style>
-</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/xml/car_volume_items.xml b/packages/CarSystemUI/res/xml/car_volume_items.xml
deleted file mode 100644
index d371a646b85d..000000000000
--- a/packages/CarSystemUI/res/xml/car_volume_items.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright 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.
- -->
-
-<!--
- Defines all possible items on car volume settings UI, keyed by usage.
--->
-<carVolumeItems xmlns:car="http://schemas.android.com/apk/res-auto">
- <item car:usage="unknown"
- car:icon="@drawable/car_ic_music"/>
- <item car:usage="media"
- car:icon="@drawable/car_ic_music"/>
- <item car:usage="assistance_navigation_guidance"
- car:icon="@drawable/car_ic_navigation"/>
- <item car:usage="voice_communication_signalling"
- car:icon="@*android:drawable/ic_audio_ring_notif"/>
- <item car:usage="alarm"
- car:icon="@drawable/ic_volume_alarm"/>
- <item car:usage="notification"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="notification_ringtone"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="notification_communication_request"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="notification_communication_instant"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="notification_communication_delayed"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="notification_event"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="assistance_accessibility"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="voice_communication"
- car:icon="@*android:drawable/ic_audio_ring_notif"/>
- <item car:usage="assistance_sonification"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="game"
- car:icon="@drawable/car_ic_music"/>
- <item car:usage="assistant"
- car:icon="@drawable/car_ic_music"/>
- <item car:usage="call_assistant"
- car:icon="@*android:drawable/ic_audio_ring_notif"/>
- <item car:usage="emergency"
- car:icon="@drawable/ic_volume_alarm"/>
- <item car:usage="safety"
- car:icon="@drawable/ic_volume_alarm"/>
- <item car:usage="vehicle_status"
- car:icon="@drawable/car_ic_notification"/>
- <item car:usage="announcement"
- car:icon="@drawable/car_ic_notification"/>
-</carVolumeItems>
-
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_apps.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_apps.xml
deleted file mode 100644
index a8d8a2f241f6..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_apps.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
-<path
- android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_apps_selected.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_apps_selected.xml
deleted file mode 100644
index 2a4e91aa3cd9..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_apps_selected.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
- android:fillColor="@color/car_nav_icon_fill_color_selected" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_music.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_music.xml
deleted file mode 100644
index 6339ebb3ea8d..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_music.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M22 5.5L22 24.8416667C20.9183333 24.2183333 19.6716667 23.8333333 18.3333333 23.8333333C14.2816667 23.8333333 11 27.115 11 31.1666667C11 35.2183333 14.2816667 38.5 18.3333333 38.5C22.385 38.5 25.6666667 35.2183333 25.6666667 31.1666667L25.6666667 12.8333333L33 12.8333333L33 5.5L22 5.5Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_music_selected.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_music_selected.xml
deleted file mode 100644
index a56bcb38d883..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_music_selected.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M22 5.5L22 24.8416667C20.9183333 24.2183333 19.6716667 23.8333333 18.3333333 23.8333333C14.2816667 23.8333333 11 27.115 11 31.1666667C11 35.2183333 14.2816667 38.5 18.3333333 38.5C22.385 38.5 25.6666667 35.2183333 25.6666667 31.1666667L25.6666667 12.8333333L33 12.8333333L33 5.5L22 5.5Z"
- android:fillColor="@color/car_nav_icon_fill_color_selected" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_navigation.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_navigation.xml
deleted file mode 100644
index e1fabe07cdeb..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_navigation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M39.8016667 20.6983333L23.3016667 4.19833333C22.5866667 3.48333333 21.4316667 3.48333333 20.7166667 4.19833333L4.21666667 20.6983333C3.50166667 21.4133333 3.50166667 22.5683333 4.21666667 23.2833333L20.7166667 39.7833333C21.4316667 40.4983333 22.5866667 40.4983333 23.3016667 39.7833333L39.8016667 23.2833333C40.5166667 22.5866667 40.5166667 21.4316667 39.8016667 20.6983333ZM25.6666667 26.5833333L25.6666667 22L18.3333333 22L18.3333333 27.5L14.6666667 27.5L14.6666667 20.1666667C14.6666667 19.1583333 15.4916667 18.3333333 16.5 18.3333333L25.6666667 18.3333333L25.6666667 13.75L32.0833333 20.1666667L25.6666667 26.5833333Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_navigation_selected.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_navigation_selected.xml
deleted file mode 100644
index d11cf28f6ca7..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_navigation_selected.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M39.8016667 20.6983333L23.3016667 4.19833333C22.5866667 3.48333333 21.4316667 3.48333333 20.7166667 4.19833333L4.21666667 20.6983333C3.50166667 21.4133333 3.50166667 22.5683333 4.21666667 23.2833333L20.7166667 39.7833333C21.4316667 40.4983333 22.5866667 40.4983333 23.3016667 39.7833333L39.8016667 23.2833333C40.5166667 22.5866667 40.5166667 21.4316667 39.8016667 20.6983333ZM25.6666667 26.5833333L25.6666667 22L18.3333333 22L18.3333333 27.5L14.6666667 27.5L14.6666667 20.1666667C14.6666667 19.1583333 15.4916667 18.3333333 16.5 18.3333333L25.6666667 18.3333333L25.6666667 13.75L32.0833333 20.1666667L25.6666667 26.5833333Z"
- android:fillColor="@color/car_nav_icon_fill_color_selected" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_overview.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_overview.xml
deleted file mode 100644
index f185eb9afb75..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_overview.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M36.92857 22.39286A14.53571 14.53571 0 0 1 7.857143 22.39286A14.53571 14.53571 0 0 1 36.92857 22.39286Z"
- android:strokeColor="@color/car_nav_icon_fill_color"
- android:strokeWidth="4" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_overview_selected.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_overview_selected.xml
deleted file mode 100644
index 19b558363720..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_overview_selected.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M36.92857 22.39286A14.53571 14.53571 0 0 1 7.857143 22.39286A14.53571 14.53571 0 0 1 36.92857 22.39286Z"
- android:strokeColor="@color/car_nav_icon_fill_color_selected"
- android:strokeWidth="4" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_phone.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_phone.xml
deleted file mode 100644
index 50e36b5a6e3c..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_phone.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M12.1366667 19.7816667C14.7766667 24.97 19.03 29.205 24.2183333 31.8633333L28.2516667 27.83C28.7466667 27.335 29.48 27.17 30.1216667 27.39C32.175 28.0683333 34.3933333 28.435 36.6666667 28.435C37.675 28.435 38.5 29.26 38.5 30.2683333L38.5 36.6666667C38.5 37.675 37.675 38.5 36.6666667 38.5C19.4516667 38.5 5.5 24.5483333 5.5 7.33333333C5.5 6.325 6.325 5.5 7.33333333 5.5L13.75 5.5C14.7583333 5.5 15.5833333 6.325 15.5833333 7.33333333C15.5833333 9.625 15.95 11.825 16.6283333 13.8783333C16.83 14.52 16.6833333 15.235 16.17 15.7483333L12.1366667 19.7816667Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_phone_selected.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_phone_selected.xml
deleted file mode 100644
index 11b1687cf1c1..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/car_ic_phone_selected.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M12.1366667 19.7816667C14.7766667 24.97 19.03 29.205 24.2183333 31.8633333L28.2516667 27.83C28.7466667 27.335 29.48 27.17 30.1216667 27.39C32.175 28.0683333 34.3933333 28.435 36.6666667 28.435C37.675 28.435 38.5 29.26 38.5 30.2683333L38.5 36.6666667C38.5 37.675 37.675 38.5 36.6666667 38.5C19.4516667 38.5 5.5 24.5483333 5.5 7.33333333C5.5 6.325 6.325 5.5 7.33333333 5.5L13.75 5.5C14.7583333 5.5 15.5833333 6.325 15.5833333 7.33333333C15.5833333 9.625 15.95 11.825 16.6283333 13.8783333C16.83 14.52 16.6833333 15.235 16.17 15.7483333L12.1366667 19.7816667Z"
- android:fillColor="@color/car_nav_icon_fill_color_selected" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background.xml
deleted file mode 100644
index 6161ad9b041c..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
- <corners
- android:topLeftRadius="0dp"
- android:topRightRadius="10dp"
- android:bottomLeftRadius="0dp"
- android:bottomRightRadius="0dp"
- />
- <solid
- android:color="#404040"
- />
- <padding
- android:left="0dp"
- android:top="0dp"
- android:right="0dp"
- android:bottom="0dp"
- />
-</shape> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background_2.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background_2.xml
deleted file mode 100644
index 35821426bee3..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background_2.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
- <corners
- android:topLeftRadius="10dp"
- android:topRightRadius="0dp"
- android:bottomLeftRadius="0dp"
- android:bottomRightRadius="0dp"
- />
- <solid
- android:color="#404040"
- />
- <padding
- android:left="0dp"
- android:top="0dp"
- android:right="0dp"
- android:bottom="0dp"
- />
-</shape> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background_3.xml b/packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background_3.xml
deleted file mode 100644
index afa5b32136a8..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/drawable/system_bar_background_3.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
- <corners
- android:topLeftRadius="0dp"
- android:topRightRadius="0dp"
- android:bottomLeftRadius="10dp"
- android:bottomRightRadius="0dp"
- />
- <solid
- android:color="#404040"
- />
- <padding
- android:left="0dp"
- android:top="0dp"
- android:right="0dp"
- android:bottom="0dp"
- />
-</shape> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/samples/sample1/rro/res/layout/car_navigation_bar.xml
deleted file mode 100644
index 4358d977bcc3..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/layout/car_navigation_bar.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-<?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.
- -->
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/transparent"
- android:orientation="horizontal">
- <!--The 20dp padding is the difference between the background selected icon size and the ripple
- that was chosen, thus it's a hack to make it look pretty and not an official margin value-->
- <LinearLayout
- android:id="@+id/nav_buttons"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/system_bar_background"
- android:gravity="center"
- android:layoutDirection="ltr"
- android:paddingEnd="20dp"
- android:paddingStart="20dp">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_overview_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/maps_nav"
- style="@style/NavigationBarButton"
- systemui:categories="android.intent.category.APP_MAPS"
- systemui:icon="@drawable/car_ic_navigation"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_navigation_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/music_nav"
- style="@style/NavigationBarButton"
- systemui:categories="android.intent.category.APP_MUSIC"
- systemui:icon="@drawable/car_ic_music"
- systemui:intent="intent:#Intent;action=android.car.intent.action.MEDIA_TEMPLATE;launchFlags=0x10000000;end"
- systemui:packages="com.android.car.media"
- systemui:selectedIcon="@drawable/car_ic_music_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/phone_nav"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/car_ic_phone"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
- systemui:packages="com.android.car.dialer"
- systemui:selectedIcon="@drawable/car_ic_phone_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/grid_nav"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
- systemui:icon="@drawable/car_ic_apps"
- systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
- systemui:selectedIcon="@drawable/car_ic_apps_selected"
- systemui:highlightWhenSelected="true"
- />
-
- </LinearLayout>
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/layout/car_right_navigation_bar.xml b/packages/CarSystemUI/samples/sample1/rro/res/layout/car_right_navigation_bar.xml
deleted file mode 100644
index dc1d0d64a40b..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/layout/car_right_navigation_bar.xml
+++ /dev/null
@@ -1,141 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:baselineAligned="false"
- android:background="@android:color/transparent">
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="110dp"
- android:background="@drawable/system_bar_background_3">
- <FrameLayout
- android:id="@+id/clock_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_centerInParent="true">
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/qs"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"
- systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$QuickSettingActivity;launchFlags=0x24000000;end"
- />
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:elevation="5dp"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- />
- </FrameLayout>
- </RelativeLayout>
- <View
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- />
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="110dp"
- android:layout_gravity="bottom"
- android:orientation="horizontal"
- android:background="@drawable/system_bar_background_2">
-
- <FrameLayout
- android:id="@+id/left_hvac_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentStart="true">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvacleft"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"
- systemui:broadcast="true"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- />
-
- <com.android.systemui.car.hvac.AnimatedTemperatureView
- android:id="@+id/lefttext"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="@*android:dimen/car_padding_4"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:minEms="4"
- android:textAppearance="@style/TextAppearance.CarStatus"
- systemui:hvacAreaId="49"
- systemui:hvacMaxText="Max"
- systemui:hvacMaxValue="126"
- systemui:hvacMinText="Min"
- systemui:hvacMinValue="0"
- systemui:hvacPivotOffset="60dp"
- systemui:hvacPropertyId="358614275"
- systemui:hvacTempFormat="%.0f\u00B0"
- />
- </FrameLayout>
- <View
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- />
- <FrameLayout
- android:id="@+id/right_hvac_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentEnd="true">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvacright"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"
- systemui:broadcast="true"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- />
-
- <com.android.systemui.car.hvac.AnimatedTemperatureView
- android:id="@+id/righttext"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="16dp"
- android:paddingEnd="@*android:dimen/car_padding_4"
- android:gravity="center_vertical|end"
- android:minEms="4"
- android:textAppearance="@style/TextAppearance.CarStatus"
- systemui:hvacAreaId="68"
- systemui:hvacMaxText="Max"
- systemui:hvacMaxValue="126"
- systemui:hvacMinText="Min"
- systemui:hvacMinValue="0"
- systemui:hvacPivotOffset="60dp"
- systemui:hvacPropertyId="358614275"
- systemui:hvacTempFormat="%.0f\u00B0"
- />
- </FrameLayout>
- </LinearLayout>
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/layout/system_icons.xml b/packages/CarSystemUI/samples/sample1/rro/res/layout/system_icons.xml
deleted file mode 100644
index d23579294ce8..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/layout/system_icons.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/system_icons"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center_vertical">
-
- <com.android.systemui.statusbar.phone.StatusIconContainer
- android:id="@+id/statusIcons"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:paddingEnd="4dp"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- />
-</LinearLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/values/attrs.xml b/packages/CarSystemUI/samples/sample1/rro/res/values/attrs.xml
deleted file mode 100644
index e02f9e6e9a72..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/values/attrs.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?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>
- <attr name="broadcast" format="boolean"/>
- <attr name="icon" format="reference"/>
- <attr name="selectedIcon" format="reference"/>
- <attr name="intent" format="string"/>
- <attr name="longIntent" format="string"/>
- <attr name="componentNames" format="string" />
- <attr name="highlightWhenSelected" format="boolean" />
- <attr name="categories" format="string"/>
- <attr name="packages" format="string" />
-
- <!-- Custom attributes to configure hvac values -->
- <declare-styleable name="AnimatedTemperatureView">
- <attr name="hvacAreaId" format="integer"/>
- <attr name="hvacPropertyId" format="integer"/>
- <attr name="hvacTempFormat" format="string"/>
- <!-- how far away the animations should center around -->
- <attr name="hvacPivotOffset" format="dimension"/>
- <attr name="hvacMinValue" format="float"/>
- <attr name="hvacMaxValue" format="float"/>
- <attr name="hvacMinText" format="string|reference"/>
- <attr name="hvacMaxText" format="string|reference"/>
- <attr name="android:gravity"/>
- <attr name="android:minEms"/>
- <attr name="android:textAppearance"/>
- </declare-styleable>
-</resources>
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/values/config.xml b/packages/CarSystemUI/samples/sample1/rro/res/values/config.xml
deleted file mode 100644
index 2ec90e95d707..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/values/config.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?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>
- <!-- Configure which system bars should be displayed. -->
- <bool name="config_enableTopNavigationBar">false</bool>
- <bool name="config_enableLeftNavigationBar">false</bool>
- <bool name="config_enableRightNavigationBar">true</bool>
- <bool name="config_enableBottomNavigationBar">true</bool>
-
- <!-- Configure the type of each system bar. Each system bar must have a unique type. -->
- <!-- STATUS_BAR = 0-->
- <!-- NAVIGATION_BAR = 1-->
- <!-- STATUS_BAR_EXTRA = 2-->
- <!-- NAVIGATION_BAR_EXTRA = 3-->
- <integer name="config_topSystemBarType">0</integer>
- <integer name="config_leftSystemBarType">0</integer>
- <integer name="config_rightSystemBarType">0</integer>
- <integer name="config_bottomSystemBarType">1</integer>
-
- <!-- Configure the relative z-order among the system bars. When two system bars overlap (e.g.
- if both top bar and left bar are enabled, it creates an overlapping space in the upper left
- corner), the system bar with the higher z-order takes the overlapping space and padding is
- applied to the other bar.-->
- <!-- NOTE: If two overlapping system bars have the same z-order, SystemBarConfigs will throw a
- RuntimeException, since their placing order cannot be determined. Bars that do not overlap
- are allowed to have the same z-order. -->
- <!-- NOTE: If the z-order of a bar is 10 or above, it will also appear on top of HUN's. -->
- <integer name="config_topSystemBarZOrder">0</integer>
- <integer name="config_leftSystemBarZOrder">0</integer>
- <integer name="config_rightSystemBarZOrder">11</integer>
- <integer name="config_bottomSystemBarZOrder">10</integer>
-
- <!-- Whether heads-up notifications should be shown on the bottom. If false, heads-up
- notifications will be shown pushed to the top of their parent container. If true, they will
- be shown pushed to the bottom of their parent container. If true, then should override
- config_headsUpNotificationAnimationHelper to use a different AnimationHelper, such as
- com.android.car.notification.headsup.animationhelper.
- CarHeadsUpNotificationBottomAnimationHelper. -->
- <bool name="config_showHeadsUpNotificationOnBottom">true</bool>
-
- <string name="config_notificationPanelViewMediator" translatable="false">
- com.android.systemui.car.notification.BottomNotificationPanelViewMediator</string>
-</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/values/dimens.xml b/packages/CarSystemUI/samples/sample1/rro/res/values/dimens.xml
deleted file mode 100644
index cdfed27c64a7..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/values/dimens.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<resources>
- <dimen name="car_right_navigation_bar_width">280dp</dimen>
-</resources>
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/values/styles.xml b/packages/CarSystemUI/samples/sample1/rro/res/values/styles.xml
deleted file mode 100644
index 136dc3b6df18..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/values/styles.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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 xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="TextAppearance.StatusBar.Clock"
- parent="@*android:style/TextAppearance.StatusBar.Icon">
- <item name="android:textSize">40sp</item>
- <item name="android:fontFamily">sans-serif-regular</item>
- <item name="android:textColor">#FFFFFF</item>
- </style>
-
- <style name="NavigationBarButton">
- <item name="android:layout_height">96dp</item>
- <item name="android:layout_width">96dp</item>
- <item name="android:background">?android:attr/selectableItemBackground</item>
- </style>
-
- <style name="TextAppearance.CarStatus" parent="@android:style/TextAppearance.DeviceDefault">
- <item name="android:textSize">30sp</item>
- <item name="android:textColor">#FFFFFF</item>
- </style>
-</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml b/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml
deleted file mode 100644
index 20aa5f79c5cc..000000000000
--- a/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml
+++ /dev/null
@@ -1,76 +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.
- -->
-
-<overlay>
- <item target="layout/car_navigation_bar" value="@layout/car_navigation_bar"/>
- <item target="layout/system_icons" value="@layout/system_icons"/>
- <item target="layout/car_right_navigation_bar" value="@layout/car_right_navigation_bar"/>
-
- <item target="attr/icon" value="@attr/icon"/>
- <item target="attr/selectedIcon" value="@attr/selectedIcon"/>
- <item target="attr/intent" value="@attr/intent"/>
- <item target="attr/longIntent" value="@attr/longIntent"/>
- <item target="attr/componentNames" value="@attr/componentNames"/>
- <item target="attr/highlightWhenSelected" value="@attr/highlightWhenSelected"/>
- <item target="attr/categories" value="@attr/categories"/>
- <item target="attr/packages" value="@attr/packages"/>
- <item target="attr/hvacAreaId" value="@attr/hvacAreaId"/>
- <item target="attr/hvacPropertyId" value="@attr/hvacPropertyId"/>
- <item target="attr/hvacTempFormat" value="@attr/hvacTempFormat"/>
- <item target="attr/hvacPivotOffset" value="@attr/hvacPivotOffset"/>
- <item target="attr/hvacMinValue" value="@attr/hvacMinValue"/>
- <item target="attr/hvacMaxValue" value="@attr/hvacMaxValue"/>
- <item target="attr/hvacMinText" value="@attr/hvacMinText"/>
- <item target="attr/hvacMaxText" value="@attr/hvacMaxText"/>
- <!-- start the intent as a broad cast instead of an activity if true-->
- <item target="attr/broadcast" value="@attr/broadcast"/>
-
- <item target="drawable/car_ic_overview" value="@drawable/car_ic_overview" />
- <item target="drawable/car_ic_overview_selected" value="@drawable/car_ic_overview_selected" />
- <item target="drawable/car_ic_apps" value="@drawable/car_ic_apps" />
- <item target="drawable/car_ic_apps_selected" value="@drawable/car_ic_apps_selected" />
- <item target="drawable/car_ic_music" value="@drawable/car_ic_music" />
- <item target="drawable/car_ic_music_selected" value="@drawable/car_ic_music_selected" />
- <item target="drawable/car_ic_phone" value="@drawable/car_ic_phone" />
- <item target="drawable/car_ic_phone_selected" value="@drawable/car_ic_phone_selected" />
- <item target="drawable/car_ic_navigation" value="@drawable/car_ic_navigation" />
- <item target="drawable/car_ic_navigation_selected" value="@drawable/car_ic_navigation_selected" />
-
- <item target="dimen/car_right_navigation_bar_width" value="@dimen/car_right_navigation_bar_width" />
-
- <item target="style/NavigationBarButton" value="@style/NavigationBarButton"/>
-
- <item target="color/car_nav_icon_fill_color" value="@color/car_nav_icon_fill_color" />
-
- <item target="bool/config_enableTopNavigationBar" value="@bool/config_enableTopNavigationBar"/>
- <item target="bool/config_enableLeftNavigationBar" value="@bool/config_enableLeftNavigationBar"/>
- <item target="bool/config_enableRightNavigationBar" value="@bool/config_enableRightNavigationBar"/>
- <item target="bool/config_enableBottomNavigationBar" value="@bool/config_enableBottomNavigationBar"/>
- <item target="bool/config_showHeadsUpNotificationOnBottom" value="@bool/config_showHeadsUpNotificationOnBottom"/>
-
- <item target="integer/config_topSystemBarType" value="@integer/config_topSystemBarType"/>
- <item target="integer/config_leftSystemBarType" value="@integer/config_leftSystemBarType"/>
- <item target="integer/config_rightSystemBarType" value="@integer/config_rightSystemBarType"/>
- <item target="integer/config_bottomSystemBarType" value="@integer/config_bottomSystemBarType"/>
-
- <item target="integer/config_topSystemBarZOrder" value="@integer/config_topSystemBarZOrder"/>
- <item target="integer/config_leftSystemBarZOrder" value="@integer/config_leftSystemBarZOrder"/>
- <item target="integer/config_rightSystemBarZOrder" value="@integer/config_rightSystemBarZOrder"/>
- <item target="integer/config_bottomSystemBarZOrder" value="@integer/config_bottomSystemBarZOrder"/>
-
- <item target="string/config_notificationPanelViewMediator" value="@string/config_notificationPanelViewMediator"/>
-</overlay> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/AndroidManifest.xml b/packages/CarSystemUI/samples/sample2/rro/AndroidManifest.xml
deleted file mode 100644
index 5c25056f7915..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/AndroidManifest.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.systemui.rro">
- <overlay
- android:targetPackage="com.android.systemui"
- android:isStatic="false"
- android:resourcesMap="@xml/car_sysui_overlays"
- />
-</manifest> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_apps.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_apps.xml
deleted file mode 100644
index a8d8a2f241f6..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_apps.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
-<path
- android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_music.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_music.xml
deleted file mode 100644
index 6339ebb3ea8d..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_music.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M22 5.5L22 24.8416667C20.9183333 24.2183333 19.6716667 23.8333333 18.3333333 23.8333333C14.2816667 23.8333333 11 27.115 11 31.1666667C11 35.2183333 14.2816667 38.5 18.3333333 38.5C22.385 38.5 25.6666667 35.2183333 25.6666667 31.1666667L25.6666667 12.8333333L33 12.8333333L33 5.5L22 5.5Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_navigation.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_navigation.xml
deleted file mode 100644
index e1fabe07cdeb..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_navigation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M39.8016667 20.6983333L23.3016667 4.19833333C22.5866667 3.48333333 21.4316667 3.48333333 20.7166667 4.19833333L4.21666667 20.6983333C3.50166667 21.4133333 3.50166667 22.5683333 4.21666667 23.2833333L20.7166667 39.7833333C21.4316667 40.4983333 22.5866667 40.4983333 23.3016667 39.7833333L39.8016667 23.2833333C40.5166667 22.5866667 40.5166667 21.4316667 39.8016667 20.6983333ZM25.6666667 26.5833333L25.6666667 22L18.3333333 22L18.3333333 27.5L14.6666667 27.5L14.6666667 20.1666667C14.6666667 19.1583333 15.4916667 18.3333333 16.5 18.3333333L25.6666667 18.3333333L25.6666667 13.75L32.0833333 20.1666667L25.6666667 26.5833333Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_notification.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_notification.xml
deleted file mode 100644
index 3c3fefc9782a..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_notification.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="44dp"
- android:height="44dp"
- android:viewportWidth="44"
- android:viewportHeight="44">
- <path
- android:pathData="M22 39.125C23.925 39.125 25.5 37.55 25.5 35.625L18.5 35.625C18.5 37.55 20.0575 39.125 22 39.125ZM32.5 28.625L32.5 19.875C32.5 14.5025 29.63 10.005 24.625 8.815L24.625 7.625C24.625 6.1725 23.4525 5 22 5C20.5475 5 19.375 6.1725 19.375 7.625L19.375 8.815C14.3525 10.005 11.5 14.485 11.5 19.875L11.5 28.625L8 32.125L8 33.875L36 33.875L36 32.125L32.5 28.625Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_overview.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_overview.xml
deleted file mode 100644
index f185eb9afb75..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_overview.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M36.92857 22.39286A14.53571 14.53571 0 0 1 7.857143 22.39286A14.53571 14.53571 0 0 1 36.92857 22.39286Z"
- android:strokeColor="@color/car_nav_icon_fill_color"
- android:strokeWidth="4" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_phone.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_phone.xml
deleted file mode 100644
index 50e36b5a6e3c..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/drawable/car_ic_phone.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M12.1366667 19.7816667C14.7766667 24.97 19.03 29.205 24.2183333 31.8633333L28.2516667 27.83C28.7466667 27.335 29.48 27.17 30.1216667 27.39C32.175 28.0683333 34.3933333 28.435 36.6666667 28.435C37.675 28.435 38.5 29.26 38.5 30.2683333L38.5 36.6666667C38.5 37.675 37.675 38.5 36.6666667 38.5C19.4516667 38.5 5.5 24.5483333 5.5 7.33333333C5.5 6.325 6.325 5.5 7.33333333 5.5L13.75 5.5C14.7583333 5.5 15.5833333 6.325 15.5833333 7.33333333C15.5833333 9.625 15.95 11.825 16.6283333 13.8783333C16.83 14.52 16.6833333 15.235 16.17 15.7483333L12.1366667 19.7816667Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/drawable/system_bar_background.xml b/packages/CarSystemUI/samples/sample2/rro/res/drawable/system_bar_background.xml
deleted file mode 100644
index 6161ad9b041c..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/drawable/system_bar_background.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2020 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
- <corners
- android:topLeftRadius="0dp"
- android:topRightRadius="10dp"
- android:bottomLeftRadius="0dp"
- android:bottomRightRadius="0dp"
- />
- <solid
- android:color="#404040"
- />
- <padding
- android:left="0dp"
- android:top="0dp"
- android:right="0dp"
- android:bottom="0dp"
- />
-</shape> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/layout/car_left_navigation_bar.xml b/packages/CarSystemUI/samples/sample2/rro/res/layout/car_left_navigation_bar.xml
deleted file mode 100644
index bd6065c3de9a..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/layout/car_left_navigation_bar.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:background="@drawable/system_bar_background">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/maps_nav"
- style="@style/NavigationBarButton"
- systemui:categories="android.intent.category.APP_MAPS"
- systemui:icon="@drawable/car_ic_navigation"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;launchFlags=0x14000000;end"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/music_nav"
- style="@style/NavigationBarButton"
- systemui:categories="android.intent.category.APP_MUSIC"
- systemui:icon="@drawable/car_ic_music"
- systemui:intent="intent:#Intent;action=android.car.intent.action.MEDIA_TEMPLATE;launchFlags=0x10000000;end"
- systemui:packages="com.android.car.media"
- systemui:highlightWhenSelected="true"
- />
-
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/grid_nav"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
- systemui:icon="@drawable/car_ic_apps"
- systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/phone_nav"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/car_ic_phone"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
- systemui:packages="com.android.car.dialer"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/notifications"
- style="@style/NavigationBarButton"
- systemui:highlightWhenSelected="true"
- systemui:icon="@drawable/car_ic_notification"
- systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"/>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="bottom"
- android:orientation="vertical">
-
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:singleLine="true"
- android:gravity="center_horizontal"
- android:paddingBottom="20dp"
- />
-
- <Space
- android:layout_height="10dp"
- android:layout_width="match_parent"/>
-
- </LinearLayout>
-
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/values/colors.xml b/packages/CarSystemUI/samples/sample2/rro/res/values/colors.xml
deleted file mode 100644
index c32d638681a2..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/values/colors.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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 xmlns:android="http://schemas.android.com/apk/res/android">
- <color name="car_nav_icon_fill_color">#8F8F8F</color>
- <color name="car_nav_icon_fill_color_selected">#FFFFFF</color>
-</resources>
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/values/config.xml b/packages/CarSystemUI/samples/sample2/rro/res/values/config.xml
deleted file mode 100644
index 89c7bd4df2bc..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/values/config.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?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>
- <!-- Configure which system bars should be displayed. -->
- <bool name="config_enableTopNavigationBar">false</bool>
- <bool name="config_enableLeftNavigationBar">true</bool>
- <bool name="config_enableRightNavigationBar">false</bool>
- <bool name="config_enableBottomNavigationBar">false</bool>
-
- <!-- Configure the type of each system bar. Each system bar must have a unique type. -->
- <!-- STATUS_BAR = 0-->
- <!-- NAVIGATION_BAR = 1-->
- <!-- STATUS_BAR_EXTRA = 2-->
- <!-- NAVIGATION_BAR_EXTRA = 3-->
- <integer name="config_topSystemBarType">0</integer>
- <integer name="config_leftSystemBarType">1</integer>
- <integer name="config_rightSystemBarType">2</integer>
- <integer name="config_bottomSystemBarType">3</integer>
-
- <!-- Configure the relative z-order among the system bars. When two system bars overlap (e.g.
- if both top bar and left bar are enabled, it creates an overlapping space in the upper left
- corner), the system bar with the higher z-order takes the overlapping space and padding is
- applied to the other bar.-->
- <!-- NOTE: If two overlapping system bars have the same z-order, SystemBarConfigs will throw a
- RuntimeException, since their placing order cannot be determined. Bars that do not overlap
- are allowed to have the same z-order. -->
- <!-- NOTE: If the z-order of a bar is 10 or above, it will also appear on top of HUN's. -->
- <integer name="config_topSystemBarZOrder">0</integer>
- <integer name="config_leftSystemBarZOrder">10</integer>
- <integer name="config_rightSystemBarZOrder">10</integer>
- <integer name="config_bottomSystemBarZOrder">10</integer>
-
- <!-- Whether heads-up notifications should be shown on the bottom. If false, heads-up
- notifications will be shown pushed to the top of their parent container. If true, they will
- be shown pushed to the bottom of their parent container. If true, then should override
- config_headsUpNotificationAnimationHelper to use a different AnimationHelper, such as
- com.android.car.notification.headsup.animationhelper.
- CarHeadsUpNotificationBottomAnimationHelper. -->
- <bool name="config_showHeadsUpNotificationOnBottom">true</bool>
-
- <string name="config_notificationPanelViewMediator" translatable="false">com.android.systemui.car.notification.NotificationPanelViewMediator</string>
-</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/values/styles.xml b/packages/CarSystemUI/samples/sample2/rro/res/values/styles.xml
deleted file mode 100644
index 136dc3b6df18..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/values/styles.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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 xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="TextAppearance.StatusBar.Clock"
- parent="@*android:style/TextAppearance.StatusBar.Icon">
- <item name="android:textSize">40sp</item>
- <item name="android:fontFamily">sans-serif-regular</item>
- <item name="android:textColor">#FFFFFF</item>
- </style>
-
- <style name="NavigationBarButton">
- <item name="android:layout_height">96dp</item>
- <item name="android:layout_width">96dp</item>
- <item name="android:background">?android:attr/selectableItemBackground</item>
- </style>
-
- <style name="TextAppearance.CarStatus" parent="@android:style/TextAppearance.DeviceDefault">
- <item name="android:textSize">30sp</item>
- <item name="android:textColor">#FFFFFF</item>
- </style>
-</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample2/rro/res/xml/car_sysui_overlays.xml b/packages/CarSystemUI/samples/sample2/rro/res/xml/car_sysui_overlays.xml
deleted file mode 100644
index 58a535b4e000..000000000000
--- a/packages/CarSystemUI/samples/sample2/rro/res/xml/car_sysui_overlays.xml
+++ /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.
- -->
-
-<overlay>
- <item target="layout/car_left_navigation_bar" value="@layout/car_left_navigation_bar"/>
-
- <item target="attr/icon" value="@attr/icon"/>
- <item target="attr/selectedIcon" value="@attr/selectedIcon"/>
- <item target="attr/intent" value="@attr/intent"/>
- <item target="attr/longIntent" value="@attr/longIntent"/>
- <item target="attr/componentNames" value="@attr/componentNames"/>
- <item target="attr/highlightWhenSelected" value="@attr/highlightWhenSelected"/>
- <item target="attr/categories" value="@attr/categories"/>
- <item target="attr/packages" value="@attr/packages"/>
- <!-- start the intent as a broad cast instead of an activity if true-->
- <item target="attr/broadcast" value="@attr/broadcast"/>
-
- <item target="drawable/car_ic_overview" value="@drawable/car_ic_overview" />
- <item target="drawable/car_ic_apps" value="@drawable/car_ic_apps" />
- <item target="drawable/car_ic_music" value="@drawable/car_ic_music" />
- <item target="drawable/car_ic_phone" value="@drawable/car_ic_phone" />
- <item target="drawable/car_ic_navigation" value="@drawable/car_ic_navigation" />
-
- <item target="style/NavigationBarButton" value="@style/NavigationBarButton"/>
-
- <item target="color/car_nav_icon_fill_color" value="@color/car_nav_icon_fill_color" />
-
- <item target="bool/config_enableTopNavigationBar" value="@bool/config_enableTopNavigationBar"/>
- <item target="bool/config_enableLeftNavigationBar" value="@bool/config_enableLeftNavigationBar"/>
- <item target="bool/config_enableRightNavigationBar" value="@bool/config_enableRightNavigationBar"/>
- <item target="bool/config_enableBottomNavigationBar" value="@bool/config_enableBottomNavigationBar"/>
- <item target="bool/config_showHeadsUpNotificationOnBottom" value="@bool/config_showHeadsUpNotificationOnBottom"/>
-
- <item target="integer/config_topSystemBarType" value="@integer/config_topSystemBarType"/>
- <item target="integer/config_leftSystemBarType" value="@integer/config_leftSystemBarType"/>
- <item target="integer/config_rightSystemBarType" value="@integer/config_rightSystemBarType"/>
- <item target="integer/config_bottomSystemBarType" value="@integer/config_bottomSystemBarType"/>
-
- <item target="integer/config_topSystemBarZOrder" value="@integer/config_topSystemBarZOrder"/>
- <item target="integer/config_leftSystemBarZOrder" value="@integer/config_leftSystemBarZOrder"/>
- <item target="integer/config_rightSystemBarZOrder" value="@integer/config_rightSystemBarZOrder"/>
- <item target="integer/config_bottomSystemBarZOrder" value="@integer/config_bottomSystemBarZOrder"/>
-
- <item target="string/config_notificationPanelViewMediator" value="@string/config_notificationPanelViewMediator"/>
-
- <item target="id/home" value="@id/home"/>
- <item target="id/maps_nav" value="@id/maps_nav"/>
- <item target="id/music_nav" value="@id/music_nav"/>
- <item target="id/grid_nav" value="@id/grid_nav"/>
- <item target="id/phone_nav" value="@id/phone_nav"/>
- <item target="id/notifications" value="@id/notifications"/>
-</overlay> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample3/rro/AndroidManifest.xml b/packages/CarSystemUI/samples/sample3/rro/AndroidManifest.xml
deleted file mode 100644
index 5c25056f7915..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/AndroidManifest.xml
+++ /dev/null
@@ -1,24 +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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.systemui.rro">
- <overlay
- android:targetPackage="com.android.systemui"
- android:isStatic="false"
- android:resourcesMap="@xml/car_sysui_overlays"
- />
-</manifest> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_apps.xml b/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_apps.xml
deleted file mode 100644
index a8d8a2f241f6..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_apps.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
-<path
- android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_hvac.xml b/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_hvac.xml
deleted file mode 100644
index 55c968eacc4d..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_hvac.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:pathData="M16.34,8.36l-2.29,0.82c-0.18,-0.13 -0.38,-0.25 -0.58,-0.34c0.17,-0.83 0.63,-1.58 1.36,-2.06C16.85,5.44 16.18,2 13.39,2C9,2 7.16,5.01 8.36,7.66l0.82,2.29c-0.13,0.18 -0.25,0.38 -0.34,0.58c-0.83,-0.17 -1.58,-0.63 -2.06,-1.36C5.44,7.15 2,7.82 2,10.61c0,4.4 3.01,6.24 5.66,5.03l2.29,-0.82c0.18,0.13 0.38,0.25 0.58,0.34c-0.17,0.83 -0.63,1.58 -1.36,2.06C7.15,18.56 7.82,22 10.61,22c4.4,0 6.24,-3.01 5.03,-5.66l-0.82,-2.29c0.13,-0.18 0.25,-0.38 0.34,-0.58c0.83,0.17 1.58,0.63 2.06,1.36c1.34,2.01 4.77,1.34 4.77,-1.45C22,9 18.99,7.16 16.34,8.36zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM10.24,5.22C10.74,4.44 11.89,4 13.39,4c0.79,0 0.71,0.86 0.34,1.11c-1.22,0.81 -2,2.06 -2.25,3.44c-0.21,0.03 -0.42,0.08 -0.62,0.15l-0.68,-1.88C10,6.42 9.86,5.81 10.24,5.22zM6.83,13.82c-0.4,0.18 -1.01,0.32 -1.61,-0.06C4.44,13.26 4,12.11 4,10.61c0,-0.79 0.86,-0.71 1.11,-0.34c0.81,1.22 2.06,2 3.44,2.25c0.03,0.21 0.08,0.42 0.15,0.62L6.83,13.82zM13.76,18.78c-0.5,0.77 -1.65,1.22 -3.15,1.22c-0.79,0 -0.71,-0.86 -0.34,-1.11c1.22,-0.81 2,-2.06 2.25,-3.44c0.21,-0.03 0.42,-0.08 0.62,-0.15l0.68,1.88C14,17.58 14.14,18.18 13.76,18.78zM18.89,13.73c-0.81,-1.22 -2.06,-2 -3.44,-2.25c-0.03,-0.21 -0.08,-0.42 -0.15,-0.62l1.88,-0.68c0.4,-0.18 1.01,-0.32 1.61,0.06c0.77,0.5 1.22,1.65 1.22,3.15C20,14.19 19.14,14.11 18.89,13.73z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector>
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_music.xml b/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_music.xml
deleted file mode 100644
index 6339ebb3ea8d..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_music.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M22 5.5L22 24.8416667C20.9183333 24.2183333 19.6716667 23.8333333 18.3333333 23.8333333C14.2816667 23.8333333 11 27.115 11 31.1666667C11 35.2183333 14.2816667 38.5 18.3333333 38.5C22.385 38.5 25.6666667 35.2183333 25.6666667 31.1666667L25.6666667 12.8333333L33 12.8333333L33 5.5L22 5.5Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_navigation.xml b/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_navigation.xml
deleted file mode 100644
index e1fabe07cdeb..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_navigation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M39.8016667 20.6983333L23.3016667 4.19833333C22.5866667 3.48333333 21.4316667 3.48333333 20.7166667 4.19833333L4.21666667 20.6983333C3.50166667 21.4133333 3.50166667 22.5683333 4.21666667 23.2833333L20.7166667 39.7833333C21.4316667 40.4983333 22.5866667 40.4983333 23.3016667 39.7833333L39.8016667 23.2833333C40.5166667 22.5866667 40.5166667 21.4316667 39.8016667 20.6983333ZM25.6666667 26.5833333L25.6666667 22L18.3333333 22L18.3333333 27.5L14.6666667 27.5L14.6666667 20.1666667C14.6666667 19.1583333 15.4916667 18.3333333 16.5 18.3333333L25.6666667 18.3333333L25.6666667 13.75L32.0833333 20.1666667L25.6666667 26.5833333Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_notification.xml b/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_notification.xml
deleted file mode 100644
index aabf9161c11f..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_notification.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
- android:viewportWidth="44"
- android:viewportHeight="44">
- <path
- android:pathData="M22 39.125C23.925 39.125 25.5 37.55 25.5 35.625L18.5 35.625C18.5 37.55 20.0575 39.125 22 39.125ZM32.5 28.625L32.5 19.875C32.5 14.5025 29.63 10.005 24.625 8.815L24.625 7.625C24.625 6.1725 23.4525 5 22 5C20.5475 5 19.375 6.1725 19.375 7.625L19.375 8.815C14.3525 10.005 11.5 14.485 11.5 19.875L11.5 28.625L8 32.125L8 33.875L36 33.875L36 32.125L32.5 28.625Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_overview.xml b/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_overview.xml
deleted file mode 100644
index f185eb9afb75..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_overview.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M36.92857 22.39286A14.53571 14.53571 0 0 1 7.857143 22.39286A14.53571 14.53571 0 0 1 36.92857 22.39286Z"
- android:strokeColor="@color/car_nav_icon_fill_color"
- android:strokeWidth="4" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_phone.xml b/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_phone.xml
deleted file mode 100644
index 50e36b5a6e3c..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_phone.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
- android:pathData="M12.1366667 19.7816667C14.7766667 24.97 19.03 29.205 24.2183333 31.8633333L28.2516667 27.83C28.7466667 27.335 29.48 27.17 30.1216667 27.39C32.175 28.0683333 34.3933333 28.435 36.6666667 28.435C37.675 28.435 38.5 29.26 38.5 30.2683333L38.5 36.6666667C38.5 37.675 37.675 38.5 36.6666667 38.5C19.4516667 38.5 5.5 24.5483333 5.5 7.33333333C5.5 6.325 6.325 5.5 7.33333333 5.5L13.75 5.5C14.7583333 5.5 15.5833333 6.325 15.5833333 7.33333333C15.5833333 9.625 15.95 11.825 16.6283333 13.8783333C16.83 14.52 16.6833333 15.235 16.17 15.7483333L12.1366667 19.7816667Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/layout/car_left_navigation_bar.xml b/packages/CarSystemUI/samples/sample3/rro/res/layout/car_left_navigation_bar.xml
deleted file mode 100644
index 3d1cd085e578..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/layout/car_left_navigation_bar.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 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.
-*/
--->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:background="@android:color/transparent">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="bottom"
- android:orientation="vertical">
-
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:singleLine="true"
- android:gravity="center_horizontal"
- android:paddingBottom="20dp"
- />
-
- <Space
- android:layout_height="50dp"
- android:layout_width="match_parent"/>
-
- </LinearLayout>
-
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/samples/sample3/rro/res/layout/car_navigation_bar.xml
deleted file mode 100644
index 8314ba5600a9..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/layout/car_navigation_bar.xml
+++ /dev/null
@@ -1,122 +0,0 @@
-<?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.
- -->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/system_bar_background"
- android:gravity="center"
- android:orientation="horizontal">
-
- <RelativeLayout
- android:id="@+id/nav_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layoutDirection="ltr">
-
- <com.android.systemui.car.hvac.AdjustableTemperatureView
- android:id="@+id/driver_hvac"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- systemui:hvacAreaId="49"
- systemui:hvacTempFormat="%.0f\u00B0" />
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_centerInParent="true"
- android:layout_weight="1"
- android:gravity="center"
- android:layoutDirection="ltr"
- android:paddingEnd="@dimen/system_bar_button_group_padding"
- android:paddingStart="@dimen/system_bar_button_group_padding">
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:highlightWhenSelected="true"
- systemui:icon="@drawable/car_ic_home"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/phone_nav"
- style="@style/NavigationBarButton"
- systemui:highlightWhenSelected="true"
- systemui:icon="@drawable/car_ic_phone"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
- systemui:packages="com.android.car.dialer"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/grid_nav"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
- systemui:highlightWhenSelected="true"
- systemui:icon="@drawable/car_ic_apps"
- systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvac"
- style="@style/NavigationBarButton"
- systemui:highlightWhenSelected="true"
- systemui:icon="@drawable/car_ic_hvac"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- systemui:broadcast="true"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/notifications"
- style="@style/NavigationBarButton"
- systemui:highlightWhenSelected="true"
- systemui:icon="@drawable/car_ic_notification"
- systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"/>
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
- </LinearLayout>
-
- <com.android.systemui.car.hvac.AdjustableTemperatureView
- android:id="@+id/passenger_hvac"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentEnd="true"
- android:gravity="center_vertical"
- systemui:hvacAreaId="68"
- systemui:hvacTempFormat="%.0f\u00B0" />
- </RelativeLayout>
-
- <LinearLayout
- android:id="@+id/lock_screen_nav_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:layoutDirection="ltr"
- android:paddingEnd="@dimen/car_keyline_1"
- android:paddingStart="@dimen/car_keyline_1"
- android:visibility="gone"
- />
-</com.android.systemui.car.navigationbar.CarNavigationBarView> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/values/attrs.xml b/packages/CarSystemUI/samples/sample3/rro/res/values/attrs.xml
deleted file mode 100644
index bc7ded20031a..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/values/attrs.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?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>
- <attr name="broadcast" format="boolean"/>
- <attr name="icon" format="reference"/>
- <attr name="intent" format="string"/>
- <attr name="longIntent" format="string"/>
- <attr name="componentNames" format="string" />
- <attr name="highlightWhenSelected" format="boolean" />
- <attr name="categories" format="string"/>
- <attr name="packages" format="string" />
-
- <!-- Custom attributes to configure hvac values -->
- <declare-styleable name="AnimatedTemperatureView">
- <attr name="hvacAreaId" format="integer"/>
- <attr name="hvacPropertyId" format="integer"/>
- <attr name="hvacTempFormat" format="string"/>
- <!-- how far away the animations should center around -->
- <attr name="hvacPivotOffset" format="dimension"/>
- <attr name="hvacMinValue" format="float"/>
- <attr name="hvacMaxValue" format="float"/>
- <attr name="hvacMinText" format="string|reference"/>
- <attr name="hvacMaxText" format="string|reference"/>
- <attr name="android:gravity"/>
- <attr name="android:minEms"/>
- <attr name="android:textAppearance"/>
- </declare-styleable>
-</resources>
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/values/config.xml b/packages/CarSystemUI/samples/sample3/rro/res/values/config.xml
deleted file mode 100644
index 2148e7cbfd96..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/values/config.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?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>
- <!-- Configure which system bars should be displayed. -->
- <bool name="config_enableTopNavigationBar">false</bool>
- <bool name="config_enableLeftNavigationBar">true</bool>
- <bool name="config_enableRightNavigationBar">false</bool>
- <bool name="config_enableBottomNavigationBar">true</bool>
-
- <!-- Configure the type of each system bar. Each system bar must have a unique type. -->
- <!-- STATUS_BAR = 0-->
- <!-- NAVIGATION_BAR = 1-->
- <!-- STATUS_BAR_EXTRA = 2-->
- <!-- NAVIGATION_BAR_EXTRA = 3-->
- <integer name="config_topSystemBarType">2</integer>
- <integer name="config_leftSystemBarType">0</integer>
- <integer name="config_rightSystemBarType">3</integer>
- <integer name="config_bottomSystemBarType">1</integer>
-
- <!-- Configure the relative z-order among the system bars. When two system bars overlap (e.g.
- if both top bar and left bar are enabled, it creates an overlapping space in the upper left
- corner), the system bar with the higher z-order takes the overlapping space and padding is
- applied to the other bar.-->
- <!-- NOTE: If two overlapping system bars have the same z-order, SystemBarConfigs will throw a
- RuntimeException, since their placing order cannot be determined. Bars that do not overlap
- are allowed to have the same z-order. -->
- <!-- NOTE: If the z-order of a bar is 10 or above, it will also appear on top of HUN's. -->
- <integer name="config_topSystemBarZOrder">0</integer>
- <integer name="config_leftSystemBarZOrder">10</integer>
- <integer name="config_rightSystemBarZOrder">0</integer>
- <integer name="config_bottomSystemBarZOrder">15</integer>
-
- <!-- Whether heads-up notifications should be shown on the bottom. If false, heads-up
- notifications will be shown pushed to the top of their parent container. If true, they will
- be shown pushed to the bottom of their parent container. If true, then should override
- config_headsUpNotificationAnimationHelper to use a different AnimationHelper, such as
- com.android.car.notification.headsup.animationhelper.
- CarHeadsUpNotificationBottomAnimationHelper. -->
- <bool name="config_showHeadsUpNotificationOnBottom">false</bool>
-
- <string name="config_notificationPanelViewMediator" translatable="false">com.android.systemui.car.notification.BottomNotificationPanelViewMediator</string>
-</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/values/dimens.xml b/packages/CarSystemUI/samples/sample3/rro/res/values/dimens.xml
deleted file mode 100644
index c89f94938582..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/values/dimens.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2018 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<resources>
- <dimen name="car_left_navigation_bar_width">280dp</dimen>
- <dimen name="car_keyline_1">24dp</dimen>
- <dimen name="system_bar_button_group_padding">64dp</dimen>
- <dimen name="system_bar_icon_drawing_size">44dp</dimen>
-</resources>
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/values/styles.xml b/packages/CarSystemUI/samples/sample3/rro/res/values/styles.xml
deleted file mode 100644
index bad36917d2cf..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/values/styles.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?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 xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="TextAppearance.StatusBar.Clock"
- parent="@*android:style/TextAppearance.StatusBar.Icon">
- <item name="android:textSize">40sp</item>
- <item name="android:fontFamily">sans-serif-regular</item>
- <item name="android:textColor">#FFFFFF</item>
- </style>
-
- <style name="NavigationBarButton">
- <item name="android:layout_height">96dp</item>
- <item name="android:layout_width">96dp</item>
- <item name="android:background">?android:attr/selectableItemBackground</item>
- </style>
-</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/xml/car_sysui_overlays.xml b/packages/CarSystemUI/samples/sample3/rro/res/xml/car_sysui_overlays.xml
deleted file mode 100644
index f08d9684f2d5..000000000000
--- a/packages/CarSystemUI/samples/sample3/rro/res/xml/car_sysui_overlays.xml
+++ /dev/null
@@ -1,75 +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.
- -->
-
-<overlay>
- <item target="layout/car_navigation_bar" value="@layout/car_navigation_bar"/>
- <item target="layout/car_left_navigation_bar" value="@layout/car_left_navigation_bar"/>
-
- <item target="bool/config_enableTopNavigationBar" value="@bool/config_enableTopNavigationBar"/>
- <item target="bool/config_enableLeftNavigationBar" value="@bool/config_enableLeftNavigationBar"/>
- <item target="bool/config_enableRightNavigationBar" value="@bool/config_enableRightNavigationBar"/>
- <item target="bool/config_enableBottomNavigationBar" value="@bool/config_enableBottomNavigationBar"/>
- <item target="bool/config_showHeadsUpNotificationOnBottom" value="@bool/config_showHeadsUpNotificationOnBottom"/>
-
- <item target="attr/icon" value="@attr/icon"/>
- <item target="attr/intent" value="@attr/intent"/>
- <item target="attr/longIntent" value="@attr/longIntent"/>
- <item target="attr/componentNames" value="@attr/componentNames"/>
- <item target="attr/highlightWhenSelected" value="@attr/highlightWhenSelected"/>
- <item target="attr/categories" value="@attr/categories"/>
- <item target="attr/packages" value="@attr/packages"/>
- <item target="attr/hvacAreaId" value="@attr/hvacAreaId"/>
- <item target="attr/hvacPropertyId" value="@attr/hvacPropertyId"/>
- <item target="attr/hvacTempFormat" value="@attr/hvacTempFormat"/>
- <item target="attr/hvacPivotOffset" value="@attr/hvacPivotOffset"/>
- <item target="attr/hvacMinValue" value="@attr/hvacMinValue"/>
- <item target="attr/hvacMaxValue" value="@attr/hvacMaxValue"/>
- <item target="attr/hvacMinText" value="@attr/hvacMinText"/>
- <item target="attr/hvacMaxText" value="@attr/hvacMaxText"/>
- <!-- start the intent as a broad cast instead of an activity if true-->
- <item target="attr/broadcast" value="@attr/broadcast"/>
-
- <item target="color/car_nav_icon_fill_color" value="@color/car_nav_icon_fill_color" />
-
- <item target="drawable/car_ic_overview" value="@drawable/car_ic_overview" />
- <item target="drawable/car_ic_home" value="@drawable/car_ic_home" />
- <item target="drawable/car_ic_hvac" value="@drawable/car_ic_hvac" />
- <item target="drawable/car_ic_apps" value="@drawable/car_ic_apps" />
- <item target="drawable/car_ic_music" value="@drawable/car_ic_music" />
- <item target="drawable/car_ic_notification" value="@drawable/car_ic_notification" />
- <item target="drawable/car_ic_phone" value="@drawable/car_ic_phone" />
- <item target="drawable/car_ic_navigation" value="@drawable/car_ic_navigation" />
-
- <item target="dimen/car_left_navigation_bar_width" value="@dimen/car_left_navigation_bar_width" />
- <item target="dimen/car_keyline_1" value="@dimen/car_keyline_1" />
- <item target="dimen/system_bar_button_group_padding" value="@dimen/system_bar_button_group_padding" />
- <item target="dimen/system_bar_icon_drawing_size" value="@dimen/system_bar_icon_drawing_size" />
-
- <item target="integer/config_topSystemBarType" value="@integer/config_topSystemBarType"/>
- <item target="integer/config_leftSystemBarType" value="@integer/config_leftSystemBarType"/>
- <item target="integer/config_rightSystemBarType" value="@integer/config_rightSystemBarType"/>
- <item target="integer/config_bottomSystemBarType" value="@integer/config_bottomSystemBarType"/>
-
- <item target="integer/config_topSystemBarZOrder" value="@integer/config_topSystemBarZOrder"/>
- <item target="integer/config_leftSystemBarZOrder" value="@integer/config_leftSystemBarZOrder"/>
- <item target="integer/config_rightSystemBarZOrder" value="@integer/config_rightSystemBarZOrder"/>
- <item target="integer/config_bottomSystemBarZOrder" value="@integer/config_bottomSystemBarZOrder"/>
-
- <item target="string/config_notificationPanelViewMediator" value="@string/config_notificationPanelViewMediator"/>
-
- <item target="style/NavigationBarButton" value="@style/NavigationBarButton"/>
-</overlay> \ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java
deleted file mode 100644
index b056dcf8fd2b..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java
+++ /dev/null
@@ -1,53 +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.systemui;
-
-import com.android.systemui.dagger.GlobalModule;
-import com.android.systemui.dagger.GlobalRootComponent;
-import com.android.systemui.dagger.WMModule;
-import com.android.systemui.wmshell.CarWMComponent;
-
-import javax.inject.Singleton;
-
-import dagger.Component;
-
-/** Car subclass for GlobalRootComponent. */
-@Singleton
-@Component(
- modules = {
- GlobalModule.class,
- CarSysUIComponentModule.class,
- WMModule.class
- })
-public interface CarGlobalRootComponent extends GlobalRootComponent {
- /**
- * Builder for a CarGlobalRootComponent.
- */
- @Component.Builder
- interface Builder extends GlobalRootComponent.Builder {
- CarGlobalRootComponent build();
- }
-
- /**
- * Builder for a WMComponent.
- */
- @Override
- CarWMComponent.Builder getWMComponentBuilder();
-
- @Override
- CarSysUIComponent.Builder getSysUIComponent();
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
deleted file mode 100644
index 51855dc648e9..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
+++ /dev/null
@@ -1,45 +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.systemui;
-
-import com.android.systemui.dagger.DependencyProvider;
-import com.android.systemui.dagger.SysUIComponent;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.SystemUIModule;
-
-import dagger.Subcomponent;
-
-/**
- * Dagger Subcomponent for Core SysUI.
- */
-@SysUISingleton
-@Subcomponent(modules = {
- CarComponentBinder.class,
- DependencyProvider.class,
- SystemUIModule.class,
- CarSystemUIModule.class,
- CarSystemUIBinder.class})
-public interface CarSysUIComponent extends SysUIComponent {
-
- /**
- * Builder for a CarSysUIComponent.
- */
- @Subcomponent.Builder
- interface Builder extends SysUIComponent.Builder {
- CarSysUIComponent build();
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
deleted file mode 100644
index 3def945dd03c..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ /dev/null
@@ -1,181 +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.systemui;
-
-import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.bubbles.dagger.BubbleModule;
-import com.android.systemui.car.navigationbar.CarNavigationBar;
-import com.android.systemui.car.notification.CarNotificationModule;
-import com.android.systemui.car.sideloaded.SideLoadedAppController;
-import com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier;
-import com.android.systemui.car.volume.VolumeUI;
-import com.android.systemui.car.window.OverlayWindowModule;
-import com.android.systemui.car.window.SystemUIOverlayWindowManager;
-import com.android.systemui.globalactions.GlobalActionsComponent;
-import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.keyguard.dagger.KeyguardModule;
-import com.android.systemui.power.PowerUI;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsModule;
-import com.android.systemui.shortcut.ShortcutKeyDispatcher;
-import com.android.systemui.statusbar.dagger.StatusBarModule;
-import com.android.systemui.statusbar.notification.InstantAppNotifier;
-import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.theme.ThemeOverlayController;
-import com.android.systemui.toast.ToastUI;
-import com.android.systemui.util.leak.GarbageMonitor;
-import com.android.systemui.wmshell.WMShell;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-
-/** Binder for car specific {@link SystemUI} modules. */
-@Module(includes = {RecentsModule.class, StatusBarModule.class, NotificationsModule.class,
- BubbleModule.class, KeyguardModule.class, OverlayWindowModule.class,
- CarNotificationModule.class})
-public abstract class CarSystemUIBinder {
- /** Inject into AuthController. */
- @Binds
- @IntoMap
- @ClassKey(AuthController.class)
- public abstract SystemUI bindAuthController(AuthController sysui);
-
- /** Inject Car Navigation Bar. */
- @Binds
- @IntoMap
- @ClassKey(CarNavigationBar.class)
- public abstract SystemUI bindCarNavigationBar(CarNavigationBar sysui);
-
- /** Inject into GarbageMonitor.Service. */
- @Binds
- @IntoMap
- @ClassKey(GarbageMonitor.Service.class)
- public abstract SystemUI bindGarbageMonitorService(GarbageMonitor.Service sysui);
-
- /** Inject into GlobalActionsComponent. */
- @Binds
- @IntoMap
- @ClassKey(GlobalActionsComponent.class)
- public abstract SystemUI bindGlobalActionsComponent(GlobalActionsComponent sysui);
-
- /** Inject into InstantAppNotifier. */
- @Binds
- @IntoMap
- @ClassKey(InstantAppNotifier.class)
- public abstract SystemUI bindInstantAppNotifier(InstantAppNotifier sysui);
-
- /** Inject into KeyguardViewMediator. */
- @Binds
- @IntoMap
- @ClassKey(KeyguardViewMediator.class)
- public abstract SystemUI bindKeyguardViewMediator(KeyguardViewMediator sysui);
-
- /** Inject into LatencyTests. */
- @Binds
- @IntoMap
- @ClassKey(LatencyTester.class)
- public abstract SystemUI bindLatencyTester(LatencyTester sysui);
-
- /** Inject into PowerUI. */
- @Binds
- @IntoMap
- @ClassKey(PowerUI.class)
- public abstract SystemUI bindPowerUI(PowerUI sysui);
-
- /** Inject into Recents. */
- @Binds
- @IntoMap
- @ClassKey(Recents.class)
- public abstract SystemUI bindRecents(Recents sysui);
-
- /** Inject into ScreenDecorations. */
- @Binds
- @IntoMap
- @ClassKey(ScreenDecorations.class)
- public abstract SystemUI bindScreenDecorations(ScreenDecorations sysui);
-
- /** Inject into ShortcutKeyDispatcher. */
- @Binds
- @IntoMap
- @ClassKey(ShortcutKeyDispatcher.class)
- public abstract SystemUI bindsShortcutKeyDispatcher(ShortcutKeyDispatcher sysui);
-
- /** Inject into SizeCompatModeActivityController. */
- @Binds
- @IntoMap
- @ClassKey(SizeCompatModeActivityController.class)
- public abstract SystemUI bindsSizeCompatModeActivityController(
- SizeCompatModeActivityController sysui);
-
- /** Inject into SliceBroadcastRelayHandler. */
- @Binds
- @IntoMap
- @ClassKey(SliceBroadcastRelayHandler.class)
- public abstract SystemUI bindSliceBroadcastRelayHandler(SliceBroadcastRelayHandler sysui);
-
- /** Inject into ThemeOverlayController. */
- @Binds
- @IntoMap
- @ClassKey(ThemeOverlayController.class)
- public abstract SystemUI bindThemeOverlayController(ThemeOverlayController sysui);
-
- /** Inject into StatusBar. */
- @Binds
- @IntoMap
- @ClassKey(StatusBar.class)
- public abstract SystemUI bindsStatusBar(StatusBar sysui);
-
- /** Inject into VolumeUI. */
- @Binds
- @IntoMap
- @ClassKey(VolumeUI.class)
- public abstract SystemUI bindVolumeUI(VolumeUI sysui);
-
- /** Inject into ToastUI. */
- @Binds
- @IntoMap
- @ClassKey(ToastUI.class)
- public abstract SystemUI bindToastUI(ToastUI service);
-
- /** Inject into ConnectedDeviceVoiceRecognitionNotifier. */
- @Binds
- @IntoMap
- @ClassKey(ConnectedDeviceVoiceRecognitionNotifier.class)
- public abstract SystemUI bindConnectedDeviceVoiceRecognitionNotifier(
- ConnectedDeviceVoiceRecognitionNotifier sysui);
-
- /** Inject into SystemUIOverlayWindowManager. */
- @Binds
- @IntoMap
- @ClassKey(SystemUIOverlayWindowManager.class)
- public abstract SystemUI bindSystemUIPrimaryWindowManager(SystemUIOverlayWindowManager sysui);
-
- /** Inject into SideLoadedAppController. */
- @Binds
- @IntoMap
- @ClassKey(SideLoadedAppController.class)
- public abstract SystemUI bindSideLoadedAppController(SideLoadedAppController sysui);
-
- /** Inject into WMShell. */
- @Binds
- @IntoMap
- @ClassKey(WMShell.class)
- public abstract SystemUI bindWMShell(WMShell sysui);
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
deleted file mode 100644
index a65edc5477df..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
+++ /dev/null
@@ -1,60 +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;
-
-import android.content.Context;
-import android.content.res.Resources;
-
-import com.android.systemui.dagger.GlobalRootComponent;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Class factory to provide car specific SystemUI components.
- */
-public class CarSystemUIFactory extends SystemUIFactory {
-
- @Override
- protected GlobalRootComponent buildGlobalRootComponent(Context context) {
- return DaggerCarGlobalRootComponent.builder()
- .context(context)
- .build();
- }
-
- @Override
- public String[] getSystemUIServiceComponents(Resources resources) {
- Set<String> names = new HashSet<>();
-
- for (String s : super.getSystemUIServiceComponents(resources)) {
- names.add(s);
- }
-
- for (String s : resources.getStringArray(R.array.config_systemUIServiceComponentsExclude)) {
- names.remove(s);
- }
-
- for (String s : resources.getStringArray(R.array.config_systemUIServiceComponentsInclude)) {
- names.add(s);
- }
-
- String[] finalNames = new String[names.size()];
- names.toArray(finalNames);
-
- return finalNames;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
deleted file mode 100644
index 1d35bbb84464..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ /dev/null
@@ -1,176 +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.systemui;
-
-import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
-import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.PowerManager;
-
-import com.android.keyguard.KeyguardViewController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarDeviceProvisionedControllerImpl;
-import com.android.systemui.car.keyguard.CarKeyguardViewController;
-import com.android.systemui.car.notification.NotificationShadeWindowControllerImpl;
-import com.android.systemui.car.statusbar.DozeServiceHost;
-import com.android.systemui.car.volume.CarVolumeDialogComponent;
-import com.android.systemui.dagger.GlobalRootComponent;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.dock.DockManager;
-import com.android.systemui.dock.DockManagerImpl;
-import com.android.systemui.doze.DozeHost;
-import com.android.systemui.plugins.qs.QSFactory;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.power.EnhancedEstimates;
-import com.android.systemui.power.EnhancedEstimatesImpl;
-import com.android.systemui.qs.dagger.QSModule;
-import com.android.systemui.qs.tileimpl.QSFactoryImpl;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsImplementation;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
-import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.ShadeControllerImpl;
-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;
-import com.android.systemui.volume.VolumeDialogComponent;
-
-import javax.inject.Named;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-
-@Module(
- includes = {
- QSModule.class
- })
-abstract class CarSystemUIModule {
-
- @SysUISingleton
- @Provides
- @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME)
- static boolean provideAllowNotificationLongPress() {
- return false;
- }
-
- @SysUISingleton
- @Provides
- static HeadsUpManagerPhone provideHeadsUpManagerPhone(
- Context context,
- StatusBarStateController statusBarStateController,
- KeyguardBypassController bypassController,
- GroupMembershipManager groupManager,
- ConfigurationController configurationController) {
- return new HeadsUpManagerPhone(context, statusBarStateController, bypassController,
- groupManager, configurationController);
- }
-
- @SysUISingleton
- @Provides
- @Named(LEAK_REPORT_EMAIL_NAME)
- static String provideLeakReportEmail() {
- return "buganizer-system+181579@google.com";
- }
-
- @Provides
- @SysUISingleton
- static Recents provideRecents(Context context, RecentsImplementation recentsImplementation,
- CommandQueue commandQueue) {
- return new Recents(context, recentsImplementation, commandQueue);
- }
-
- @Binds
- abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone);
-
- @Binds
- abstract EnhancedEstimates bindEnhancedEstimates(EnhancedEstimatesImpl enhancedEstimates);
-
- @Binds
- abstract NotificationLockscreenUserManager bindNotificationLockscreenUserManager(
- NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
-
- @Provides
- @SysUISingleton
- static BatteryController provideBatteryController(Context context,
- EnhancedEstimates enhancedEstimates, PowerManager powerManager,
- BroadcastDispatcher broadcastDispatcher, DemoModeController demoModeController,
- @Main Handler mainHandler,
- @Background Handler bgHandler) {
- BatteryController bC = new BatteryControllerImpl(context, enhancedEstimates, powerManager,
- broadcastDispatcher, demoModeController, mainHandler, bgHandler);
- bC.init();
- return bC;
- }
-
- @Binds
- @SysUISingleton
- public abstract QSFactory bindQSFactory(QSFactoryImpl qsFactoryImpl);
-
- @Binds
- abstract DockManager bindDockManager(DockManagerImpl dockManager);
-
- @Binds
- abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment(
- KeyguardEnvironmentImpl keyguardEnvironment);
-
- @Binds
- abstract ShadeController provideShadeController(ShadeControllerImpl shadeController);
-
- @Binds
- abstract GlobalRootComponent bindGlobalRootComponent(
- CarGlobalRootComponent globalRootComponent);
-
- @Binds
- abstract VolumeDialogComponent bindVolumeDialogComponent(
- CarVolumeDialogComponent carVolumeDialogComponent);
-
- @Binds
- abstract KeyguardViewController bindKeyguardViewController(
- CarKeyguardViewController carKeyguardViewController);
-
- @Binds
- abstract NotificationShadeWindowController bindNotificationShadeController(
- NotificationShadeWindowControllerImpl notificationPanelViewController);
-
- @Binds
- abstract DeviceProvisionedController bindDeviceProvisionedController(
- CarDeviceProvisionedControllerImpl deviceProvisionedController);
-
- @Binds
- abstract CarDeviceProvisionedController bindCarDeviceProvisionedController(
- CarDeviceProvisionedControllerImpl deviceProvisionedController);
-
- @Binds
- abstract DozeHost bindDozeHost(DozeServiceHost dozeServiceHost);
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedController.java b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedController.java
deleted file mode 100644
index 44e43fe9af8c..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedController.java
+++ /dev/null
@@ -1,44 +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.systemui.car;
-
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-
-/**
- * This interface defines controller that monitors the status of SUW progress for each user in
- * addition to the functionality defined by {@link DeviceProvisionedController}.
- */
-public interface CarDeviceProvisionedController extends DeviceProvisionedController {
- /**
- * Returns {@code true} when SUW is in progress for the given user.
- */
- boolean isUserSetupInProgress(int user);
-
- /**
- * Returns {@code true} when SUW is in progress for the current user.
- */
- default boolean isCurrentUserSetupInProgress() {
- return isUserSetupInProgress(getCurrentUser());
- }
-
- /**
- * Returns {@code true} when the user is setup and not currently in SUW.
- */
- default boolean isCurrentUserFullySetup() {
- return isCurrentUserSetup() && !isCurrentUserSetupInProgress();
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
deleted file mode 100644
index fef032414bb9..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedControllerImpl.java
+++ /dev/null
@@ -1,119 +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.systemui.car;
-
-import android.annotation.NonNull;
-import android.app.ActivityManager;
-import android.car.settings.CarSettings;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
-import com.android.systemui.util.settings.GlobalSettings;
-import com.android.systemui.util.settings.SecureSettings;
-
-import javax.inject.Inject;
-
-/**
- * A controller that monitors the status of SUW progress for each user in addition to the
- * functionality provided by {@link DeviceProvisionedControllerImpl}.
- */
-@SysUISingleton
-public class CarDeviceProvisionedControllerImpl extends DeviceProvisionedControllerImpl implements
- CarDeviceProvisionedController {
- private final Uri mUserSetupInProgressUri;
- private final ContentObserver mCarSettingsObserver;
- private final Handler mMainHandler;
- private final SecureSettings mSecureSettings;
-
- @Inject
- public CarDeviceProvisionedControllerImpl(@Main Handler mainHandler,
- BroadcastDispatcher broadcastDispatcher, GlobalSettings globalSetting,
- SecureSettings secureSettings) {
- super(mainHandler, broadcastDispatcher, globalSetting, secureSettings);
- mMainHandler = mainHandler;
- mSecureSettings = secureSettings;
- mUserSetupInProgressUri = mSecureSettings.getUriFor(
- CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS);
- mCarSettingsObserver = new ContentObserver(mMainHandler) {
- @Override
- public void onChange(boolean selfChange, Uri uri, int flags) {
- if (mUserSetupInProgressUri.equals(uri)) {
- notifyUserSetupInProgressChanged();
- }
- }
- };
- }
-
- @Override
- public boolean isUserSetupInProgress(int user) {
- return mSecureSettings.getIntForUser(
- CarSettings.Secure.KEY_SETUP_WIZARD_IN_PROGRESS, /* def= */ 0, user) != 0;
- }
-
- @Override
- public boolean isCurrentUserSetupInProgress() {
- return isUserSetupInProgress(ActivityManager.getCurrentUser());
- }
-
- @Override
- public void addCallback(@NonNull DeviceProvisionedListener listener) {
- super.addCallback(listener);
- if (listener instanceof CarDeviceProvisionedListener) {
- ((CarDeviceProvisionedListener) listener).onUserSetupInProgressChanged();
- }
- }
-
- @Override
- protected void startListening(int user) {
- mSecureSettings.registerContentObserverForUser(
- mUserSetupInProgressUri, /* notifyForDescendants= */ true,
- mCarSettingsObserver, user);
- // The SUW Flag observer is registered before super.startListening() so that the observer is
- // in place before DeviceProvisionedController starts to track user switches which avoids
- // an edge case where our observer gets registered twice.
- super.startListening(user);
- }
-
- @Override
- protected void stopListening() {
- super.stopListening();
- mSecureSettings.unregisterContentObserver(mCarSettingsObserver);
- }
-
- @Override
- public void onUserSwitched(int newUserId) {
- super.onUserSwitched(newUserId);
- mSecureSettings.unregisterContentObserver(mCarSettingsObserver);
- mSecureSettings.registerContentObserverForUser(
- mUserSetupInProgressUri, /* notifyForDescendants= */ true,
- mCarSettingsObserver, newUserId);
- }
-
- private void notifyUserSetupInProgressChanged() {
- for (int i = mListeners.size() - 1; i >= 0; --i) {
- DeviceProvisionedListener listener = mListeners.get(i);
- if (listener instanceof CarDeviceProvisionedListener) {
- ((CarDeviceProvisionedListener) listener).onUserSetupInProgressChanged();
- }
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedListener.java b/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedListener.java
deleted file mode 100644
index 008632223f3f..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarDeviceProvisionedListener.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 com.android.systemui.car;
-
-import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-
-/**
- * A listener that listens for changes in SUW progress for a user in addition to the
- * functionality defined by {@link DeviceProvisionedListener}.
- */
-public interface CarDeviceProvisionedListener extends DeviceProvisionedListener {
- @Override
- default void onUserSwitched() {
- onUserSetupChanged();
- onUserSetupInProgressChanged();
- }
- /**
- * A callback for when a change occurs in SUW progress for a user.
- */
- default void onUserSetupInProgressChanged() {
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java
deleted file mode 100644
index 5778d660a672..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java
+++ /dev/null
@@ -1,80 +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.systemui.car;
-
-import android.car.Car;
-import android.content.Context;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.systemui.dagger.SysUISingleton;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-/** Provides a common connection to the car service that can be shared. */
-@SysUISingleton
-public class CarServiceProvider {
-
- private final Context mContext;
- private final List<CarServiceOnConnectedListener> mListeners = new ArrayList<>();
- private Car mCar;
-
- @Inject
- public CarServiceProvider(Context context) {
- mContext = context;
- mCar = Car.createCar(mContext, /* handler= */ null, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
- (car, ready) -> {
- mCar = car;
-
- synchronized (mListeners) {
- for (CarServiceOnConnectedListener listener : mListeners) {
- if (ready) {
- listener.onConnected(mCar);
- }
- }
- }
- });
- }
-
- @VisibleForTesting
- public CarServiceProvider(Context context, Car car) {
- mContext = context;
- mCar = car;
- }
-
- /**
- * Let's other components hook into the connection to the car service. If we're already
- * connected to the car service, the callback is immediately triggered.
- */
- public void addListener(CarServiceOnConnectedListener listener) {
- if (mCar.isConnected()) {
- listener.onConnected(mCar);
- }
- mListeners.add(listener);
- }
-
- /**
- * Listener which is triggered when Car Service is connected.
- */
- public interface CarServiceOnConnectedListener {
- /** This will be called when the car service has successfully been connected. */
- void onConnected(Car car);
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/bluetooth/CarBatteryController.java b/packages/CarSystemUI/src/com/android/systemui/car/bluetooth/CarBatteryController.java
deleted file mode 100644
index 9b5e2712a527..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/bluetooth/CarBatteryController.java
+++ /dev/null
@@ -1,292 +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.car.bluetooth;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadsetClient;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothProfile.ServiceListener;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.util.Log;
-
-import com.android.systemui.statusbar.policy.BatteryController;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-/**
- * A {@link BatteryController} that is specific to the Auto use-case. For Auto, the battery icon
- * displays the battery status of a device that is connected via bluetooth and not the system's
- * battery.
- */
-public class CarBatteryController extends BroadcastReceiver implements BatteryController {
- private static final String TAG = "CarBatteryController";
-
- // According to the Bluetooth HFP 1.5 specification, battery levels are indicated by a
- // value from 1-5, where these values represent the following:
- // 0%% - 0, 1-25%% - 1, 26-50%% - 2, 51-75%% - 3, 76-99%% - 4, 100%% - 5
- // As a result, set the level as the average within that range.
- private static final int BATTERY_LEVEL_EMPTY = 0;
- private static final int BATTERY_LEVEL_1 = 12;
- private static final int BATTERY_LEVEL_2 = 28;
- private static final int BATTERY_LEVEL_3 = 63;
- private static final int BATTERY_LEVEL_4 = 87;
- private static final int BATTERY_LEVEL_FULL = 100;
-
- private static final int INVALID_BATTERY_LEVEL = -1;
-
- private final Context mContext;
-
- private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
- private final ArrayList<BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
- private BluetoothHeadsetClient mBluetoothHeadsetClient;
- private final ServiceListener mHfpServiceListener = new ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (profile == BluetoothProfile.HEADSET_CLIENT) {
- mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
- }
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- if (profile == BluetoothProfile.HEADSET_CLIENT) {
- mBluetoothHeadsetClient = null;
- }
- }
- };
- private int mLevel;
- private BatteryViewHandler mBatteryViewHandler;
-
- public CarBatteryController(Context context) {
- mContext = context;
-
- if (mAdapter == null) {
- return;
- }
-
- mAdapter.getProfileProxy(context.getApplicationContext(), mHfpServiceListener,
- BluetoothProfile.HEADSET_CLIENT);
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("CarBatteryController state:");
- pw.print(" mLevel=");
- pw.println(mLevel);
- }
-
- @Override
- public void setPowerSaveMode(boolean powerSave) {
- // No-op. No power save mode for the car.
- }
-
- @Override
- public void addCallback(BatteryController.BatteryStateChangeCallback cb) {
- mChangeCallbacks.add(cb);
-
- // There is no way to know if the phone is plugged in or charging via bluetooth, so pass
- // false for these values.
- cb.onBatteryLevelChanged(mLevel, false /* pluggedIn */, false /* charging */);
- cb.onPowerSaveChanged(false /* isPowerSave */);
- }
-
- @Override
- public void removeCallback(BatteryController.BatteryStateChangeCallback cb) {
- mChangeCallbacks.remove(cb);
- }
-
- /** Sets {@link BatteryViewHandler}. */
- public void addBatteryViewHandler(BatteryViewHandler batteryViewHandler) {
- mBatteryViewHandler = batteryViewHandler;
- }
-
- /** Starts listening for bluetooth broadcast messages. */
- public void startListening() {
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT);
- mContext.registerReceiver(this, filter);
- }
-
- /** Stops listening for bluetooth broadcast messages. */
- public void stopListening() {
- mContext.unregisterReceiver(this);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
-
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "onReceive(). action: " + action);
- }
-
- if (BluetoothHeadsetClient.ACTION_AG_EVENT.equals(action)) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Received ACTION_AG_EVENT");
- }
-
- int batteryLevel = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_BATTERY_LEVEL,
- INVALID_BATTERY_LEVEL);
-
- updateBatteryLevel(batteryLevel);
-
- if (batteryLevel != INVALID_BATTERY_LEVEL && mBatteryViewHandler != null) {
- mBatteryViewHandler.showBatteryView();
- }
- } else if (BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
- int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
-
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
- Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGED event: "
- + oldState + " -> " + newState);
-
- }
- BluetoothDevice device =
- (BluetoothDevice) intent.getExtra(BluetoothDevice.EXTRA_DEVICE);
- updateBatteryIcon(device, newState);
- }
- }
-
- /**
- * Converts the battery level to a percentage that can be displayed on-screen and notifies
- * any {@link BatteryStateChangeCallback}s of this.
- */
- private void updateBatteryLevel(int batteryLevel) {
- if (batteryLevel == INVALID_BATTERY_LEVEL) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Battery level invalid. Ignoring.");
- }
- return;
- }
-
- // The battery level is a value between 0-5. Let the default battery level be 0.
- switch (batteryLevel) {
- case 5:
- mLevel = BATTERY_LEVEL_FULL;
- break;
- case 4:
- mLevel = BATTERY_LEVEL_4;
- break;
- case 3:
- mLevel = BATTERY_LEVEL_3;
- break;
- case 2:
- mLevel = BATTERY_LEVEL_2;
- break;
- case 1:
- mLevel = BATTERY_LEVEL_1;
- break;
- case 0:
- default:
- mLevel = BATTERY_LEVEL_EMPTY;
- }
-
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Battery level: " + batteryLevel + "; setting mLevel as: " + mLevel);
- }
-
- notifyBatteryLevelChanged();
- }
-
- /**
- * Updates the display of the battery icon depending on the given connection state from the
- * given {@link BluetoothDevice}.
- */
- private void updateBatteryIcon(BluetoothDevice device, int newState) {
- if (newState == BluetoothProfile.STATE_CONNECTED) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Device connected");
- }
-
- if (mBatteryViewHandler != null) {
- mBatteryViewHandler.showBatteryView();
- }
-
- if (mBluetoothHeadsetClient == null || device == null) {
- return;
- }
-
- // Check if battery information is available and immediately update.
- Bundle featuresBundle = mBluetoothHeadsetClient.getCurrentAgEvents(device);
- if (featuresBundle == null) {
- return;
- }
-
- int batteryLevel = featuresBundle.getInt(BluetoothHeadsetClient.EXTRA_BATTERY_LEVEL,
- INVALID_BATTERY_LEVEL);
- updateBatteryLevel(batteryLevel);
- } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Device disconnected");
- }
-
- if (mBatteryViewHandler != null) {
- mBatteryViewHandler.hideBatteryView();
- }
- }
- }
-
- @Override
- public void dispatchDemoCommand(String command, Bundle args) {
- // TODO: Car demo mode.
- }
-
- @Override
- public boolean isPluggedIn() {
- return true;
- }
-
- @Override
- public boolean isPowerSave() {
- // Power save is not valid for the car, so always return false.
- return false;
- }
-
- @Override
- public boolean isAodPowerSave() {
- return false;
- }
-
- private void notifyBatteryLevelChanged() {
- for (int i = 0, size = mChangeCallbacks.size(); i < size; i++) {
- mChangeCallbacks.get(i)
- .onBatteryLevelChanged(mLevel, false /* pluggedIn */, false /* charging */);
- }
- }
-
- /**
- * An interface indicating the container of a View that will display what the information
- * in the {@link CarBatteryController}.
- */
- public interface BatteryViewHandler {
- /** Hides the battery view. */
- void hideBatteryView();
-
- /** Shows the battery view. */
- void showBatteryView();
- }
-
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/bluetooth/ConnectedDeviceSignalController.java b/packages/CarSystemUI/src/com/android/systemui/car/bluetooth/ConnectedDeviceSignalController.java
deleted file mode 100644
index 4642868a225e..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/bluetooth/ConnectedDeviceSignalController.java
+++ /dev/null
@@ -1,272 +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.car.bluetooth;
-
-import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadsetClient;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothProfile.ServiceListener;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.telephony.SignalStrength;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.View;
-import android.widget.ImageView;
-
-import com.android.settingslib.graph.SignalDrawable;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.ScalingDrawableWrapper;
-import com.android.systemui.statusbar.policy.BluetoothController;
-
-/**
- * Controller that monitors signal strength for a device that is connected via bluetooth.
- */
-public class ConnectedDeviceSignalController extends BroadcastReceiver implements
- BluetoothController.Callback {
- private static final String TAG = "DeviceSignalCtlr";
-
- /**
- * The value that indicates if a network is unavailable. This value is according ot the
- * Bluetooth HFP 1.5 spec, which indicates this value is one of two: 0 or 1. These stand
- * for network unavailable and available respectively.
- */
- private static final int NETWORK_UNAVAILABLE = 0;
- private static final int NETWORK_UNAVAILABLE_ICON_ID = R.drawable.stat_sys_signal_null;
-
- /**
- * All possible signal strength icons. According to the Bluetooth HFP 1.5 specification,
- * signal strength is indicated by a value from 1-5, where these values represent the following:
- *
- * <p>0%% - 0, 1-25%% - 1, 26-50%% - 2, 51-75%% - 3, 76-99%% - 4, 100%% - 5
- *
- * <p>As a result, these are treated as an index into this array for the corresponding icon.
- * Note that the icon is the same for 0 and 1.
- */
- private static final int[] SIGNAL_STRENGTH_ICONS = {
- 0,
- 0,
- 1,
- 2,
- 3,
- 4,
- };
-
- private static final int INVALID_SIGNAL = -1;
-
- private final BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
- private final Context mContext;
- private final BluetoothController mController;
-
- private final View mSignalsView;
- private final ImageView mNetworkSignalView;
-
- private final float mIconScaleFactor;
- private final SignalDrawable mSignalDrawable;
-
- private BluetoothHeadsetClient mBluetoothHeadsetClient;
- private final ServiceListener mHfpServiceListener = new ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (profile == BluetoothProfile.HEADSET_CLIENT) {
- mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
- }
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- if (profile == BluetoothProfile.HEADSET_CLIENT) {
- mBluetoothHeadsetClient = null;
- }
- }
- };
-
- public ConnectedDeviceSignalController(Context context, View signalsView) {
- mContext = context;
- mController = Dependency.get(BluetoothController.class);
-
- mSignalsView = signalsView;
- mNetworkSignalView = (ImageView)
- mSignalsView.findViewById(R.id.connected_device_network_signal);
-
- TypedValue typedValue = new TypedValue();
- context.getResources().getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
- mIconScaleFactor = typedValue.getFloat();
- mSignalDrawable = new SignalDrawable(mNetworkSignalView.getContext());
- mNetworkSignalView.setImageDrawable(
- new ScalingDrawableWrapper(mSignalDrawable, mIconScaleFactor));
-
- if (mAdapter == null) {
- return;
- }
-
- mAdapter.getProfileProxy(context.getApplicationContext(), mHfpServiceListener,
- BluetoothProfile.HEADSET_CLIENT);
- }
-
- /** Starts listening for bluetooth broadcast messages. */
- public void startListening() {
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT);
- mContext.registerReceiver(this, filter);
-
- mController.addCallback(this);
- }
-
- /** Stops listening for bluetooth broadcast messages. */
- public void stopListening() {
- mContext.unregisterReceiver(this);
- mController.removeCallback(this);
- }
-
- @Override
- public void onBluetoothDevicesChanged() {
- // Nothing to do here because this Controller is not displaying a list of possible
- // bluetooth devices.
- }
-
- @Override
- public void onBluetoothStateChange(boolean enabled) {
- if (DEBUG) {
- Log.d(TAG, "onBluetoothStateChange(). enabled: " + enabled);
- }
-
- // Only need to handle the case if bluetooth has been disabled, in which case the
- // signal indicators are hidden. If bluetooth has been enabled, then this class should
- // receive updates to the connection state via onReceive().
- if (!enabled) {
- mNetworkSignalView.setVisibility(View.GONE);
- mSignalsView.setVisibility(View.GONE);
- }
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
-
- if (DEBUG) {
- Log.d(TAG, "onReceive(). action: " + action);
- }
-
- if (BluetoothHeadsetClient.ACTION_AG_EVENT.equals(action)) {
- if (DEBUG) {
- Log.d(TAG, "Received ACTION_AG_EVENT");
- }
-
- processActionAgEvent(intent);
- } else if (BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
- int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
-
- if (DEBUG) {
- int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1);
- Log.d(TAG, "ACTION_CONNECTION_STATE_CHANGED event: "
- + oldState + " -> " + newState);
- }
- BluetoothDevice device =
- (BluetoothDevice) intent.getExtra(BluetoothDevice.EXTRA_DEVICE);
- updateViewVisibility(device, newState);
- }
- }
-
- /**
- * Processes an {@link Intent} that had an action of
- * {@link BluetoothHeadsetClient#ACTION_AG_EVENT}.
- */
- private void processActionAgEvent(Intent intent) {
- int networkStatus = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_NETWORK_STATUS,
- INVALID_SIGNAL);
- if (networkStatus != INVALID_SIGNAL) {
- if (DEBUG) {
- Log.d(TAG, "EXTRA_NETWORK_STATUS: " + " " + networkStatus);
- }
-
- if (networkStatus == NETWORK_UNAVAILABLE) {
- setNetworkSignalIcon(NETWORK_UNAVAILABLE_ICON_ID);
- }
- }
-
- int signalStrength = intent.getIntExtra(
- BluetoothHeadsetClient.EXTRA_NETWORK_SIGNAL_STRENGTH, INVALID_SIGNAL);
- if (signalStrength != INVALID_SIGNAL) {
- if (DEBUG) {
- Log.d(TAG, "EXTRA_NETWORK_SIGNAL_STRENGTH: " + signalStrength);
- }
-
- setNetworkSignalIcon(SIGNAL_STRENGTH_ICONS[signalStrength]);
- }
-
- int roamingStatus = intent.getIntExtra(BluetoothHeadsetClient.EXTRA_NETWORK_ROAMING,
- INVALID_SIGNAL);
- if (roamingStatus != INVALID_SIGNAL) {
- if (DEBUG) {
- Log.d(TAG, "EXTRA_NETWORK_ROAMING: " + roamingStatus);
- }
- }
- }
-
- private void setNetworkSignalIcon(int level) {
- // Setting the icon on a child view of mSignalView, so toggle this container visible.
- mSignalsView.setVisibility(View.VISIBLE);
-
- mSignalDrawable.setLevel(SignalDrawable.getState(level,
- SignalStrength.NUM_SIGNAL_STRENGTH_BINS, false));
- mNetworkSignalView.setVisibility(View.VISIBLE);
- }
-
- private void updateViewVisibility(BluetoothDevice device, int newState) {
- if (newState == BluetoothProfile.STATE_CONNECTED) {
- if (DEBUG) {
- Log.d(TAG, "Device connected");
- }
-
- if (mBluetoothHeadsetClient == null || device == null) {
- return;
- }
-
- // Check if battery information is available and immediately update.
- Bundle featuresBundle = mBluetoothHeadsetClient.getCurrentAgEvents(device);
- if (featuresBundle == null) {
- return;
- }
-
- int signalStrength = featuresBundle.getInt(
- BluetoothHeadsetClient.EXTRA_NETWORK_SIGNAL_STRENGTH, INVALID_SIGNAL);
- if (signalStrength != INVALID_SIGNAL) {
- if (DEBUG) {
- Log.d(TAG, "EXTRA_NETWORK_SIGNAL_STRENGTH: " + signalStrength);
- }
-
- setNetworkSignalIcon(SIGNAL_STRENGTH_ICONS[signalStrength]);
- }
- } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
- if (DEBUG) {
- Log.d(TAG, "Device disconnected");
- }
-
- mNetworkSignalView.setVisibility(View.GONE);
- mSignalsView.setVisibility(View.GONE);
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java
deleted file mode 100644
index af2a1d36bbd7..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java
+++ /dev/null
@@ -1,130 +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.car.hvac;
-
-import static com.android.systemui.car.hvac.HvacController.convertToCelsius;
-import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-
-/**
- * Displays temperature with a button to decrease and a button to increase on either side.
- * Properties configured in the XML:
- * hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
- */
-public class AdjustableTemperatureView extends LinearLayout implements TemperatureView {
-
- private final int mAreaId;
- private TextView mTempTextView;
- private float mMinTempC;
- private float mMaxTempC;
- private String mTempFormat;
- private String mNullTempText;
- private String mMinTempText;
- private String mMaxTempText;
- private boolean mDisplayInFahrenheit = false;
-
- private HvacController mHvacController;
- private float mCurrentTempC;
-
- public AdjustableTemperatureView(Context context, AttributeSet attrs) {
- super(context, attrs);
- TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView);
- mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId, -1);
- }
-
- @Override
- public void onFinishInflate() {
- super.onFinishInflate();
- LayoutInflater.from(getContext()).inflate(R.layout.adjustable_temperature_view,
- /* root= */ this);
- mTempFormat = getResources().getString(R.string.hvac_temperature_format);
- mMinTempC = getResources().getFloat(R.dimen.hvac_min_value_celsius);
- mMaxTempC = getResources().getFloat(R.dimen.hvac_max_value_celsius);
- mNullTempText = getResources().getString(R.string.hvac_null_temp_text);
- mMinTempText = getResources().getString(R.string.hvac_min_text);
- mMaxTempText = getResources().getString(R.string.hvac_max_text);
- initializeButtons();
- }
-
- @Override
- public void setHvacController(HvacController controller) {
- mHvacController = controller;
- }
-
- @Override
- public void setTemp(float tempC) {
- if (mTempTextView == null) {
- mTempTextView = findViewById(R.id.hvac_temperature_text);
- }
- if (Float.isNaN(tempC)) {
- mTempTextView.setText(mNullTempText);
- return;
- }
- if (tempC <= mMinTempC) {
- mTempTextView.setText(mMinTempText);
- mCurrentTempC = mMinTempC;
- return;
- }
- if (tempC >= mMaxTempC) {
- mTempTextView.setText(mMaxTempText);
- mCurrentTempC = mMaxTempC;
- return;
- }
- mTempTextView.setText(String.format(mTempFormat,
- mDisplayInFahrenheit ? convertToFahrenheit(tempC) : tempC));
- mCurrentTempC = tempC;
- }
-
- @Override
- public void setDisplayInFahrenheit(boolean displayFahrenheit) {
- mDisplayInFahrenheit = displayFahrenheit;
- setTemp(mCurrentTempC);
- }
-
- @Override
- public int getAreaId() {
- return mAreaId;
- }
-
- private void initializeButtons() {
- findViewById(R.id.hvac_decrease_button).setOnClickListener(v -> {
- float newTemp = mDisplayInFahrenheit ? convertToCelsius(
- convertToFahrenheit(mCurrentTempC) - 1) : (mCurrentTempC - 1);
- setTemperature(newTemp, mAreaId);
- });
-
- findViewById(R.id.hvac_increase_button).setOnClickListener(v -> {
- float newTemp = mDisplayInFahrenheit ? convertToCelsius(
- convertToFahrenheit(mCurrentTempC) + 1) : (mCurrentTempC + 1);
- setTemperature(newTemp, mAreaId);
- });
- }
-
- private void setTemperature(float tempC, int zone) {
- if (tempC < mMaxTempC && tempC > mMinTempC && mHvacController != null) {
- mHvacController.setTemperature(tempC, zone);
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java
deleted file mode 100644
index b98b68038e6f..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java
+++ /dev/null
@@ -1,265 +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.car.hvac;
-
-import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
-
-import android.animation.ObjectAnimator;
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.util.AttributeSet;
-import android.util.Property;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextSwitcher;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-
-/**
- * Simple text display of HVAC properties, It is designed to show mTemperature and is configured in
- * the XML.
- * XML properties:
- * hvacAreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
- * hvacOrientaion = Example: left
- */
-public class AnimatedTemperatureView extends FrameLayout implements TemperatureView {
-
- private static final float TEMPERATURE_EQUIVALENT_DELTA = .01f;
- private static final Property<ColorDrawable, Integer> COLOR_PROPERTY =
- new Property<ColorDrawable, Integer>(Integer.class, "color") {
-
- @Override
- public Integer get(ColorDrawable object) {
- return object.getColor();
- }
-
- @Override
- public void set(ColorDrawable object, Integer value) {
- object.setColor(value);
- }
- };
-
- static boolean isHorizontal(int gravity) {
- return Gravity.isHorizontal(gravity)
- && (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.CENTER_HORIZONTAL;
- }
-
- @SuppressLint("RtlHardcoded")
- static boolean isLeft(int gravity, int layoutDirection) {
- return Gravity
- .getAbsoluteGravity(gravity & Gravity.HORIZONTAL_GRAVITY_MASK, layoutDirection)
- == Gravity.LEFT;
- }
-
- static boolean isVertical(int gravity) {
- return Gravity.isVertical(gravity)
- && (gravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.CENTER_VERTICAL;
- }
-
- static boolean isTop(int gravity) {
- return (gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.TOP;
- }
-
- private final int mAreaId;
- private final int mPivotOffset;
- private final int mGravity;
- private final int mTextAppearanceRes;
- private final int mMinEms;
- private final Rect mPaddingRect;
- private final float mMinValue;
- private final float mMaxValue;
-
- private final ColorDrawable mBackgroundColor;
-
- private final TemperatureColorStore mColorStore = new TemperatureColorStore();
- private final TemperatureBackgroundAnimator mBackgroundAnimator;
- private final TemperatureTextAnimator mTextAnimator;
- boolean mDisplayInFahrenheit = false;
-
- private HvacController mHvacController;
-
- public AnimatedTemperatureView(Context context, AttributeSet attrs) {
- super(context, attrs);
- TypedArray typedArray = context.obtainStyledAttributes(attrs,
- R.styleable.AnimatedTemperatureView);
- mAreaId = typedArray.getInt(R.styleable.AnimatedTemperatureView_hvacAreaId, -1);
- mPivotOffset =
- typedArray.getDimensionPixelOffset(
- R.styleable.AnimatedTemperatureView_hvacPivotOffset, 0);
- mGravity = typedArray.getInt(R.styleable.AnimatedTemperatureView_android_gravity,
- Gravity.START);
- mTextAppearanceRes =
- typedArray.getResourceId(R.styleable.AnimatedTemperatureView_android_textAppearance,
- 0);
- mMinEms = typedArray.getInteger(R.styleable.AnimatedTemperatureView_android_minEms, 0);
- mMinValue = getResources().getFloat(R.dimen.hvac_min_value_celsius);
- mMaxValue = getResources().getFloat(R.dimen.hvac_max_value_celsius);
-
- mPaddingRect =
- new Rect(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
- setPadding(0, 0, 0, 0);
-
- setClipChildren(false);
- setClipToPadding(false);
-
- // init Views
- TextSwitcher textSwitcher = new TextSwitcher(context);
- textSwitcher.setFactory(this::generateTextView);
- ImageView background = new ImageView(context);
- mBackgroundColor = new ColorDrawable(Color.TRANSPARENT);
- background.setImageDrawable(mBackgroundColor);
- background.setVisibility(View.GONE);
-
- mBackgroundAnimator = new TemperatureBackgroundAnimator(this, background);
-
- mTextAnimator = new TemperatureTextAnimator(this, textSwitcher,
- getResources().getString(R.string.hvac_temperature_format), mPivotOffset,
- getResources().getString(R.string.hvac_min_text),
- getResources().getString(R.string.hvac_max_text));
-
- addView(background, ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT);
- addView(textSwitcher, ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT);
-
- typedArray.recycle();
- }
-
-
- private TextView generateTextView() {
- TextView textView = new TextView(getContext());
- textView.setTextAppearance(mTextAppearanceRes);
- textView.setAllCaps(true);
- textView.setMinEms(mMinEms);
- textView.setGravity(mGravity);
- textView.setPadding(mPaddingRect.left, mPaddingRect.top, mPaddingRect.right,
- mPaddingRect.bottom);
- textView.getViewTreeObserver()
- .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- if (isHorizontal(mGravity)) {
- if (isLeft(mGravity, getLayoutDirection())) {
- textView.setPivotX(-mPivotOffset);
- } else {
- textView.setPivotX(textView.getWidth() + mPivotOffset);
- }
- }
- textView.getViewTreeObserver().removeOnPreDrawListener(this);
- return true;
- }
- });
- textView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- return textView;
- }
-
- @Override
- public void setHvacController(HvacController controller) {
- mHvacController = controller;
- }
-
- /**
- * Formats the float for display
- *
- * @param temp - The current temp or NaN
- */
- @Override
- public void setTemp(float temp) {
- if (mDisplayInFahrenheit) {
- temp = convertToFahrenheit(temp);
- }
- mTextAnimator.setTemp(temp);
- if (Float.isNaN(temp)) {
- mBackgroundAnimator.hideCircle();
- return;
- }
- int color;
- if (isMinValue(temp)) {
- color = mColorStore.getMinColor();
- } else if (isMaxValue(temp)) {
- color = mColorStore.getMaxColor();
- } else {
- color = mColorStore.getColorForTemperature(temp);
- }
- if (mBackgroundAnimator.isOpen()) {
- ObjectAnimator colorAnimator =
- ObjectAnimator.ofInt(mBackgroundColor, COLOR_PROPERTY, color);
- colorAnimator.setEvaluator((fraction, startValue, endValue) -> mColorStore
- .lerpColor(fraction, (int) startValue, (int) endValue));
- colorAnimator.start();
- } else {
- mBackgroundColor.setColor(color);
- }
-
- mBackgroundAnimator.animateOpen();
- }
-
- @Override
- public void setDisplayInFahrenheit(boolean displayInFahrenheit) {
- mDisplayInFahrenheit = displayInFahrenheit;
- }
-
- boolean isMinValue(float temp) {
- return !Float.isNaN(mMinValue) && isApproxEqual(temp, mMinValue);
- }
-
- boolean isMaxValue(float temp) {
- return !Float.isNaN(mMaxValue) && isApproxEqual(temp, mMaxValue);
- }
-
- private boolean isApproxEqual(float left, float right) {
- return Math.abs(left - right) <= TEMPERATURE_EQUIVALENT_DELTA;
- }
-
- int getGravity() {
- return mGravity;
- }
-
- int getPivotOffset() {
- return mPivotOffset;
- }
-
- Rect getPaddingRect() {
- return mPaddingRect;
- }
-
- /**
- * @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
- */
- @Override
- public int getAreaId() {
- return mAreaId;
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mBackgroundAnimator.stopAnimations();
- }
-}
-
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java
deleted file mode 100644
index 10a361c3084e..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java
+++ /dev/null
@@ -1,245 +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.car.hvac;
-
-import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
-import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
-import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
-
-import android.car.Car;
-import android.car.VehicleUnit;
-import android.car.hardware.CarPropertyValue;
-import android.car.hardware.property.CarPropertyManager;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.UiBackground;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-
-/**
- * Manages the connection to the Car service and delegates value changes to the registered
- * {@link TemperatureView}s
- */
-@SysUISingleton
-public class HvacController {
- public static final String TAG = "HvacController";
- private static final boolean DEBUG = true;
-
- private final Executor mBackgroundExecutor;
- private final CarServiceProvider mCarServiceProvider;
- private final Set<TemperatureView> mRegisteredViews = new HashSet<>();
-
- private CarPropertyManager mCarPropertyManager;
- private HashMap<Integer, List<TemperatureView>> mTempComponents = new HashMap<>();
-
- private final CarPropertyManager.CarPropertyEventCallback mHvacTemperatureSetCallback =
- new CarPropertyManager.CarPropertyEventCallback() {
- @Override
- public void onChangeEvent(CarPropertyValue value) {
- try {
- int areaId = value.getAreaId();
- List<TemperatureView> temperatureViews = mTempComponents.get(areaId);
- if (temperatureViews != null && !temperatureViews.isEmpty()) {
- float newTemp = (float) value.getValue();
- if (DEBUG) {
- Log.d(TAG, "onChangeEvent: " + areaId + ":" + value);
- }
- for (TemperatureView view : temperatureViews) {
- view.setTemp(newTemp);
- }
- }
- } catch (Exception e) {
- Log.e(TAG, "Failed handling hvac change event", e);
- }
- }
-
- @Override
- public void onErrorEvent(int propId, int zone) {
- Log.d(TAG, "HVAC error event, propertyId: " + propId + " zone: " + zone);
- }
- };
-
- private final CarPropertyManager.CarPropertyEventCallback mTemperatureUnitChangeCallback =
- new CarPropertyManager.CarPropertyEventCallback() {
- @Override
- public void onChangeEvent(CarPropertyValue value) {
- if (!mRegisteredViews.isEmpty()) {
- for (TemperatureView view : mRegisteredViews) {
- view.setDisplayInFahrenheit(
- value.getValue().equals(VehicleUnit.FAHRENHEIT));
- }
- }
- }
-
- @Override
- public void onErrorEvent(int propId, int zone) {
- Log.d(TAG, "HVAC error event, propertyId: " + propId + " zone: " + zone);
- }
- };
-
- private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener =
- car -> {
- try {
- mCarPropertyManager = (CarPropertyManager) car.getCarManager(
- Car.PROPERTY_SERVICE);
- mCarPropertyManager.registerCallback(mHvacTemperatureSetCallback,
- HVAC_TEMPERATURE_SET, CarPropertyManager.SENSOR_RATE_ONCHANGE);
- mCarPropertyManager.registerCallback(mTemperatureUnitChangeCallback,
- HVAC_TEMPERATURE_DISPLAY_UNITS,
- CarPropertyManager.SENSOR_RATE_ONCHANGE);
- initComponents();
- } catch (Exception e) {
- Log.e(TAG, "Failed to correctly connect to HVAC", e);
- }
- };
-
- @Inject
- public HvacController(CarServiceProvider carServiceProvider,
- @UiBackground Executor backgroundExecutor) {
- mCarServiceProvider = carServiceProvider;
- mBackgroundExecutor = backgroundExecutor;
- }
-
- /**
- * Create connection to the Car service.
- */
- public void connectToCarService() {
- mCarServiceProvider.addListener(mCarServiceLifecycleListener);
- }
-
- /**
- * Add component to list and initialize it if the connection is up.
- */
- private void addHvacTextView(TemperatureView temperatureView) {
- if (mRegisteredViews.contains(temperatureView)) {
- return;
- }
-
- int areaId = temperatureView.getAreaId();
- if (!mTempComponents.containsKey(areaId)) {
- mTempComponents.put(areaId, new ArrayList<>());
- }
- mTempComponents.get(areaId).add(temperatureView);
- initComponent(temperatureView);
-
- mRegisteredViews.add(temperatureView);
- }
-
- private void initComponents() {
- for (Map.Entry<Integer, List<TemperatureView>> next : mTempComponents.entrySet()) {
- List<TemperatureView> temperatureViews = next.getValue();
- for (TemperatureView view : temperatureViews) {
- initComponent(view);
- }
- }
- }
-
- private void initComponent(TemperatureView view) {
- int zone = view.getAreaId();
- if (DEBUG) {
- Log.d(TAG, "initComponent: " + zone);
- }
-
- try {
- if (mCarPropertyManager != null && mCarPropertyManager.isPropertyAvailable(
- HVAC_TEMPERATURE_DISPLAY_UNITS, VEHICLE_AREA_TYPE_GLOBAL)) {
- if (mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL) == VehicleUnit.FAHRENHEIT) {
- view.setDisplayInFahrenheit(true);
- }
- }
- if (mCarPropertyManager == null || !mCarPropertyManager.isPropertyAvailable(
- HVAC_TEMPERATURE_SET, zone)) {
- view.setTemp(Float.NaN);
- return;
- }
- view.setTemp(
- mCarPropertyManager.getFloatProperty(HVAC_TEMPERATURE_SET, zone));
- view.setHvacController(this);
- } catch (Exception e) {
- view.setTemp(Float.NaN);
- Log.e(TAG, "Failed to get value from hvac service", e);
- }
- }
-
- /**
- * Removes all registered components. This is useful if you need to rebuild the UI since
- * components self register.
- */
- public void removeAllComponents() {
- mTempComponents.clear();
- mRegisteredViews.clear();
- }
-
- /**
- * Iterate through a view, looking for {@link TemperatureView} instances and add them to the
- * controller if found.
- */
- public void addTemperatureViewToController(View v) {
- if (v instanceof TemperatureView) {
- addHvacTextView((TemperatureView) v);
- } else if (v instanceof ViewGroup) {
- ViewGroup viewGroup = (ViewGroup) v;
- for (int i = 0; i < viewGroup.getChildCount(); i++) {
- addTemperatureViewToController(viewGroup.getChildAt(i));
- }
- }
- }
-
- /**
- * Set the temperature in Celsius of the specified zone
- */
- public void setTemperature(float tempC, int zone) {
- if (mCarPropertyManager != null) {
- // Internally, all temperatures are represented in floating point Celsius
- mBackgroundExecutor.execute(
- () -> mCarPropertyManager.setFloatProperty(HVAC_TEMPERATURE_SET, zone, tempC));
- }
- }
-
- /**
- * Convert the given temperature in Celsius into Fahrenheit
- *
- * @param tempC - The temperature in Celsius
- * @return Temperature in Fahrenheit.
- */
- public static float convertToFahrenheit(float tempC) {
- return (tempC * 9f / 5f) + 32;
- }
-
- /**
- * Convert the given temperature in Fahrenheit to Celsius
- *
- * @param tempF - The temperature in Fahrenheit.
- * @return Temperature in Celsius.
- */
- public static float convertToCelsius(float tempF) {
- return (tempF - 32) * 5f / 9f;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureBackgroundAnimator.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureBackgroundAnimator.java
deleted file mode 100644
index a4c45730a9c2..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureBackgroundAnimator.java
+++ /dev/null
@@ -1,340 +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.car.hvac;
-
-import static com.android.systemui.car.hvac.AnimatedTemperatureView.isHorizontal;
-import static com.android.systemui.car.hvac.AnimatedTemperatureView.isLeft;
-import static com.android.systemui.car.hvac.AnimatedTemperatureView.isTop;
-import static com.android.systemui.car.hvac.AnimatedTemperatureView.isVertical;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.annotation.IntDef;
-import android.graphics.Rect;
-import android.view.View;
-import android.view.ViewAnimationUtils;
-import android.view.animation.AnticipateInterpolator;
-import android.widget.ImageView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Controls circular reveal animation of temperature background
- */
-class TemperatureBackgroundAnimator {
-
- private static final AnticipateInterpolator ANTICIPATE_INTERPOLATOR =
- new AnticipateInterpolator();
- private static final float MAX_OPACITY = .6f;
-
- private final View mAnimatedView;
-
- private int mPivotX;
- private int mPivotY;
- private int mGoneRadius;
- private int mOvershootRadius;
- private int mRestingRadius;
- private int mBumpRadius;
-
- @CircleState
- private int mCircleState;
-
- private Animator mCircularReveal;
- private boolean mAnimationsReady;
-
- @IntDef({CircleState.GONE, CircleState.ENTERING, CircleState.OVERSHOT, CircleState.RESTING,
- CircleState.RESTED, CircleState.BUMPING, CircleState.BUMPED, CircleState.EXITING})
- private @interface CircleState {
- int GONE = 0;
- int ENTERING = 1;
- int OVERSHOT = 2;
- int RESTING = 3;
- int RESTED = 4;
- int BUMPING = 5;
- int BUMPED = 6;
- int EXITING = 7;
- }
-
- TemperatureBackgroundAnimator(
- AnimatedTemperatureView parent,
- ImageView animatedView) {
- mAnimatedView = animatedView;
- mAnimatedView.setAlpha(0);
-
- parent.addOnLayoutChangeListener(
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
- setupAnimations(parent.getGravity(), parent.getPivotOffset(),
- parent.getPaddingRect(), parent.getWidth(), parent.getHeight()));
- }
-
- private void setupAnimations(int gravity, int pivotOffset, Rect paddingRect,
- int width, int height) {
- int padding;
- if (isHorizontal(gravity)) {
- mGoneRadius = pivotOffset;
- if (isLeft(gravity, mAnimatedView.getLayoutDirection())) {
- mPivotX = -pivotOffset;
- padding = paddingRect.right;
- } else {
- mPivotX = width + pivotOffset;
- padding = paddingRect.left;
- }
- mPivotY = height / 2;
- mOvershootRadius = pivotOffset + width;
- } else if (isVertical(gravity)) {
- mGoneRadius = pivotOffset;
- if (isTop(gravity)) {
- mPivotY = -pivotOffset;
- padding = paddingRect.bottom;
- } else {
- mPivotY = height + pivotOffset;
- padding = paddingRect.top;
- }
- mPivotX = width / 2;
- mOvershootRadius = pivotOffset + height;
- } else {
- mPivotX = width / 2;
- mPivotY = height / 2;
- mGoneRadius = 0;
- if (width > height) {
- mOvershootRadius = height;
- padding = Math.max(paddingRect.top, paddingRect.bottom);
- } else {
- mOvershootRadius = width;
- padding = Math.max(paddingRect.left, paddingRect.right);
- }
- }
- mRestingRadius = mOvershootRadius - padding;
- mBumpRadius = mOvershootRadius - padding / 3;
- mAnimationsReady = true;
- }
-
- boolean isOpen() {
- return mCircleState != CircleState.GONE;
- }
-
- void animateOpen() {
- if (!mAnimationsReady
- || !mAnimatedView.isAttachedToWindow()
- || mCircleState == CircleState.ENTERING) {
- return;
- }
-
- AnimatorSet set = new AnimatorSet();
- List<Animator> animators = new ArrayList<>();
- switch (mCircleState) {
- case CircleState.ENTERING:
- throw new AssertionError("Should not be able to reach this statement");
- case CircleState.GONE: {
- Animator startCircle = createEnterAnimator();
- markState(startCircle, CircleState.ENTERING);
- animators.add(startCircle);
- Animator holdOvershoot = ViewAnimationUtils
- .createCircularReveal(mAnimatedView, mPivotX, mPivotY, mOvershootRadius,
- mOvershootRadius);
- holdOvershoot.setDuration(50);
- markState(holdOvershoot, CircleState.OVERSHOT);
- animators.add(holdOvershoot);
- Animator rest = ViewAnimationUtils
- .createCircularReveal(mAnimatedView, mPivotX, mPivotY, mOvershootRadius,
- mRestingRadius);
- markState(rest, CircleState.RESTING);
- animators.add(rest);
- Animator holdRest = ViewAnimationUtils
- .createCircularReveal(mAnimatedView, mPivotX, mPivotY, mRestingRadius,
- mRestingRadius);
- markState(holdRest, CircleState.RESTED);
- holdRest.setDuration(1000);
- animators.add(holdRest);
- Animator exit = createExitAnimator(mRestingRadius);
- markState(exit, CircleState.EXITING);
- animators.add(exit);
- }
- break;
- case CircleState.RESTED:
- case CircleState.RESTING:
- case CircleState.EXITING:
- case CircleState.OVERSHOT:
- int startRadius =
- mCircleState == CircleState.OVERSHOT ? mOvershootRadius : mRestingRadius;
- Animator bump = ViewAnimationUtils
- .createCircularReveal(mAnimatedView, mPivotX, mPivotY, startRadius,
- mBumpRadius);
- bump.setDuration(50);
- markState(bump, CircleState.BUMPING);
- animators.add(bump);
- // fallthrough intentional
- case CircleState.BUMPED:
- case CircleState.BUMPING:
- Animator holdBump = ViewAnimationUtils
- .createCircularReveal(mAnimatedView, mPivotX, mPivotY, mBumpRadius,
- mBumpRadius);
- holdBump.setDuration(100);
- markState(holdBump, CircleState.BUMPED);
- animators.add(holdBump);
- Animator rest = ViewAnimationUtils
- .createCircularReveal(mAnimatedView, mPivotX, mPivotY, mBumpRadius,
- mRestingRadius);
- markState(rest, CircleState.RESTING);
- animators.add(rest);
- Animator holdRest = ViewAnimationUtils
- .createCircularReveal(mAnimatedView, mPivotX, mPivotY, mRestingRadius,
- mRestingRadius);
- holdRest.setDuration(1000);
- markState(holdRest, CircleState.RESTED);
- animators.add(holdRest);
- Animator exit = createExitAnimator(mRestingRadius);
- markState(exit, CircleState.EXITING);
- animators.add(exit);
- break;
- }
- set.playSequentially(animators);
- set.addListener(new AnimatorListenerAdapter() {
- private boolean mCanceled = false;
-
- @Override
- public void onAnimationStart(Animator animation) {
- if (mCircularReveal != null) {
- mCircularReveal.cancel();
- }
- mCircularReveal = animation;
- mAnimatedView.setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCanceled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mCanceled) {
- return;
- }
- mCircularReveal = null;
- mCircleState = CircleState.GONE;
- mAnimatedView.setVisibility(View.GONE);
- }
- });
-
- set.start();
- }
-
- private Animator createEnterAnimator() {
- AnimatorSet animatorSet = new AnimatorSet();
- Animator circularReveal = ViewAnimationUtils
- .createCircularReveal(mAnimatedView, mPivotX, mPivotY, mGoneRadius,
- mOvershootRadius);
- Animator fade = ObjectAnimator.ofFloat(mAnimatedView, View.ALPHA, MAX_OPACITY);
- animatorSet.playTogether(circularReveal, fade);
- return animatorSet;
- }
-
- private Animator createExitAnimator(int startRadius) {
- AnimatorSet animatorSet = new AnimatorSet();
- Animator circularHide = ViewAnimationUtils
- .createCircularReveal(mAnimatedView, mPivotX, mPivotY, startRadius,
- (mGoneRadius + startRadius) / 2);
- circularHide.setInterpolator(ANTICIPATE_INTERPOLATOR);
- Animator fade = ObjectAnimator.ofFloat(mAnimatedView, View.ALPHA, 0);
- fade.setStartDelay(50);
- animatorSet.playTogether(circularHide, fade);
- return animatorSet;
- }
-
- void hideCircle() {
- if (!mAnimationsReady || mCircleState == CircleState.GONE
- || mCircleState == CircleState.EXITING) {
- return;
- }
-
- int startRadius;
- switch (mCircleState) {
- // Unreachable, but here to exhaust switch cases
- //noinspection ConstantConditions
- case CircleState.EXITING:
- //noinspection ConstantConditions
- case CircleState.GONE:
- throw new AssertionError("Should not be able to reach this statement");
- case CircleState.BUMPED:
- case CircleState.BUMPING:
- startRadius = mBumpRadius;
- break;
- case CircleState.OVERSHOT:
- startRadius = mOvershootRadius;
- break;
- case CircleState.ENTERING:
- case CircleState.RESTED:
- case CircleState.RESTING:
- startRadius = mRestingRadius;
- break;
- default:
- throw new IllegalStateException("Unknown CircleState: " + mCircleState);
- }
-
- Animator hideAnimation = createExitAnimator(startRadius);
- if (startRadius == mRestingRadius) {
- hideAnimation.setInterpolator(ANTICIPATE_INTERPOLATOR);
- }
- hideAnimation.addListener(new AnimatorListenerAdapter() {
- private boolean mCanceled = false;
-
- @Override
- public void onAnimationStart(Animator animation) {
- mCircleState = CircleState.EXITING;
- if (mCircularReveal != null) {
- mCircularReveal.cancel();
- }
- mCircularReveal = animation;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCanceled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mCanceled) {
- return;
- }
- mCircularReveal = null;
- mCircleState = CircleState.GONE;
- mAnimatedView.setVisibility(View.GONE);
- }
- });
- hideAnimation.start();
- }
-
- void stopAnimations() {
- if (mCircularReveal != null) {
- mCircularReveal.end();
- }
- }
-
- private void markState(Animator animator, @CircleState int startState) {
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mCircleState = startState;
- }
- });
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureColorStore.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureColorStore.java
deleted file mode 100644
index 9a7b0b9819c5..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureColorStore.java
+++ /dev/null
@@ -1,202 +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.car.hvac;
-
-import android.graphics.Color;
-
-/**
- * Contains the logic for mapping colors to temperatures
- */
-class TemperatureColorStore {
-
- private static class TemperatureColorValue {
- final float mTemperature;
- final int mColor;
-
- private TemperatureColorValue(float temperature, int color) {
- this.mTemperature = temperature;
- this.mColor = color;
- }
-
- float getTemperature() {
- return mTemperature;
- }
-
- int getColor() {
- return mColor;
- }
- }
-
- private static TemperatureColorValue tempToColor(float temperature, int color) {
- return new TemperatureColorValue(temperature, color);
- }
-
- private static final int COLOR_COLDEST = 0xFF406DFF;
- private static final int COLOR_COLD = 0xFF4094FF;
- private static final int COLOR_NEUTRAL = 0xFFF4F4F4;
- private static final int COLOR_WARM = 0xFFFF550F;
- private static final int COLOR_WARMEST = 0xFFFF0000;
- // must be sorted by temperature
- private static final TemperatureColorValue[] sTemperatureColorValues =
- {
- // Celsius
- tempToColor(19, COLOR_COLDEST),
- tempToColor(21, COLOR_COLD),
- tempToColor(23, COLOR_NEUTRAL),
- tempToColor(25, COLOR_WARM),
- tempToColor(27, COLOR_WARMEST),
-
- // Switch over
- tempToColor(45, COLOR_WARMEST),
- tempToColor(45.00001f, COLOR_COLDEST),
-
- // Farenheight
- tempToColor(66, COLOR_COLDEST),
- tempToColor(70, COLOR_COLD),
- tempToColor(74, COLOR_NEUTRAL),
- tempToColor(76, COLOR_WARM),
- tempToColor(80, COLOR_WARMEST)
- };
-
- private static final int COLOR_UNSET = Color.BLACK;
-
- private final float[] mTempHsv1 = new float[3];
- private final float[] mTempHsv2 = new float[3];
- private final float[] mTempHsv3 = new float[3];
-
- int getMinColor() {
- return COLOR_COLDEST;
- }
-
- int getMaxColor() {
- return COLOR_WARMEST;
- }
-
- int getColorForTemperature(float temperature) {
- if (Float.isNaN(temperature)) {
- return COLOR_UNSET;
- }
- TemperatureColorValue bottomValue = sTemperatureColorValues[0];
- if (temperature <= bottomValue.getTemperature()) {
- return bottomValue.getColor();
- }
- TemperatureColorValue topValue =
- sTemperatureColorValues[sTemperatureColorValues.length - 1];
- if (temperature >= topValue.getTemperature()) {
- return topValue.getColor();
- }
-
- int index = binarySearch(temperature);
- if (index >= 0) {
- return sTemperatureColorValues[index].getColor();
- }
-
- index = -index - 1; // move to the insertion point
-
- TemperatureColorValue startValue = sTemperatureColorValues[index - 1];
- TemperatureColorValue endValue = sTemperatureColorValues[index];
- float fraction = (temperature - startValue.getTemperature()) / (endValue.getTemperature()
- - startValue.getTemperature());
- return lerpColor(fraction, startValue.getColor(), endValue.getColor());
- }
-
- int lerpColor(float fraction, int startColor, int endColor) {
- float[] startHsv = mTempHsv1;
- Color.colorToHSV(startColor, startHsv);
- float[] endHsv = mTempHsv2;
- Color.colorToHSV(endColor, endHsv);
-
- // If a target color is white/gray, it should use the same hue as the other target
- if (startHsv[1] == 0) {
- startHsv[0] = endHsv[0];
- }
- if (endHsv[1] == 0) {
- endHsv[0] = startHsv[0];
- }
-
- float[] outColor = mTempHsv3;
- outColor[0] = hueLerp(fraction, startHsv[0], endHsv[0]);
- outColor[1] = lerp(fraction, startHsv[1], endHsv[1]);
- outColor[2] = lerp(fraction, startHsv[2], endHsv[2]);
-
- return Color.HSVToColor(outColor);
- }
-
- private float hueLerp(float fraction, float start, float end) {
- // If in flat part of curve, no interpolation necessary
- if (start == end) {
- return start;
- }
-
- // If the hues are more than 180 degrees apart, go the other way around the color wheel
- // by moving the smaller value above 360
- if (Math.abs(start - end) > 180f) {
- if (start < end) {
- start += 360f;
- } else {
- end += 360f;
- }
- }
- // Lerp and ensure the final output is within [0, 360)
- return lerp(fraction, start, end) % 360f;
-
- }
-
- private float lerp(float fraction, float start, float end) {
- // If in flat part of curve, no interpolation necessary
- if (start == end) {
- return start;
- }
-
- // If outside bounds, use boundary value
- if (fraction >= 1) {
- return end;
- }
- if (fraction <= 0) {
- return start;
- }
-
- return (end - start) * fraction + start;
- }
-
- private int binarySearch(float temperature) {
- int low = 0;
- int high = sTemperatureColorValues.length;
-
- while (low <= high) {
- int mid = (low + high) >>> 1;
- float midVal = sTemperatureColorValues[mid].getTemperature();
-
- if (midVal < temperature) {
- low = mid + 1; // Neither val is NaN, thisVal is smaller
- } else if (midVal > temperature) {
- high = mid - 1; // Neither val is NaN, thisVal is larger
- } else {
- int midBits = Float.floatToIntBits(midVal);
- int keyBits = Float.floatToIntBits(temperature);
- if (midBits == keyBits) { // Values are equal
- return mid; // Key found
- } else if (midBits < keyBits) { // (-0.0, 0.0) or (!NaN, NaN)
- low = mid + 1;
- } else { /* (0.0, -0.0) or (NaN, !NaN)*/
- high = mid - 1;
- }
- }
- }
- return -(low + 1); // key not found.
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextAnimator.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextAnimator.java
deleted file mode 100644
index 74d970464108..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextAnimator.java
+++ /dev/null
@@ -1,164 +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.car.hvac;
-
-import static com.android.systemui.car.hvac.AnimatedTemperatureView.isHorizontal;
-import static com.android.systemui.car.hvac.AnimatedTemperatureView.isLeft;
-
-import android.annotation.NonNull;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.RotateAnimation;
-import android.view.animation.TranslateAnimation;
-import android.widget.TextSwitcher;
-
-/**
- * Controls animating TemperatureView's text
- */
-class TemperatureTextAnimator {
-
- private static final DecelerateInterpolator DECELERATE_INTERPOLATOR =
- new DecelerateInterpolator();
- private static final AccelerateDecelerateInterpolator ACCELERATE_DECELERATE_INTERPOLATOR =
- new AccelerateDecelerateInterpolator();
-
- private static final int ROTATION_DEGREES = 15;
- private static final int DURATION_MILLIS = 200;
-
- private AnimatedTemperatureView mParent;
- private final TextSwitcher mTextSwitcher;
- private final String mTempFormat;
- private final int mPivotOffset;
- private final CharSequence mMinText;
- private final CharSequence mMaxText;
-
- private Animation mTextInAnimationUp;
- private Animation mTextOutAnimationUp;
- private Animation mTextInAnimationDown;
- private Animation mTextOutAnimationDown;
- private Animation mTextFadeInAnimation;
- private Animation mTextFadeOutAnimation;
-
- private float mLastTemp = Float.NaN;
-
- TemperatureTextAnimator(AnimatedTemperatureView parent, TextSwitcher textSwitcher,
- String tempFormat, int pivotOffset,
- CharSequence minText, CharSequence maxText) {
- mParent = parent;
- mTextSwitcher = textSwitcher;
- mTempFormat = tempFormat;
- mPivotOffset = pivotOffset;
- mMinText = minText;
- mMaxText = maxText;
-
- mParent.addOnLayoutChangeListener(
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
- setupAnimations(mParent.getGravity()));
- }
-
- void setTemp(float temp) {
- if (Float.isNaN(temp)) {
- mTextSwitcher.setInAnimation(mTextFadeInAnimation);
- mTextSwitcher.setOutAnimation(mTextFadeOutAnimation);
- mTextSwitcher.setText("--");
- mLastTemp = temp;
- return;
- }
- boolean isMinValue = mParent.isMinValue(temp);
- boolean isMaxValue = mParent.isMaxValue(temp);
- if (Float.isNaN(mLastTemp)) {
- mTextSwitcher.setInAnimation(mTextFadeInAnimation);
- mTextSwitcher.setOutAnimation(mTextFadeOutAnimation);
- } else if (!isMinValue && (isMaxValue || temp > mLastTemp)) {
- mTextSwitcher.setInAnimation(mTextInAnimationUp);
- mTextSwitcher.setOutAnimation(mTextOutAnimationUp);
- } else {
- mTextSwitcher.setInAnimation(mTextInAnimationDown);
- mTextSwitcher.setOutAnimation(mTextOutAnimationDown);
- }
- CharSequence text;
- if (isMinValue) {
- text = mMinText;
- } else if (isMaxValue) {
- text = mMaxText;
- } else {
- text = String.format(mTempFormat, temp);
- }
- mTextSwitcher.setText(text);
- mLastTemp = temp;
- }
-
- private void setupAnimations(int gravity) {
- mTextFadeInAnimation = createFadeAnimation(true);
- mTextFadeOutAnimation = createFadeAnimation(false);
- if (!isHorizontal(gravity)) {
- mTextInAnimationUp = createTranslateFadeAnimation(true, true);
- mTextOutAnimationUp = createTranslateFadeAnimation(false, true);
- mTextInAnimationDown = createTranslateFadeAnimation(true, false);
- mTextOutAnimationDown = createTranslateFadeAnimation(false, false);
- } else {
- boolean isLeft = isLeft(gravity, mTextSwitcher.getLayoutDirection());
- mTextInAnimationUp = createRotateFadeAnimation(true, isLeft, true);
- mTextOutAnimationUp = createRotateFadeAnimation(false, isLeft, true);
- mTextInAnimationDown = createRotateFadeAnimation(true, isLeft, false);
- mTextOutAnimationDown = createRotateFadeAnimation(false, isLeft, false);
- }
- }
-
- @NonNull
- private Animation createFadeAnimation(boolean in) {
- AnimationSet set = new AnimationSet(true);
- AlphaAnimation alphaAnimation = new AlphaAnimation(in ? 0 : 1, in ? 1 : 0);
- alphaAnimation.setDuration(DURATION_MILLIS);
- set.addAnimation(new RotateAnimation(0, 0)); // Undo any previous rotation
- set.addAnimation(alphaAnimation);
- return set;
- }
-
- @NonNull
- private Animation createTranslateFadeAnimation(boolean in, boolean up) {
- AnimationSet set = new AnimationSet(true);
- set.setInterpolator(ACCELERATE_DECELERATE_INTERPOLATOR);
- set.setDuration(DURATION_MILLIS);
- int fromYDelta = in ? (up ? 1 : -1) : 0;
- int toYDelta = in ? 0 : (up ? -1 : 1);
- set.addAnimation(
- new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0,
- Animation.RELATIVE_TO_SELF, fromYDelta, Animation.RELATIVE_TO_SELF,
- toYDelta));
- set.addAnimation(new AlphaAnimation(in ? 0 : 1, in ? 1 : 0));
- return set;
- }
-
- @NonNull
- private Animation createRotateFadeAnimation(boolean in, boolean isLeft, boolean up) {
- AnimationSet set = new AnimationSet(true);
- set.setInterpolator(DECELERATE_INTERPOLATOR);
- set.setDuration(DURATION_MILLIS);
-
- float degrees = isLeft == up ? -ROTATION_DEGREES : ROTATION_DEGREES;
- int pivotX = isLeft ? -mPivotOffset : mParent.getWidth() + mPivotOffset;
- set.addAnimation(
- new RotateAnimation(in ? -degrees : 0f, in ? 0f : degrees, Animation.ABSOLUTE,
- pivotX, Animation.ABSOLUTE, 0f));
- set.addAnimation(new AlphaAnimation(in ? 0 : 1, in ? 1 : 0));
- return set;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java
deleted file mode 100644
index 90df15c907dd..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java
+++ /dev/null
@@ -1,83 +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.car.hvac;
-
-import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-
-/**
- * Simple text display of HVAC properties, It is designed to show temperature and is configured in
- * the XML.
- * XML properties:
- * hvacAreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
- */
-public class TemperatureTextView extends TextView implements TemperatureView {
-
- private final int mAreaId;
- private final String mTempFormat;
- private HvacController mHvacController;
- private boolean mDisplayFahrenheit = false;
-
- public TemperatureTextView(Context context, AttributeSet attrs) {
- super(context, attrs);
- TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView);
- mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId, -1);
- mTempFormat = getResources().getString(R.string.hvac_temperature_format);
- }
-
- @Override
- public void setHvacController(HvacController controller) {
- mHvacController = controller;
- }
-
- /**
- * Formats the float for display
- *
- * @param temp - The current temp or NaN
- */
- @Override
- public void setTemp(float temp) {
- if (Float.isNaN(temp)) {
- setText("--");
- return;
- }
- if (mDisplayFahrenheit) {
- temp = convertToFahrenheit(temp);
- }
- setText(String.format(mTempFormat, temp));
- }
-
- @Override
- public void setDisplayInFahrenheit(boolean displayFahrenheit) {
- mDisplayFahrenheit = displayFahrenheit;
- }
-
- /**
- * @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
- */
- @Override
- public int getAreaId() {
- return mAreaId;
- }
-}
-
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java
deleted file mode 100644
index 6edf25431ffd..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java
+++ /dev/null
@@ -1,49 +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.car.hvac;
-
-/**
- * Interface for Views that display temperature HVAC properties.
- */
-public interface TemperatureView {
-
- /**
- * Sets the {@link HvacController} to handle changes to HVAC properties. The View is only
- * responsible for the UI to display temperature. It should not contain logic that makes direct
- * changes to HVAC properties and instead use this {@link HvacController}.
- */
- void setHvacController(HvacController controller);
-
- /**
- * Formats the float for display
- *
- * @param temp - The current temp in Celsius or NaN
- */
- void setTemp(float temp);
-
- /**
- * Render the displayed temperature in Fahrenheit
- *
- * @param displayFahrenheit - True if temperature should be displayed in Fahrenheit
- */
- void setDisplayInFahrenheit(boolean displayFahrenheit);
-
- /**
- * @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
- */
- int getAreaId();
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
deleted file mode 100644
index c190ae54b1cf..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
+++ /dev/null
@@ -1,404 +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.car.keyguard;
-
-import android.car.Car;
-import android.car.user.CarUserManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewRootImpl;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardViewController;
-import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.R;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.navigationbar.CarNavigationBarController;
-import com.android.systemui.car.window.OverlayViewController;
-import com.android.systemui.car.window.OverlayViewGlobalStateController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.phone.BiometricUnlockController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.statusbar.phone.KeyguardBouncer.Factory;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.NotificationPanelViewController;
-import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import javax.inject.Inject;
-
-import dagger.Lazy;
-
-/**
- * Automotive implementation of the {@link KeyguardViewController}. It controls the Keyguard View
- * that is mounted to the SystemUIOverlayWindow.
- */
-@SysUISingleton
-public class CarKeyguardViewController extends OverlayViewController implements
- KeyguardViewController {
- private static final String TAG = "CarKeyguardViewController";
- private static final boolean DEBUG = true;
-
- private final Handler mHandler;
- private final CarServiceProvider mCarServiceProvider;
- private final KeyguardStateController mKeyguardStateController;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
- private final ViewMediatorCallback mViewMediatorCallback;
- private final CarNavigationBarController mCarNavigationBarController;
- private final Factory mKeyguardBouncerFactory;
- // Needed to instantiate mBouncer.
- private final KeyguardBouncer.BouncerExpansionCallback
- mExpansionCallback = new KeyguardBouncer.BouncerExpansionCallback() {
- @Override
- public void onFullyShown() {
- }
-
- @Override
- public void onStartingToHide() {
- }
-
- @Override
- public void onStartingToShow() {
- }
-
- @Override
- public void onFullyHidden() {
- }
- };
- private final CarUserManager.UserLifecycleListener mUserLifecycleListener = (e) -> {
- if (e.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
- revealKeyguardIfBouncerPrepared();
- }
- };
-
- private KeyguardBouncer mBouncer;
- private OnKeyguardCancelClickedListener mKeyguardCancelClickedListener;
- private boolean mShowing;
- private boolean mIsOccluded;
-
- @Inject
- public CarKeyguardViewController(
- @Main Handler mainHandler,
- CarServiceProvider carServiceProvider,
- OverlayViewGlobalStateController overlayViewGlobalStateController,
- KeyguardStateController keyguardStateController,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
- ViewMediatorCallback viewMediatorCallback,
- CarNavigationBarController carNavigationBarController,
- KeyguardBouncer.Factory keyguardBouncerFactory) {
-
- super(R.id.keyguard_stub, overlayViewGlobalStateController);
-
- mHandler = mainHandler;
- mCarServiceProvider = carServiceProvider;
- mKeyguardStateController = keyguardStateController;
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
- mViewMediatorCallback = viewMediatorCallback;
- mCarNavigationBarController = carNavigationBarController;
- mKeyguardBouncerFactory = keyguardBouncerFactory;
-
- registerUserSwitchedListener();
- }
-
- @Override
- protected boolean shouldShowNavigationBarInsets() {
- return true;
- }
-
- @Override
- public void onFinishInflate() {
- mBouncer = mKeyguardBouncerFactory
- .create(getLayout().findViewById(R.id.keyguard_container), mExpansionCallback);
- mBiometricUnlockControllerLazy.get().setKeyguardViewController(this);
- }
-
- @Override
- public void notifyKeyguardAuthenticated(boolean strongAuth) {
- if (mBouncer != null) {
- mBouncer.notifyKeyguardAuthenticated(strongAuth);
- }
- }
-
- @Override
- public void showBouncer(boolean scrimmed) {
- if (mShowing && !mBouncer.isShowing()) {
- mBouncer.show(/* resetSecuritySelection= */ false);
- }
- }
-
- @Override
- public void show(Bundle options) {
- if (mShowing) return;
-
- mShowing = true;
- mKeyguardStateController.notifyKeyguardState(mShowing, /* occluded= */ false);
- mCarNavigationBarController.showAllKeyguardButtons(/* isSetUp= */ true);
- start();
- reset(/* hideBouncerWhenShowing= */ false);
- notifyKeyguardUpdateMonitor();
- }
-
- @Override
- public void hide(long startTime, long fadeoutDuration) {
- if (!mShowing) return;
-
- mViewMediatorCallback.readyForKeyguardDone();
- mShowing = false;
- mKeyguardStateController.notifyKeyguardState(mShowing, /* occluded= */ false);
- mBouncer.hide(/* destroyView= */ true);
- mCarNavigationBarController.hideAllKeyguardButtons(/* isSetUp= */ true);
- stop();
- mKeyguardStateController.notifyKeyguardDoneFading();
- mHandler.post(mViewMediatorCallback::keyguardGone);
- notifyKeyguardUpdateMonitor();
- }
-
- @Override
- public void reset(boolean hideBouncerWhenShowing) {
- if (mShowing) {
- if (mBouncer != null) {
- if (!mBouncer.isSecure()) {
- dismissAndCollapse();
- }
- mBouncer.show(/* resetSecuritySelection= */ true);
- }
- mKeyguardUpdateMonitor.sendKeyguardReset();
- notifyKeyguardUpdateMonitor();
- } else {
- // This is necessary in order to address an inconsistency between the keyguard service
- // and the keyguard views.
- // TODO: Investigate the source of the inconsistency.
- show(/* options= */ null);
- }
- }
-
- @Override
- public void onFinishedGoingToSleep() {
- if (mBouncer != null) {
- mBouncer.onScreenTurnedOff();
- }
- }
-
- @Override
- public void setOccluded(boolean occluded, boolean animate) {
- mIsOccluded = occluded;
- getOverlayViewGlobalStateController().setOccluded(occluded);
- if (!occluded) {
- reset(/* hideBouncerWhenShowing= */ false);
- }
- }
-
- @Override
- public void onCancelClicked() {
- if (mBouncer == null) return;
-
- getOverlayViewGlobalStateController().setWindowNeedsInput(/* needsInput= */ false);
-
- mBouncer.hide(/* destroyView= */ true);
- mKeyguardCancelClickedListener.onCancelClicked();
- }
-
- @Override
- public boolean isShowing() {
- return mShowing;
- }
-
- @Override
- public void dismissAndCollapse() {
- // If dismissing and collapsing Keyguard is requested (e.g. by a Keyguard-dismissing
- // Activity) while Keyguard is occluded, unocclude Keyguard so the user can authenticate to
- // dismiss Keyguard.
- if (mIsOccluded) {
- setOccluded(/* occluded= */ false, /* animate= */ false);
- }
- if (!mBouncer.isSecure()) {
- hide(/* startTime= */ 0, /* fadeoutDuration= */ 0);
- }
- }
-
- @Override
- public void startPreHideAnimation(Runnable finishRunnable) {
- if (mBouncer == null) return;
-
- mBouncer.startPreHideAnimation(finishRunnable);
- }
-
- @Override
- public void setNeedsInput(boolean needsInput) {
- getOverlayViewGlobalStateController().setWindowNeedsInput(needsInput);
- }
-
- /**
- * Add listener for keyguard cancel clicked.
- */
- public void registerOnKeyguardCancelClickedListener(
- OnKeyguardCancelClickedListener keyguardCancelClickedListener) {
- mKeyguardCancelClickedListener = keyguardCancelClickedListener;
- }
-
- /**
- * Remove listener for keyguard cancel clicked.
- */
- public void unregisterOnKeyguardCancelClickedListener(
- OnKeyguardCancelClickedListener keyguardCancelClickedListener) {
- mKeyguardCancelClickedListener = null;
- }
-
- @Override
- public ViewRootImpl getViewRootImpl() {
- return ((View) getLayout().getParent()).getViewRootImpl();
- }
-
- @Override
- public boolean isBouncerShowing() {
- return mBouncer != null && mBouncer.isShowing();
- }
-
- @Override
- public boolean bouncerIsOrWillBeShowing() {
- return mBouncer != null && (mBouncer.isShowing() || mBouncer.inTransit());
- }
-
- @Override
- public void keyguardGoingAway() {
- // no-op
- }
-
- @Override
- public void setKeyguardGoingAwayState(boolean isKeyguardGoingAway) {
- // no-op
- }
-
- @Override
- public void onStartedGoingToSleep() {
- // no-op
- }
-
- @Override
- public void onStartedWakingUp() {
- // no-op
- }
-
- @Override
- public void onScreenTurningOn() {
- // no-op
- }
-
- @Override
- public void onScreenTurnedOn() {
- // no-op
- }
-
- @Override
- public boolean shouldDisableWindowAnimationsForUnlock() {
- return false;
- }
-
- @Override
- public boolean isGoingToNotificationShade() {
- return false;
- }
-
- @Override
- public boolean isUnlockWithWallpaper() {
- return false;
- }
-
- @Override
- public boolean shouldSubtleWindowAnimationsForUnlock() {
- return false;
- }
-
- @Override
- public void registerStatusBar(StatusBar statusBar, ViewGroup container,
- NotificationPanelViewController notificationPanelViewController,
- BiometricUnlockController biometricUnlockController,
- ViewGroup lockIconContainer,
- View notificationContainer, KeyguardBypassController bypassController) {
- // no-op
- }
-
- /**
- * Hides Keyguard so that the transitioning Bouncer can be hidden until it is prepared. To be
- * called by {@link com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator}
- * when a new user is selected.
- */
- public void hideKeyguardToPrepareBouncer() {
- getLayout().setVisibility(View.INVISIBLE);
- }
-
- @VisibleForTesting
- void setKeyguardBouncer(KeyguardBouncer keyguardBouncer) {
- mBouncer = keyguardBouncer;
- }
-
- private void revealKeyguardIfBouncerPrepared() {
- int reattemptDelayMillis = 50;
- Runnable revealKeyguard = () -> {
- if (mBouncer == null) {
- if (DEBUG) {
- Log.d(TAG, "revealKeyguardIfBouncerPrepared: revealKeyguard request is ignored "
- + "since the Bouncer has not been initialized yet.");
- }
- return;
- }
- if (!mBouncer.inTransit() || !mBouncer.isSecure()) {
- getLayout().setVisibility(View.VISIBLE);
- } else {
- if (DEBUG) {
- Log.d(TAG, "revealKeyguardIfBouncerPrepared: Bouncer is not prepared "
- + "yet so reattempting after " + reattemptDelayMillis + "ms.");
- }
- mHandler.postDelayed(this::revealKeyguardIfBouncerPrepared, reattemptDelayMillis);
- }
- };
- mHandler.post(revealKeyguard);
- }
-
- private void notifyKeyguardUpdateMonitor() {
- mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(mShowing);
- if (mBouncer != null) {
- mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isBouncerShowing());
- }
- }
-
- private void registerUserSwitchedListener() {
- mCarServiceProvider.addListener(car -> {
- CarUserManager userManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
- userManager.addListener(Runnable::run, mUserLifecycleListener);
- });
- }
-
- /**
- * 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/car/keyguard/CarKeyguardViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewMediator.java
deleted file mode 100644
index 155b73e691ef..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewMediator.java
+++ /dev/null
@@ -1,54 +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.car.keyguard;
-
-import com.android.systemui.car.userswitcher.FullScreenUserSwitcherViewController;
-import com.android.systemui.car.window.OverlayViewMediator;
-import com.android.systemui.dagger.SysUISingleton;
-
-import javax.inject.Inject;
-
-/**
- * Manages events originating from the Keyguard service that cause Keyguard or other OverlayWindow
- * Components to appear or disappear.
- */
-@SysUISingleton
-public class CarKeyguardViewMediator implements OverlayViewMediator {
-
- private final CarKeyguardViewController mCarKeyguardViewController;
- private final FullScreenUserSwitcherViewController mFullScreenUserSwitcherViewController;
-
- @Inject
- public CarKeyguardViewMediator(
- CarKeyguardViewController carKeyguardViewController,
- FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController
- ) {
- mCarKeyguardViewController = carKeyguardViewController;
- mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController;
- }
-
- @Override
- public void registerListeners() {
- mCarKeyguardViewController.registerOnKeyguardCancelClickedListener(
- mFullScreenUserSwitcherViewController::start);
- }
-
- @Override
- public void setupOverlayContentViewControllers() {
- // no-op
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/AssitantButton.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/AssitantButton.java
deleted file mode 100644
index ede4696a96c3..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/AssitantButton.java
+++ /dev/null
@@ -1,71 +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.car.navigationbar;
-
-import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_ASSIST_GESTURE;
-
-import android.app.role.RoleManager;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.util.Log;
-
-import com.android.internal.app.AssistUtils;
-import com.android.internal.app.IVoiceInteractionSessionShowCallback;
-
-/**
- * AssitantButton is a ui component that will trigger the Voice Interaction Service.
- */
-public class AssitantButton extends CarNavigationButton {
- private static final String TAG = "AssistantButton";
- private final AssistUtils mAssistUtils;
- private IVoiceInteractionSessionShowCallback mShowCallback =
- new IVoiceInteractionSessionShowCallback.Stub() {
- @Override
- public void onFailed() {
- Log.w(TAG, "Failed to show VoiceInteractionSession");
- }
-
- @Override
- public void onShown() {
- Log.d(TAG, "IVoiceInteractionSessionShowCallback onShown()");
- }
- };
-
- public AssitantButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- mAssistUtils = new AssistUtils(context);
- setOnClickListener(v -> showAssistant());
- }
-
- private void showAssistant() {
- final Bundle args = new Bundle();
- mAssistUtils.showSessionForActiveService(args,
- SHOW_SOURCE_ASSIST_GESTURE, mShowCallback, /*activityToken=*/ null);
- }
-
- @Override
- protected void setUpIntents(TypedArray typedArray) {
- // left blank because for the assistant button Intent will not be passed from the layout.
- }
-
- @Override
- protected String getRoleName() {
- return RoleManager.ROLE_ASSISTANT;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonRoleHolderController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonRoleHolderController.java
deleted file mode 100644
index f8cd20fe8377..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonRoleHolderController.java
+++ /dev/null
@@ -1,142 +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.car.navigationbar;
-
-import android.annotation.Nullable;
-import android.app.role.OnRoleHoldersChangedListener;
-import android.app.role.RoleManager;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.dagger.SysUISingleton;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.inject.Inject;
-
-/**
- * Some CarNavigationButtons can be associated to a {@link RoleManager} role. When they are, it is
- * possible to have them display the icon of the default application (role holder) for the given
- * role.
- *
- * This class monitors the current role holders for each role type and updates the button icon for
- * this buttons with have this feature enabled.
- */
-@SysUISingleton
-public class ButtonRoleHolderController {
- private static final String TAG = "ButtonRoleHolderController";
-
- private final Context mContext;
- private final PackageManager mPackageManager;
- private final RoleManager mRoleManager;
- private final CarDeviceProvisionedController mDeviceController;
- private final Map<String, CarNavigationButton> mButtonMap = new HashMap<>();
- private final OnRoleHoldersChangedListener mListener = this::onRoleChanged;
- private boolean mRegistered;
-
- @Inject
- public ButtonRoleHolderController(Context context, PackageManager packageManager,
- RoleManager roleManager, CarDeviceProvisionedController deviceController) {
- mContext = context;
- mPackageManager = packageManager;
- mRoleManager = roleManager;
- mDeviceController = deviceController;
- }
-
- /**
- * Iterate through a view looking for CarNavigationButton and add it to this controller if it
- * opted to be associated with a {@link RoleManager} role type.
- *
- * @param v the View that may contain CarFacetButtons
- */
- void addAllButtonsWithRoleName(View v) {
- if (v instanceof CarNavigationButton) {
- CarNavigationButton button = (CarNavigationButton) v;
- String roleName = button.getRoleName();
- if (roleName != null && button.isDefaultAppIconForRoleEnabled()) {
- addButtonWithRoleName(button, roleName);
- }
- } else if (v instanceof ViewGroup) {
- ViewGroup viewGroup = (ViewGroup) v;
- for (int i = 0; i < viewGroup.getChildCount(); i++) {
- addAllButtonsWithRoleName(viewGroup.getChildAt(i));
- }
- }
- }
-
- private void addButtonWithRoleName(CarNavigationButton button, String roleName) {
- mButtonMap.put(roleName, button);
- updateIcon(roleName);
- if (!mRegistered) {
- mRoleManager.addOnRoleHoldersChangedListenerAsUser(mContext.getMainExecutor(),
- mListener, UserHandle.ALL);
- mRegistered = true;
- }
- }
-
- void removeAll() {
- mButtonMap.clear();
- if (mRegistered) {
- mRoleManager.removeOnRoleHoldersChangedListenerAsUser(mListener, UserHandle.ALL);
- mRegistered = false;
- }
- }
-
- @VisibleForTesting
- void onRoleChanged(String roleName, UserHandle user) {
- if (RoleManager.ROLE_ASSISTANT.equals(roleName)
- && user.getIdentifier() == mDeviceController.getCurrentUser()) {
- updateIcon(roleName);
- }
- }
-
- private void updateIcon(String roleName) {
- CarNavigationButton button = mButtonMap.get(roleName);
- if (button == null) {
- return;
- }
- List<String> holders = mRoleManager.getRoleHoldersAsUser(button.getRoleName(),
- UserHandle.of(mDeviceController.getCurrentUser()));
- if (holders == null || holders.isEmpty()) {
- button.setAppIcon(null);
- } else {
- button.setAppIcon(loadIcon(holders.get(0)));
- }
- }
-
- @Nullable
- private Drawable loadIcon(String packageName) {
- try {
- ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName,
- PackageManager.MATCH_ANY_USER);
- return appInfo.loadIcon(mPackageManager);
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(ButtonRoleHolderController.TAG, "Package not found: " + packageName, e);
- return null;
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateController.java
deleted file mode 100644
index 2dc475682fac..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateController.java
+++ /dev/null
@@ -1,232 +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.car.navigationbar;
-
-import android.app.ActivityTaskManager.RootTaskInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.view.Display;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.systemui.dagger.SysUISingleton;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.inject.Inject;
-
-/**
- * CarNavigationButtons can optionally have selection state that toggles certain visual indications
- * based on whether the active application on screen is associated with it. This is basically a
- * similar concept to a radio button group.
- *
- * This class controls the selection state of CarNavigationButtons that have opted in to have such
- * selection state-dependent visual indications.
- */
-@SysUISingleton
-public class ButtonSelectionStateController {
-
- private final Set<CarNavigationButton> mRegisteredViews = new HashSet<>();
-
- protected ButtonMap mButtonsByCategory = new ButtonMap();
- protected ButtonMap mButtonsByPackage = new ButtonMap();
- protected ButtonMap mButtonsByComponentName = new ButtonMap();
- protected HashSet<CarNavigationButton> mSelectedButtons;
- protected Context mContext;
-
- @Inject
- public ButtonSelectionStateController(Context context) {
- mContext = context;
- mSelectedButtons = new HashSet<>();
- }
-
- /**
- * Iterate through a view looking for CarNavigationButton and add it to the controller if it
- * opted in to be highlighted when the active application is associated with it.
- *
- * @param v the View that may contain CarFacetButtons
- */
- protected void addAllButtonsWithSelectionState(View v) {
- if (v instanceof CarNavigationButton) {
- if (((CarNavigationButton) v).hasSelectionState()) {
- addButtonWithSelectionState((CarNavigationButton) v);
- }
- } else if (v instanceof ViewGroup) {
- ViewGroup viewGroup = (ViewGroup) v;
- for (int i = 0; i < viewGroup.getChildCount(); i++) {
- addAllButtonsWithSelectionState(viewGroup.getChildAt(i));
- }
- }
- }
-
- /** Removes all buttons from the button maps. */
- protected void removeAll() {
- mButtonsByCategory.clear();
- mButtonsByPackage.clear();
- mButtonsByComponentName.clear();
- mSelectedButtons.clear();
- mRegisteredViews.clear();
- }
-
- /**
- * This will unselect the currently selected CarNavigationButton and determine which one should
- * be selected next. It does this by reading the properties on the CarNavigationButton and
- * seeing if they are a match with the supplied StackInfo list.
- * The order of selection detection is ComponentName, PackageName then Category
- * They will then be compared with the supplied StackInfo list.
- * The StackInfo is expected to be supplied in order of recency and StackInfo will only be used
- * for consideration if it has the same displayId as the CarNavigationButton.
- *
- * @param taskInfoList of the currently running application
- * @param validDisplay index of the valid display
- */
-
- protected void taskChanged(List<RootTaskInfo> taskInfoList, int validDisplay) {
- RootTaskInfo validTaskInfo = null;
- for (RootTaskInfo taskInfo : taskInfoList) {
- // Find the first stack info with a topActivity in the primary display.
- // TODO: We assume that CarFacetButton will launch an app only in the primary display.
- // We need to extend the functionality to handle the multiple display properly.
- if (taskInfo.topActivity != null && taskInfo.displayId == validDisplay) {
- validTaskInfo = taskInfo;
- break;
- }
- }
-
- if (validTaskInfo == null) {
- // No stack was found that was on the same display as the buttons thus return
- return;
- }
- int displayId = validTaskInfo.displayId;
-
- mSelectedButtons.forEach(carNavigationButton -> {
- if (carNavigationButton.getDisplayId() == displayId) {
- carNavigationButton.setSelected(false);
- }
- });
- mSelectedButtons.clear();
-
- HashSet<CarNavigationButton> selectedButtons = findSelectedButtons(validTaskInfo);
-
- if (selectedButtons != null) {
- selectedButtons.forEach(carNavigationButton -> {
- if (carNavigationButton.getDisplayId() == displayId) {
- carNavigationButton.setSelected(true);
- mSelectedButtons.add(carNavigationButton);
- }
- });
- }
- }
-
- /**
- * Defaults to Display.DEFAULT_DISPLAY when no parameter is provided for the validDisplay.
- *
- * @param taskInfoList
- */
- protected void taskChanged(List<RootTaskInfo> taskInfoList) {
- taskChanged(taskInfoList, Display.DEFAULT_DISPLAY);
- }
-
- /**
- * Add navigation button to this controller if it uses selection state.
- */
- private void addButtonWithSelectionState(CarNavigationButton carNavigationButton) {
- if (mRegisteredViews.contains(carNavigationButton)) {
- return;
- }
- String[] categories = carNavigationButton.getCategories();
- for (int i = 0; i < categories.length; i++) {
- mButtonsByCategory.add(categories[i], carNavigationButton);
- }
-
- String[] packages = carNavigationButton.getPackages();
- for (int i = 0; i < packages.length; i++) {
- mButtonsByPackage.add(packages[i], carNavigationButton);
- }
- String[] componentNames = carNavigationButton.getComponentName();
- for (int i = 0; i < componentNames.length; i++) {
- mButtonsByComponentName.add(componentNames[i], carNavigationButton);
- }
-
- mRegisteredViews.add(carNavigationButton);
- }
-
- private HashSet<CarNavigationButton> findSelectedButtons(RootTaskInfo validTaskInfo) {
- String packageName = validTaskInfo.topActivity.getPackageName();
-
- HashSet<CarNavigationButton> selectedButtons =
- findButtonsByComponentName(validTaskInfo.topActivity);
- if (selectedButtons == null) {
- selectedButtons = mButtonsByPackage.get(packageName);
- }
- if (selectedButtons == null) {
- String category = getPackageCategory(packageName);
- if (category != null) {
- selectedButtons = mButtonsByCategory.get(category);
- }
- }
-
- return selectedButtons;
- }
-
- private HashSet<CarNavigationButton> findButtonsByComponentName(
- ComponentName componentName) {
- HashSet<CarNavigationButton> buttons =
- mButtonsByComponentName.get(componentName.flattenToShortString());
- return (buttons != null) ? buttons :
- mButtonsByComponentName.get(componentName.flattenToString());
- }
-
- private String getPackageCategory(String packageName) {
- PackageManager pm = mContext.getPackageManager();
- Set<String> supportedCategories = mButtonsByCategory.keySet();
- for (String category : supportedCategories) {
- Intent intent = new Intent();
- intent.setPackage(packageName);
- intent.setAction(Intent.ACTION_MAIN);
- intent.addCategory(category);
- List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
- if (list.size() > 0) {
- // Cache this package name into ButtonsByPackage map, so we won't have to query
- // all categories next time this package name shows up.
- mButtonsByPackage.put(packageName, mButtonsByCategory.get(category));
- return category;
- }
- }
- return null;
- }
-
- // simple multi-map
- private static class ButtonMap extends HashMap<String, HashSet<CarNavigationButton>> {
-
- public boolean add(String key, CarNavigationButton value) {
- if (containsKey(key)) {
- return get(key).add(value);
- }
- HashSet<CarNavigationButton> set = new HashSet<>();
- set.add(value);
- put(key, set);
- return true;
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateListener.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateListener.java
deleted file mode 100644
index f74bd4fce312..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonSelectionStateListener.java
+++ /dev/null
@@ -1,62 +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.car.navigationbar;
-
-import android.app.ActivityTaskManager;
-import android.util.Log;
-
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-
-import javax.inject.Inject;
-
-/**
- * An implementation of TaskStackChangeListener, that listens for changes in the system
- * task stack and notifies the navigation bar.
- */
-@SysUISingleton
-class ButtonSelectionStateListener extends TaskStackChangeListener {
- private static final String TAG = ButtonSelectionStateListener.class.getSimpleName();
-
- private final ButtonSelectionStateController mButtonSelectionStateController;
-
- @Inject
- ButtonSelectionStateListener(ButtonSelectionStateController carNavigationButtonController) {
- mButtonSelectionStateController = carNavigationButtonController;
- }
-
- @Override
- public void onTaskStackChanged() {
- try {
- mButtonSelectionStateController.taskChanged(
- ActivityTaskManager.getService().getAllRootTaskInfos());
- } catch (Exception e) {
- Log.e(TAG, "Getting RootTaskInfo from activity task manager failed", e);
- }
- }
-
- @Override
- public void onTaskDisplayChanged(int taskId, int newDisplayId) {
- try {
- mButtonSelectionStateController.taskChanged(
- ActivityTaskManager.getService().getAllRootTaskInfos());
- } catch (Exception e) {
- Log.e(TAG, "Getting RootTaskInfo from activity task manager failed", e);
- }
-
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
deleted file mode 100644
index c7db3f6fc4f9..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
+++ /dev/null
@@ -1,590 +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.car.navigationbar;
-
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.containsType;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
-
-import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
-import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.inputmethodservice.InputMethodService;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.view.Display;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsetsController;
-import android.view.WindowManager;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.RegisterStatusBarResult;
-import com.android.internal.view.AppearanceRegion;
-import com.android.systemui.SystemUI;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarDeviceProvisionedListener;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.statusbar.AutoHideUiElement;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.AutoHideController;
-import com.android.systemui.statusbar.phone.BarTransitions;
-import com.android.systemui.statusbar.phone.LightBarController;
-import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy;
-import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-
-import dagger.Lazy;
-
-/** Navigation bars customized for the automotive use case. */
-public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks {
- private final Resources mResources;
- private final CarNavigationBarController mCarNavigationBarController;
- private final SysuiDarkIconDispatcher mStatusBarIconController;
- private final WindowManager mWindowManager;
- private final CarDeviceProvisionedController mCarDeviceProvisionedController;
- private final CommandQueue mCommandQueue;
- private final AutoHideController mAutoHideController;
- private final ButtonSelectionStateListener mButtonSelectionStateListener;
- private final Handler mMainHandler;
- private final Executor mUiBgExecutor;
- private final IStatusBarService mBarService;
- private final Lazy<KeyguardStateController> mKeyguardStateControllerLazy;
- private final Lazy<PhoneStatusBarPolicy> mIconPolicyLazy;
- private final Lazy<StatusBarIconController> mIconControllerLazy;
-
- private final int mDisplayId;
- private final SystemBarConfigs mSystemBarConfigs;
-
- private StatusBarSignalPolicy mSignalPolicy;
- private ActivityManagerWrapper mActivityManagerWrapper;
-
- // If the nav bar should be hidden when the soft keyboard is visible.
- private boolean mHideTopBarForKeyboard;
- private boolean mHideLeftBarForKeyboard;
- private boolean mHideRightBarForKeyboard;
- private boolean mHideBottomBarForKeyboard;
-
- private boolean mBottomNavBarVisible;
-
- // Nav bar views.
- private ViewGroup mTopNavigationBarWindow;
- private ViewGroup mBottomNavigationBarWindow;
- private ViewGroup mLeftNavigationBarWindow;
- private ViewGroup mRightNavigationBarWindow;
- private CarNavigationBarView mTopNavigationBarView;
- private CarNavigationBarView mBottomNavigationBarView;
- private CarNavigationBarView mLeftNavigationBarView;
- private CarNavigationBarView mRightNavigationBarView;
-
- // To be attached to the navigation bars such that they can close the notification panel if
- // it's open.
- private boolean mDeviceIsSetUpForUser = true;
- private boolean mIsUserSetupInProgress = false;
-
- private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0];
- @BarTransitions.TransitionMode
- private int mStatusBarMode;
- @BarTransitions.TransitionMode
- private int mNavigationBarMode;
- private boolean mStatusBarTransientShown;
- private boolean mNavBarTransientShown;
-
- @Inject
- public CarNavigationBar(Context context,
- @Main Resources resources,
- CarNavigationBarController carNavigationBarController,
- // TODO(b/156052638): Should not need to inject LightBarController
- LightBarController lightBarController,
- DarkIconDispatcher darkIconDispatcher,
- WindowManager windowManager,
- CarDeviceProvisionedController deviceProvisionedController,
- CommandQueue commandQueue,
- AutoHideController autoHideController,
- ButtonSelectionStateListener buttonSelectionStateListener,
- @Main Handler mainHandler,
- @UiBackground Executor uiBgExecutor,
- IStatusBarService barService,
- Lazy<KeyguardStateController> keyguardStateControllerLazy,
- Lazy<PhoneStatusBarPolicy> iconPolicyLazy,
- Lazy<StatusBarIconController> iconControllerLazy,
- SystemBarConfigs systemBarConfigs
- ) {
- super(context);
- mResources = resources;
- mCarNavigationBarController = carNavigationBarController;
- mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
- mWindowManager = windowManager;
- mCarDeviceProvisionedController = deviceProvisionedController;
- mCommandQueue = commandQueue;
- mAutoHideController = autoHideController;
- mButtonSelectionStateListener = buttonSelectionStateListener;
- mMainHandler = mainHandler;
- mUiBgExecutor = uiBgExecutor;
- mBarService = barService;
- mKeyguardStateControllerLazy = keyguardStateControllerLazy;
- mIconPolicyLazy = iconPolicyLazy;
- mIconControllerLazy = iconControllerLazy;
- mSystemBarConfigs = systemBarConfigs;
-
- mDisplayId = context.getDisplayId();
- }
-
- @Override
- public void start() {
- // Set initial state.
- mHideTopBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(SystemBarConfigs.TOP);
- mHideBottomBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(
- SystemBarConfigs.BOTTOM);
- mHideLeftBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(SystemBarConfigs.LEFT);
- mHideRightBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(
- SystemBarConfigs.RIGHT);
-
- mBottomNavBarVisible = false;
-
- // Connect into the status bar manager service
- mCommandQueue.addCallback(this);
-
- RegisterStatusBarResult result = null;
- try {
- result = mBarService.registerStatusBar(mCommandQueue);
- } catch (RemoteException ex) {
- ex.rethrowFromSystemServer();
- }
-
- onSystemBarAppearanceChanged(mDisplayId, result.mAppearance, result.mAppearanceRegions,
- result.mNavbarColorManagedByIme);
-
- // StatusBarManagerService has a back up of IME token and it's restored here.
- setImeWindowStatus(mDisplayId, result.mImeToken, result.mImeWindowVis,
- result.mImeBackDisposition, result.mShowImeSwitcher);
-
- // Set up the initial icon state
- int numIcons = result.mIcons.size();
- for (int i = 0; i < numIcons; i++) {
- mCommandQueue.setIcon(result.mIcons.keyAt(i), result.mIcons.valueAt(i));
- }
-
- mAutoHideController.setStatusBar(new AutoHideUiElement() {
- @Override
- public void synchronizeState() {
- // No op.
- }
-
- @Override
- public boolean isVisible() {
- return mStatusBarTransientShown;
- }
-
- @Override
- public void hide() {
- clearTransient();
- }
- });
-
- mAutoHideController.setNavigationBar(new AutoHideUiElement() {
- @Override
- public void synchronizeState() {
- // No op.
- }
-
- @Override
- public boolean isVisible() {
- return mNavBarTransientShown;
- }
-
- @Override
- public void hide() {
- clearTransient();
- }
- });
-
- mDeviceIsSetUpForUser = mCarDeviceProvisionedController.isCurrentUserSetup();
- mIsUserSetupInProgress = mCarDeviceProvisionedController.isCurrentUserSetupInProgress();
- mCarDeviceProvisionedController.addCallback(
- new CarDeviceProvisionedListener() {
- @Override
- public void onUserSetupInProgressChanged() {
- mMainHandler.post(() -> restartNavBarsIfNecessary());
- }
-
- @Override
- public void onUserSetupChanged() {
- mMainHandler.post(() -> restartNavBarsIfNecessary());
- }
-
- @Override
- public void onUserSwitched() {
- mMainHandler.post(() -> restartNavBarsIfNecessary());
- }
- });
-
- createNavigationBar(result);
-
- mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
- mActivityManagerWrapper.registerTaskStackListener(mButtonSelectionStateListener);
-
- mUiBgExecutor.execute(mCarNavigationBarController::connectToHvac);
-
- // Lastly, call to the icon policy to install/update all the icons.
- // Must be called on the main thread due to the use of observeForever() in
- // mIconPolicy.init().
- mMainHandler.post(() -> {
- mIconPolicyLazy.get().init();
- mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconControllerLazy.get());
- });
- }
-
- private void restartNavBarsIfNecessary() {
- boolean currentUserSetup = mCarDeviceProvisionedController.isCurrentUserSetup();
- boolean currentUserSetupInProgress = mCarDeviceProvisionedController
- .isCurrentUserSetupInProgress();
- if (mIsUserSetupInProgress != currentUserSetupInProgress
- || mDeviceIsSetUpForUser != currentUserSetup) {
- mDeviceIsSetUpForUser = currentUserSetup;
- mIsUserSetupInProgress = currentUserSetupInProgress;
- restartNavBars();
- }
- }
-
- /**
- * Remove all content from navbars and rebuild them. Used to allow for different nav bars
- * before and after the device is provisioned. . Also for change of density and font size.
- */
- private void restartNavBars() {
- // remove and reattach all components such that we don't keep a reference to unused ui
- // elements
- mCarNavigationBarController.removeAll();
-
- if (mTopNavigationBarWindow != null) {
- mTopNavigationBarWindow.removeAllViews();
- mTopNavigationBarView = null;
- }
-
- if (mBottomNavigationBarWindow != null) {
- mBottomNavigationBarWindow.removeAllViews();
- mBottomNavigationBarView = null;
- }
-
- if (mLeftNavigationBarWindow != null) {
- mLeftNavigationBarWindow.removeAllViews();
- mLeftNavigationBarView = null;
- }
-
- if (mRightNavigationBarWindow != null) {
- mRightNavigationBarWindow.removeAllViews();
- mRightNavigationBarView = null;
- }
-
- buildNavBarContent();
- // If the UI was rebuilt (day/night change or user change) while the keyguard was up we need
- // to correctly respect that state.
- if (mKeyguardStateControllerLazy.get().isShowing()) {
- mCarNavigationBarController.showAllKeyguardButtons(isDeviceSetupForUser());
- } else {
- mCarNavigationBarController.hideAllKeyguardButtons(isDeviceSetupForUser());
- }
-
- // Upon restarting the Navigation Bar, CarFacetButtonController should immediately apply the
- // selection state that reflects the current task stack.
- mButtonSelectionStateListener.onTaskStackChanged();
- }
-
- private boolean isDeviceSetupForUser() {
- return mDeviceIsSetUpForUser && !mIsUserSetupInProgress;
- }
-
- private void createNavigationBar(RegisterStatusBarResult result) {
- buildNavBarWindows();
- buildNavBarContent();
- attachNavBarWindows();
-
- // Try setting up the initial state of the nav bar if applicable.
- if (result != null) {
- setImeWindowStatus(Display.DEFAULT_DISPLAY, result.mImeToken,
- result.mImeWindowVis, result.mImeBackDisposition,
- result.mShowImeSwitcher);
- }
- }
-
- private void buildNavBarWindows() {
- mTopNavigationBarWindow = mCarNavigationBarController.getTopWindow();
- mBottomNavigationBarWindow = mCarNavigationBarController.getBottomWindow();
- mLeftNavigationBarWindow = mCarNavigationBarController.getLeftWindow();
- mRightNavigationBarWindow = mCarNavigationBarController.getRightWindow();
- }
-
- private void buildNavBarContent() {
- mTopNavigationBarView = mCarNavigationBarController.getTopBar(isDeviceSetupForUser());
- if (mTopNavigationBarView != null) {
- mSystemBarConfigs.insetSystemBar(SystemBarConfigs.TOP, mTopNavigationBarView);
- mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.TOP, mTopNavigationBarView);
- mTopNavigationBarWindow.addView(mTopNavigationBarView);
- }
-
- mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(isDeviceSetupForUser());
- if (mBottomNavigationBarView != null) {
- mSystemBarConfigs.insetSystemBar(SystemBarConfigs.BOTTOM, mBottomNavigationBarView);
- mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.BOTTOM, mBottomNavigationBarView);
- mBottomNavigationBarWindow.addView(mBottomNavigationBarView);
- }
-
- mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(isDeviceSetupForUser());
- if (mLeftNavigationBarView != null) {
- mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, mLeftNavigationBarView);
- mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.LEFT, mLeftNavigationBarView);
- mLeftNavigationBarWindow.addView(mLeftNavigationBarView);
- }
-
- mRightNavigationBarView = mCarNavigationBarController.getRightBar(isDeviceSetupForUser());
- if (mRightNavigationBarView != null) {
- mSystemBarConfigs.insetSystemBar(SystemBarConfigs.RIGHT, mRightNavigationBarView);
- mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.RIGHT, mRightNavigationBarView);
- mRightNavigationBarWindow.addView(mRightNavigationBarView);
- }
- }
-
- private void attachNavBarWindows() {
- mSystemBarConfigs.getSystemBarSidesByZOrder().forEach(this::attachNavBarBySide);
- }
-
- private void attachNavBarBySide(int side) {
- switch (side) {
- case SystemBarConfigs.TOP:
- if (mTopNavigationBarWindow != null) {
- mWindowManager.addView(mTopNavigationBarWindow,
- mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.TOP));
- }
- break;
- case SystemBarConfigs.BOTTOM:
- if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) {
- mBottomNavBarVisible = true;
-
- mWindowManager.addView(mBottomNavigationBarWindow,
- mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.BOTTOM));
- }
- break;
- case SystemBarConfigs.LEFT:
- if (mLeftNavigationBarWindow != null) {
- mWindowManager.addView(mLeftNavigationBarWindow,
- mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.LEFT));
- }
- break;
- case SystemBarConfigs.RIGHT:
- if (mRightNavigationBarWindow != null) {
- mWindowManager.addView(mRightNavigationBarWindow,
- mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.RIGHT));
- }
- break;
- default:
- return;
- }
- }
-
- /**
- * We register for soft keyboard visibility events such that we can hide the navigation bar
- * giving more screen space to the IME. Note: this is optional and controlled by
- * {@code com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard}.
- */
- @Override
- public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
- boolean showImeSwitcher) {
- if (mContext.getDisplayId() != displayId) {
- return;
- }
-
- boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
-
- if (mHideTopBarForKeyboard) {
- mCarNavigationBarController.setTopWindowVisibility(
- isKeyboardVisible ? View.GONE : View.VISIBLE);
- }
-
- if (mHideBottomBarForKeyboard) {
- mCarNavigationBarController.setBottomWindowVisibility(
- isKeyboardVisible ? View.GONE : View.VISIBLE);
- }
-
- if (mHideLeftBarForKeyboard) {
- mCarNavigationBarController.setLeftWindowVisibility(
- isKeyboardVisible ? View.GONE : View.VISIBLE);
- }
- if (mHideRightBarForKeyboard) {
- mCarNavigationBarController.setRightWindowVisibility(
- isKeyboardVisible ? View.GONE : View.VISIBLE);
- }
- }
-
- @Override
- public void onSystemBarAppearanceChanged(
- int displayId,
- @WindowInsetsController.Appearance int appearance,
- AppearanceRegion[] appearanceRegions,
- boolean navbarColorManagedByIme) {
- if (displayId != mDisplayId) {
- return;
- }
- boolean barModeChanged = updateStatusBarMode(
- mStatusBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT);
- int numStacks = appearanceRegions.length;
- boolean stackAppearancesChanged = mAppearanceRegions.length != numStacks;
- for (int i = 0; i < numStacks && !stackAppearancesChanged; i++) {
- stackAppearancesChanged |= !appearanceRegions[i].equals(mAppearanceRegions[i]);
- }
- if (stackAppearancesChanged || barModeChanged) {
- mAppearanceRegions = appearanceRegions;
- updateStatusBarAppearance();
- }
- }
-
- private void updateStatusBarAppearance() {
- int numStacks = mAppearanceRegions.length;
- int numLightStacks = 0;
-
- // We can only have maximum one light stack.
- int indexLightStack = -1;
-
- for (int i = 0; i < numStacks; i++) {
- if (isLight(mAppearanceRegions[i].getAppearance())) {
- numLightStacks++;
- indexLightStack = i;
- }
- }
-
- // If all stacks are light, all icons become dark.
- if (numLightStacks == numStacks) {
- mStatusBarIconController.setIconsDarkArea(null);
- mStatusBarIconController.getTransitionsController().setIconsDark(
- /* dark= */ true, /* animate= */ false);
- } else if (numLightStacks == 0) {
- // If no one is light, all icons become white.
- mStatusBarIconController.getTransitionsController().setIconsDark(
- /* dark= */ false, /* animate= */ false);
- } else {
- // Not the same for every stack, update icons in area only.
- mStatusBarIconController.setIconsDarkArea(
- mAppearanceRegions[indexLightStack].getBounds());
- mStatusBarIconController.getTransitionsController().setIconsDark(
- /* dark= */ true, /* animate= */ false);
- }
- }
-
- private static boolean isLight(int appearance) {
- return (appearance & APPEARANCE_LIGHT_STATUS_BARS) != 0;
- }
-
- @Override
- public void showTransient(int displayId, int[] types) {
- if (displayId != mDisplayId) {
- return;
- }
- if (containsType(types, ITYPE_STATUS_BAR)) {
- if (!mStatusBarTransientShown) {
- mStatusBarTransientShown = true;
- handleTransientChanged();
- }
- }
- if (containsType(types, ITYPE_NAVIGATION_BAR)) {
- if (!mNavBarTransientShown) {
- mNavBarTransientShown = true;
- handleTransientChanged();
- }
- }
- }
-
- @Override
- public void abortTransient(int displayId, int[] types) {
- if (displayId != mDisplayId) {
- return;
- }
- if (!containsType(types, ITYPE_STATUS_BAR) && !containsType(types, ITYPE_NAVIGATION_BAR)) {
- return;
- }
- clearTransient();
- }
-
- private void clearTransient() {
- if (mStatusBarTransientShown) {
- mStatusBarTransientShown = false;
- handleTransientChanged();
- }
- if (mNavBarTransientShown) {
- mNavBarTransientShown = false;
- handleTransientChanged();
- }
- }
-
- @VisibleForTesting
- boolean isStatusBarTransientShown() {
- return mStatusBarTransientShown;
- }
-
- @VisibleForTesting
- boolean isNavBarTransientShown() {
- return mNavBarTransientShown;
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.print(" mTaskStackListener=");
- pw.println(mButtonSelectionStateListener);
- pw.print(" mBottomNavigationBarView=");
- pw.println(mBottomNavigationBarView);
- }
-
- private void handleTransientChanged() {
- updateStatusBarMode(mStatusBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT);
- updateNavBarMode(mNavBarTransientShown ? MODE_SEMI_TRANSPARENT : MODE_TRANSPARENT);
- }
-
- // Returns true if the status bar mode has changed.
- private boolean updateStatusBarMode(int barMode) {
- if (mStatusBarMode != barMode) {
- mStatusBarMode = barMode;
- mAutoHideController.touchAutoHide();
- return true;
- }
- return false;
- }
-
- // Returns true if the nav bar mode has changed.
- private boolean updateNavBarMode(int barMode) {
- if (mNavigationBarMode != barMode) {
- mNavigationBarMode = barMode;
- mAutoHideController.touchAutoHide();
- return true;
- }
- return false;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
deleted file mode 100644
index 4fb522008578..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
+++ /dev/null
@@ -1,352 +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.car.navigationbar;
-
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.Nullable;
-
-import com.android.systemui.car.hvac.HvacController;
-import com.android.systemui.car.statusbar.UserNameViewController;
-import com.android.systemui.dagger.SysUISingleton;
-
-import javax.inject.Inject;
-
-import dagger.Lazy;
-
-/** A single class which controls the navigation bar views. */
-@SysUISingleton
-public class CarNavigationBarController {
-
- private final Context mContext;
- private final NavigationBarViewFactory mNavigationBarViewFactory;
- private final ButtonSelectionStateController mButtonSelectionStateController;
- private final ButtonRoleHolderController mButtonRoleHolderController;
- private final Lazy<HvacController> mHvacControllerLazy;
- private final Lazy<UserNameViewController> mUserNameViewControllerLazy;
-
- private boolean mShowTop;
- private boolean mShowBottom;
- private boolean mShowLeft;
- private boolean mShowRight;
-
- private View.OnTouchListener mTopBarTouchListener;
- private View.OnTouchListener mBottomBarTouchListener;
- private View.OnTouchListener mLeftBarTouchListener;
- private View.OnTouchListener mRightBarTouchListener;
- private NotificationsShadeController mNotificationsShadeController;
-
- private CarNavigationBarView mTopView;
- private CarNavigationBarView mBottomView;
- private CarNavigationBarView mLeftView;
- private CarNavigationBarView mRightView;
-
- @Inject
- public CarNavigationBarController(Context context,
- NavigationBarViewFactory navigationBarViewFactory,
- ButtonSelectionStateController buttonSelectionStateController,
- Lazy<HvacController> hvacControllerLazy,
- Lazy<UserNameViewController> userNameViewControllerLazy,
- ButtonRoleHolderController buttonRoleHolderController,
- SystemBarConfigs systemBarConfigs) {
- mContext = context;
- mNavigationBarViewFactory = navigationBarViewFactory;
- mButtonSelectionStateController = buttonSelectionStateController;
- mHvacControllerLazy = hvacControllerLazy;
- mUserNameViewControllerLazy = userNameViewControllerLazy;
- mButtonRoleHolderController = buttonRoleHolderController;
-
- // Read configuration.
- mShowTop = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.TOP);
- mShowBottom = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.BOTTOM);
- mShowLeft = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.LEFT);
- mShowRight = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.RIGHT);
- }
-
- /**
- * Hides all system bars.
- */
- public void hideBars() {
- setTopWindowVisibility(View.GONE);
- setBottomWindowVisibility(View.GONE);
- setLeftWindowVisibility(View.GONE);
- setRightWindowVisibility(View.GONE);
- }
-
- /**
- * Shows all system bars.
- */
- public void showBars() {
- setTopWindowVisibility(View.VISIBLE);
- setBottomWindowVisibility(View.VISIBLE);
- setLeftWindowVisibility(View.VISIBLE);
- setRightWindowVisibility(View.VISIBLE);
- }
-
- /** Connect to hvac service. */
- public void connectToHvac() {
- mHvacControllerLazy.get().connectToCarService();
- }
-
- /** Clean up */
- public void removeAll() {
- mHvacControllerLazy.get().removeAllComponents();
- mButtonSelectionStateController.removeAll();
- mButtonRoleHolderController.removeAll();
- mUserNameViewControllerLazy.get().removeAll();
- }
-
- /** Gets the top window if configured to do so. */
- @Nullable
- public ViewGroup getTopWindow() {
- return mShowTop ? mNavigationBarViewFactory.getTopWindow() : null;
- }
-
- /** Gets the bottom window if configured to do so. */
- @Nullable
- public ViewGroup getBottomWindow() {
- return mShowBottom ? mNavigationBarViewFactory.getBottomWindow() : null;
- }
-
- /** Gets the left window if configured to do so. */
- @Nullable
- public ViewGroup getLeftWindow() {
- return mShowLeft ? mNavigationBarViewFactory.getLeftWindow() : null;
- }
-
- /** Gets the right window if configured to do so. */
- @Nullable
- public ViewGroup getRightWindow() {
- return mShowRight ? mNavigationBarViewFactory.getRightWindow() : null;
- }
-
- /** Toggles the top nav bar visibility. */
- public boolean setTopWindowVisibility(@View.Visibility int visibility) {
- return setWindowVisibility(getTopWindow(), visibility);
- }
-
- /** Toggles the bottom nav bar visibility. */
- public boolean setBottomWindowVisibility(@View.Visibility int visibility) {
- return setWindowVisibility(getBottomWindow(), visibility);
- }
-
- /** Toggles the left nav bar visibility. */
- public boolean setLeftWindowVisibility(@View.Visibility int visibility) {
- return setWindowVisibility(getLeftWindow(), visibility);
- }
-
- /** Toggles the right nav bar visibility. */
- public boolean setRightWindowVisibility(@View.Visibility int visibility) {
- return setWindowVisibility(getRightWindow(), visibility);
- }
-
- private boolean setWindowVisibility(ViewGroup window, @View.Visibility int visibility) {
- if (window == null) {
- return false;
- }
-
- if (window.getVisibility() == visibility) {
- return false;
- }
-
- window.setVisibility(visibility);
- return true;
- }
-
- /** Gets the top navigation bar with the appropriate listeners set. */
- @Nullable
- public CarNavigationBarView getTopBar(boolean isSetUp) {
- if (!mShowTop) {
- return null;
- }
-
- mTopView = mNavigationBarViewFactory.getTopBar(isSetUp);
- setupBar(mTopView, mTopBarTouchListener, mNotificationsShadeController);
- return mTopView;
- }
-
- /** Gets the bottom navigation bar with the appropriate listeners set. */
- @Nullable
- public CarNavigationBarView getBottomBar(boolean isSetUp) {
- if (!mShowBottom) {
- return null;
- }
-
- mBottomView = mNavigationBarViewFactory.getBottomBar(isSetUp);
- setupBar(mBottomView, mBottomBarTouchListener, mNotificationsShadeController);
- return mBottomView;
- }
-
- /** Gets the left navigation bar with the appropriate listeners set. */
- @Nullable
- public CarNavigationBarView getLeftBar(boolean isSetUp) {
- if (!mShowLeft) {
- return null;
- }
-
- mLeftView = mNavigationBarViewFactory.getLeftBar(isSetUp);
- setupBar(mLeftView, mLeftBarTouchListener, mNotificationsShadeController);
- return mLeftView;
- }
-
- /** Gets the right navigation bar with the appropriate listeners set. */
- @Nullable
- public CarNavigationBarView getRightBar(boolean isSetUp) {
- if (!mShowRight) {
- return null;
- }
-
- mRightView = mNavigationBarViewFactory.getRightBar(isSetUp);
- setupBar(mRightView, mRightBarTouchListener, mNotificationsShadeController);
- return mRightView;
- }
-
- private void setupBar(CarNavigationBarView view, View.OnTouchListener statusBarTouchListener,
- NotificationsShadeController notifShadeController) {
- view.setStatusBarWindowTouchListener(statusBarTouchListener);
- view.setNotificationsPanelController(notifShadeController);
- mButtonSelectionStateController.addAllButtonsWithSelectionState(view);
- mButtonRoleHolderController.addAllButtonsWithRoleName(view);
- mHvacControllerLazy.get().addTemperatureViewToController(view);
- mUserNameViewControllerLazy.get().addUserNameView(view);
- }
-
- /** Sets a touch listener for the top navigation bar. */
- public void registerTopBarTouchListener(View.OnTouchListener listener) {
- mTopBarTouchListener = listener;
- if (mTopView != null) {
- mTopView.setStatusBarWindowTouchListener(mTopBarTouchListener);
- }
- }
-
- /** Sets a touch listener for the bottom navigation bar. */
- public void registerBottomBarTouchListener(View.OnTouchListener listener) {
- mBottomBarTouchListener = listener;
- if (mBottomView != null) {
- mBottomView.setStatusBarWindowTouchListener(mBottomBarTouchListener);
- }
- }
-
- /** Sets a touch listener for the left navigation bar. */
- public void registerLeftBarTouchListener(View.OnTouchListener listener) {
- mLeftBarTouchListener = listener;
- if (mLeftView != null) {
- mLeftView.setStatusBarWindowTouchListener(mLeftBarTouchListener);
- }
- }
-
- /** Sets a touch listener for the right navigation bar. */
- public void registerRightBarTouchListener(View.OnTouchListener listener) {
- mRightBarTouchListener = listener;
- if (mRightView != null) {
- mRightView.setStatusBarWindowTouchListener(mRightBarTouchListener);
- }
- }
-
- /** Sets a notification controller which toggles the notification panel. */
- public void registerNotificationController(
- NotificationsShadeController notificationsShadeController) {
- mNotificationsShadeController = notificationsShadeController;
- if (mTopView != null) {
- mTopView.setNotificationsPanelController(mNotificationsShadeController);
- }
- if (mBottomView != null) {
- mBottomView.setNotificationsPanelController(mNotificationsShadeController);
- }
- if (mLeftView != null) {
- mLeftView.setNotificationsPanelController(mNotificationsShadeController);
- }
- if (mRightView != null) {
- mRightView.setNotificationsPanelController(mNotificationsShadeController);
- }
- }
-
- /**
- * Shows all of the keyguard specific buttons on the valid instances of
- * {@link CarNavigationBarView}.
- */
- public void showAllKeyguardButtons(boolean isSetUp) {
- checkAllBars(isSetUp);
- if (mTopView != null) {
- mTopView.showKeyguardButtons();
- }
- if (mBottomView != null) {
- mBottomView.showKeyguardButtons();
- }
- if (mLeftView != null) {
- mLeftView.showKeyguardButtons();
- }
- if (mRightView != null) {
- mRightView.showKeyguardButtons();
- }
- }
-
- /**
- * Hides all of the keyguard specific buttons on the valid instances of
- * {@link CarNavigationBarView}.
- */
- public void hideAllKeyguardButtons(boolean isSetUp) {
- checkAllBars(isSetUp);
- if (mTopView != null) {
- mTopView.hideKeyguardButtons();
- }
- if (mBottomView != null) {
- mBottomView.hideKeyguardButtons();
- }
- if (mLeftView != null) {
- mLeftView.hideKeyguardButtons();
- }
- if (mRightView != null) {
- mRightView.hideKeyguardButtons();
- }
- }
-
- /** Toggles whether the notifications icon has an unseen indicator or not. */
- public void toggleAllNotificationsUnseenIndicator(boolean isSetUp, boolean hasUnseen) {
- checkAllBars(isSetUp);
- if (mTopView != null) {
- mTopView.toggleNotificationUnseenIndicator(hasUnseen);
- }
- if (mBottomView != null) {
- mBottomView.toggleNotificationUnseenIndicator(hasUnseen);
- }
- if (mLeftView != null) {
- mLeftView.toggleNotificationUnseenIndicator(hasUnseen);
- }
- if (mRightView != null) {
- mRightView.toggleNotificationUnseenIndicator(hasUnseen);
- }
- }
-
- /** Interface for controlling the notifications shade. */
- public interface NotificationsShadeController {
- /** Toggles the visibility of the notifications shade. */
- void togglePanel();
-
- /** Returns {@code true} if the panel is open. */
- boolean isNotificationPanelOpen();
- }
-
- private void checkAllBars(boolean isSetUp) {
- mTopView = getTopBar(isSetUp);
- mBottomView = getBottomBar(isSetUp);
- mLeftView = getLeftBar(isSetUp);
- mRightView = getRightBar(isSetUp);
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
deleted file mode 100644
index ab401bbf06bb..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.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.car.navigationbar;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.car.navigationbar.CarNavigationBarController.NotificationsShadeController;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-
-/**
- * A custom navigation bar for the automotive use case.
- * <p>
- * The navigation bar in the automotive use case is more like a list of shortcuts, rendered
- * in a linear layout.
- */
-public class CarNavigationBarView extends LinearLayout {
- private final boolean mConsumeTouchWhenPanelOpen;
-
- private View mNavButtons;
- private CarNavigationButton mNotificationsButton;
- private NotificationsShadeController mNotificationsShadeController;
- private View mLockScreenButtons;
- // used to wire in open/close gestures for notifications
- private OnTouchListener mStatusBarWindowTouchListener;
-
- public CarNavigationBarView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mConsumeTouchWhenPanelOpen = getResources().getBoolean(
- R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen);
- }
-
- @Override
- public void onFinishInflate() {
- mNavButtons = findViewById(R.id.nav_buttons);
- mLockScreenButtons = findViewById(R.id.lock_screen_nav_buttons);
-
- mNotificationsButton = findViewById(R.id.notifications);
- if (mNotificationsButton != null) {
- mNotificationsButton.setOnClickListener(this::onNotificationsClick);
- }
- View mStatusIcons = findViewById(R.id.statusIcons);
- if (mStatusIcons != null) {
- // Attach the controllers for Status icons such as wifi and bluetooth if the standard
- // container is in the view.
- StatusBarIconController.DarkIconManager mDarkIconManager =
- new StatusBarIconController.DarkIconManager(
- mStatusIcons.findViewById(R.id.statusIcons),
- Dependency.get(CommandQueue.class));
- mDarkIconManager.setShouldLog(true);
- Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
- }
- // Needs to be clickable so that it will receive ACTION_MOVE events.
- setClickable(true);
- // Needs to not be focusable so rotary won't highlight the entire nav bar.
- setFocusable(false);
- }
-
- // Used to forward touch events even if the touch was initiated from a child component
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (mStatusBarWindowTouchListener != null) {
- boolean shouldConsumeEvent = mNotificationsShadeController == null ? false
- : mNotificationsShadeController.isNotificationPanelOpen();
-
- // Forward touch events to the status bar window so it can drag
- // windows if required (Notification shade)
- mStatusBarWindowTouchListener.onTouch(this, ev);
-
- if (mConsumeTouchWhenPanelOpen && shouldConsumeEvent) {
- return true;
- }
- }
- return super.onInterceptTouchEvent(ev);
- }
-
- /** Sets the notifications panel controller. */
- public void setNotificationsPanelController(NotificationsShadeController controller) {
- mNotificationsShadeController = controller;
- }
-
- /** Gets the notifications panel controller. */
- public NotificationsShadeController getNotificationsPanelController() {
- return mNotificationsShadeController;
- }
-
- /**
- * Sets a touch listener that will be called from onInterceptTouchEvent and onTouchEvent
- *
- * @param statusBarWindowTouchListener The listener to call from touch and intercept touch
- */
- public void setStatusBarWindowTouchListener(OnTouchListener statusBarWindowTouchListener) {
- mStatusBarWindowTouchListener = statusBarWindowTouchListener;
- }
-
- /** Gets the touch listener that will be called from onInterceptTouchEvent and onTouchEvent. */
- public OnTouchListener getStatusBarWindowTouchListener() {
- return mStatusBarWindowTouchListener;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mStatusBarWindowTouchListener != null) {
- mStatusBarWindowTouchListener.onTouch(this, event);
- }
- return super.onTouchEvent(event);
- }
-
- protected void onNotificationsClick(View v) {
- if (mNotificationsShadeController != null) {
- mNotificationsShadeController.togglePanel();
- }
- }
-
- /**
- * If there are buttons declared in the layout they will be shown and the normal
- * Nav buttons will be hidden.
- */
- public void showKeyguardButtons() {
- if (mLockScreenButtons == null) {
- return;
- }
- mLockScreenButtons.setVisibility(View.VISIBLE);
- mNavButtons.setVisibility(View.GONE);
- }
-
- /**
- * If there are buttons declared in the layout they will be hidden and the normal
- * Nav buttons will be shown.
- */
- public void hideKeyguardButtons() {
- if (mLockScreenButtons == null) return;
-
- mNavButtons.setVisibility(View.VISIBLE);
- mLockScreenButtons.setVisibility(View.GONE);
- }
-
- /**
- * Toggles the notification unseen indicator on/off.
- *
- * @param hasUnseen true if the unseen notification count is great than 0.
- */
- public void toggleNotificationUnseenIndicator(Boolean hasUnseen) {
- if (mNotificationsButton == null) return;
-
- mNotificationsButton.setUnseen(hasUnseen);
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java
deleted file mode 100644
index d2b931b3624b..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java
+++ /dev/null
@@ -1,319 +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.car.navigationbar;
-
-import android.app.ActivityOptions;
-import android.app.role.RoleManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.UserHandle;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Display;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.AlphaOptimizedImageView;
-
-import java.net.URISyntaxException;
-
-/**
- * CarNavigationButton is an image button that allows for a bit more configuration at the
- * xml file level. This allows for more control via overlays instead of having to update
- * code.
- */
-public class CarNavigationButton extends LinearLayout {
-
- protected static final float DEFAULT_SELECTED_ALPHA = 1f;
- protected static final float DEFAULT_UNSELECTED_ALPHA = 0.75f;
-
- private static final String TAG = "CarNavigationButton";
- private static final String BUTTON_FILTER_DELIMITER = ";";
- private static final String EXTRA_BUTTON_CATEGORIES = "categories";
- private static final String EXTRA_BUTTON_PACKAGES = "packages";
-
- private Context mContext;
- private AlphaOptimizedImageView mIcon;
- private AlphaOptimizedImageView mMoreIcon;
- private ImageView mUnseenIcon;
- private String mIntent;
- private String mLongIntent;
- private boolean mBroadcastIntent;
- private boolean mHasUnseen = false;
- private boolean mSelected = false;
- private float mSelectedAlpha;
- private float mUnselectedAlpha;
- private int mSelectedIconResourceId;
- private int mIconResourceId;
- private Drawable mAppIcon;
- private boolean mIsDefaultAppIconForRoleEnabled;
- private String[] mComponentNames;
- /** App categories that are to be used with this widget */
- private String[] mButtonCategories;
- /** App packages that are allowed to be used with this widget */
- private String[] mButtonPackages;
- /** Whether to display more icon beneath the primary icon when the button is selected */
- private boolean mShowMoreWhenSelected = false;
- /** Whether to highlight the button if the active application is associated with it */
- private boolean mHighlightWhenSelected = false;
-
- public CarNavigationButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- View.inflate(mContext, R.layout.car_navigation_button, /* root= */ this);
- // CarNavigationButton attrs
- TypedArray typedArray = context.obtainStyledAttributes(attrs,
- R.styleable.CarNavigationButton);
-
- setUpIntents(typedArray);
- setUpIcons(typedArray);
- typedArray.recycle();
- }
-
- /**
- * @param selected true if should indicate if this is a selected state, false otherwise
- */
- public void setSelected(boolean selected) {
- super.setSelected(selected);
- mSelected = selected;
-
- if (mHighlightWhenSelected) {
- setAlpha(mSelected ? mSelectedAlpha : mUnselectedAlpha);
- }
-
- if (mShowMoreWhenSelected && mMoreIcon != null) {
- mMoreIcon.setVisibility(selected ? VISIBLE : GONE);
- }
- updateImage();
- }
-
- /**
- * @param hasUnseen true if should indicate if this is a Unseen state, false otherwise.
- */
- public void setUnseen(boolean hasUnseen) {
- mHasUnseen = hasUnseen;
- updateImage();
- }
-
- /**
- * Sets the current icon of the default application associated with this button.
- */
- public void setAppIcon(Drawable appIcon) {
- mAppIcon = appIcon;
- updateImage();
- }
-
- /** Gets the icon of the app currently associated to the role of this button. */
- @VisibleForTesting
- protected Drawable getAppIcon() {
- return mAppIcon;
- }
-
- /** Gets whether the icon is in an unseen state. */
- public boolean getUnseen() {
- return mHasUnseen;
- }
-
- /**
- * @return The app categories the component represents
- */
- public String[] getCategories() {
- if (mButtonCategories == null) {
- return new String[0];
- }
- return mButtonCategories;
- }
-
- /**
- * @return The valid packages that should be considered.
- */
- public String[] getPackages() {
- if (mButtonPackages == null) {
- return new String[0];
- }
- return mButtonPackages;
- }
-
- /**
- * @return The list of component names.
- */
- public String[] getComponentName() {
- if (mComponentNames == null) {
- return new String[0];
- }
- return mComponentNames;
- }
-
- /**
- * Subclasses should override this method to return the {@link RoleManager} role associated
- * with this button.
- */
- protected String getRoleName() {
- return null;
- }
-
- /**
- * @return true if this button should show the icon of the default application for the
- * role returned by {@link #getRoleName()}.
- */
- protected boolean isDefaultAppIconForRoleEnabled() {
- return mIsDefaultAppIconForRoleEnabled;
- }
-
- /**
- * @return The id of the display the button is on or Display.INVALID_DISPLAY if it's not yet on
- * a display.
- */
- protected int getDisplayId() {
- Display display = getDisplay();
- if (display == null) {
- return Display.INVALID_DISPLAY;
- }
- return display.getDisplayId();
- }
-
- protected boolean hasSelectionState() {
- return mHighlightWhenSelected || mShowMoreWhenSelected;
- }
-
- /**
- * Sets up intents for click, long touch, and broadcast.
- */
- protected void setUpIntents(TypedArray typedArray) {
- mIntent = typedArray.getString(R.styleable.CarNavigationButton_intent);
- mLongIntent = typedArray.getString(R.styleable.CarNavigationButton_longIntent);
- mBroadcastIntent = typedArray.getBoolean(R.styleable.CarNavigationButton_broadcast, false);
-
- String categoryString = typedArray.getString(R.styleable.CarNavigationButton_categories);
- String packageString = typedArray.getString(R.styleable.CarNavigationButton_packages);
- String componentNameString =
- typedArray.getString(R.styleable.CarNavigationButton_componentNames);
-
- try {
- if (mIntent != null) {
- final Intent intent = Intent.parseUri(mIntent, Intent.URI_INTENT_SCHEME);
- setOnClickListener(getButtonClickListener(intent));
- if (packageString != null) {
- mButtonPackages = packageString.split(BUTTON_FILTER_DELIMITER);
- intent.putExtra(EXTRA_BUTTON_PACKAGES, mButtonPackages);
- }
- if (categoryString != null) {
- mButtonCategories = categoryString.split(BUTTON_FILTER_DELIMITER);
- intent.putExtra(EXTRA_BUTTON_CATEGORIES, mButtonCategories);
- }
- if (componentNameString != null) {
- mComponentNames = componentNameString.split(BUTTON_FILTER_DELIMITER);
- }
- }
- } catch (URISyntaxException e) {
- throw new RuntimeException("Failed to attach intent", e);
- }
-
- try {
- if (mLongIntent != null && (Build.IS_ENG || Build.IS_USERDEBUG)) {
- final Intent intent = Intent.parseUri(mLongIntent, Intent.URI_INTENT_SCHEME);
- setOnLongClickListener(getButtonLongClickListener(intent));
- }
- } catch (URISyntaxException e) {
- throw new RuntimeException("Failed to attach long press intent", e);
- }
- }
-
- /** Defines the behavior of a button click. */
- protected OnClickListener getButtonClickListener(Intent toSend) {
- return v -> {
- mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS),
- UserHandle.CURRENT);
- try {
- if (mBroadcastIntent) {
- mContext.sendBroadcastAsUser(toSend, UserHandle.CURRENT);
- return;
- }
- ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchDisplayId(mContext.getDisplayId());
- mContext.startActivityAsUser(toSend, options.toBundle(),
- UserHandle.CURRENT);
- } catch (Exception e) {
- Log.e(TAG, "Failed to launch intent", e);
- }
- };
- }
-
- /** Defines the behavior of a long click. */
- protected OnLongClickListener getButtonLongClickListener(Intent toSend) {
- return v -> {
- mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS),
- UserHandle.CURRENT);
- try {
- ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchDisplayId(mContext.getDisplayId());
- mContext.startActivityAsUser(toSend, options.toBundle(),
- UserHandle.CURRENT);
- } catch (Exception e) {
- Log.e(TAG, "Failed to launch intent", e);
- }
- // consume event either way
- return true;
- };
- }
-
- /**
- * Initializes view-related aspects of the button.
- */
- private void setUpIcons(TypedArray typedArray) {
- mSelectedAlpha = typedArray.getFloat(
- R.styleable.CarNavigationButton_selectedAlpha, DEFAULT_SELECTED_ALPHA);
- mUnselectedAlpha = typedArray.getFloat(
- R.styleable.CarNavigationButton_unselectedAlpha, DEFAULT_UNSELECTED_ALPHA);
- mHighlightWhenSelected = typedArray.getBoolean(
- R.styleable.CarNavigationButton_highlightWhenSelected,
- mHighlightWhenSelected);
- mShowMoreWhenSelected = typedArray.getBoolean(
- R.styleable.CarNavigationButton_showMoreWhenSelected,
- mShowMoreWhenSelected);
-
- mIconResourceId = typedArray.getResourceId(
- R.styleable.CarNavigationButton_icon, 0);
- mSelectedIconResourceId = typedArray.getResourceId(
- R.styleable.CarNavigationButton_selectedIcon, mIconResourceId);
- mIsDefaultAppIconForRoleEnabled = typedArray.getBoolean(
- R.styleable.CarNavigationButton_useDefaultAppIconForRole, false);
- mIcon = findViewById(R.id.car_nav_button_icon_image);
- // Always apply un-selected alpha regardless of if the button toggles alpha based on
- // selection state.
- setAlpha(mHighlightWhenSelected ? mUnselectedAlpha : mSelectedAlpha);
- mMoreIcon = findViewById(R.id.car_nav_button_more_icon);
- mUnseenIcon = findViewById(R.id.car_nav_button_unseen_icon);
- updateImage();
- }
-
- private void updateImage() {
- if (mIsDefaultAppIconForRoleEnabled && mAppIcon != null) {
- mIcon.setImageDrawable(mAppIcon);
- } else {
- mIcon.setImageResource(mSelected ? mSelectedIconResourceId : mIconResourceId);
- }
- mUnseenIcon.setVisibility(mHasUnseen ? VISIBLE : GONE);
- }
-
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java
deleted file mode 100644
index a473bb7423b7..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java
+++ /dev/null
@@ -1,158 +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.car.navigationbar;
-
-import android.content.Context;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.LayoutRes;
-
-import com.android.car.ui.FocusParkingView;
-import com.android.systemui.R;
-import com.android.systemui.dagger.SysUISingleton;
-
-import javax.inject.Inject;
-
-/** A factory that creates and caches views for navigation bars. */
-@SysUISingleton
-public class NavigationBarViewFactory {
-
- private static final String TAG = NavigationBarViewFactory.class.getSimpleName();
- private static final ArrayMap<Type, Integer> sLayoutMap = setupLayoutMapping();
-
- private static ArrayMap<Type, Integer> setupLayoutMapping() {
- ArrayMap<Type, Integer> map = new ArrayMap<>();
- map.put(Type.TOP, R.layout.car_top_navigation_bar);
- map.put(Type.TOP_UNPROVISIONED, R.layout.car_top_navigation_bar_unprovisioned);
- map.put(Type.BOTTOM, R.layout.car_navigation_bar);
- map.put(Type.BOTTOM_UNPROVISIONED, R.layout.car_navigation_bar_unprovisioned);
- map.put(Type.LEFT, R.layout.car_left_navigation_bar);
- map.put(Type.LEFT_UNPROVISIONED, R.layout.car_left_navigation_bar_unprovisioned);
- map.put(Type.RIGHT, R.layout.car_right_navigation_bar);
- map.put(Type.RIGHT_UNPROVISIONED, R.layout.car_right_navigation_bar_unprovisioned);
- return map;
- }
-
- private final Context mContext;
- private final ArrayMap<Type, CarNavigationBarView> mCachedViewMap = new ArrayMap<>(
- Type.values().length);
- private final ArrayMap<Type, ViewGroup> mCachedContainerMap = new ArrayMap<>();
-
- /** Type of navigation bar to be created. */
- private enum Type {
- TOP,
- TOP_UNPROVISIONED,
- BOTTOM,
- BOTTOM_UNPROVISIONED,
- LEFT,
- LEFT_UNPROVISIONED,
- RIGHT,
- RIGHT_UNPROVISIONED
- }
-
- @Inject
- public NavigationBarViewFactory(Context context) {
- mContext = context;
- }
-
- /** Gets the top window. */
- public ViewGroup getTopWindow() {
- return getWindowCached(Type.TOP);
- }
-
- /** Gets the bottom window. */
- public ViewGroup getBottomWindow() {
- return getWindowCached(Type.BOTTOM);
- }
-
- /** Gets the left window. */
- public ViewGroup getLeftWindow() {
- return getWindowCached(Type.LEFT);
- }
-
- /** Gets the right window. */
- public ViewGroup getRightWindow() {
- return getWindowCached(Type.RIGHT);
- }
-
- /** Gets the top bar. */
- public CarNavigationBarView getTopBar(boolean isSetUp) {
- return getBar(isSetUp, Type.TOP, Type.TOP_UNPROVISIONED);
- }
-
- /** Gets the bottom bar. */
- public CarNavigationBarView getBottomBar(boolean isSetUp) {
- return getBar(isSetUp, Type.BOTTOM, Type.BOTTOM_UNPROVISIONED);
- }
-
- /** Gets the left bar. */
- public CarNavigationBarView getLeftBar(boolean isSetUp) {
- return getBar(isSetUp, Type.LEFT, Type.LEFT_UNPROVISIONED);
- }
-
- /** Gets the right bar. */
- public CarNavigationBarView getRightBar(boolean isSetUp) {
- return getBar(isSetUp, Type.RIGHT, Type.RIGHT_UNPROVISIONED);
- }
-
- private ViewGroup getWindowCached(Type type) {
- if (mCachedContainerMap.containsKey(type)) {
- return mCachedContainerMap.get(type);
- }
-
- ViewGroup window = (ViewGroup) View.inflate(mContext,
- R.layout.navigation_bar_window, /* root= */ null);
- mCachedContainerMap.put(type, window);
- return mCachedContainerMap.get(type);
- }
-
- private CarNavigationBarView getBar(boolean isSetUp, Type provisioned, Type unprovisioned) {
- CarNavigationBarView view;
- if (isSetUp) {
- view = getBarCached(provisioned, sLayoutMap.get(provisioned));
- } else {
- view = getBarCached(unprovisioned, sLayoutMap.get(unprovisioned));
- }
-
- if (view == null) {
- String name = isSetUp ? provisioned.name() : unprovisioned.name();
- Log.e(TAG, "CarStatusBar failed inflate for " + name);
- throw new RuntimeException(
- "Unable to build " + name + " nav bar due to missing layout");
- }
- return view;
- }
-
- private CarNavigationBarView getBarCached(Type type, @LayoutRes int barLayout) {
- if (mCachedViewMap.containsKey(type)) {
- return mCachedViewMap.get(type);
- }
-
- CarNavigationBarView view = (CarNavigationBarView) View.inflate(mContext, barLayout,
- /* root= */ null);
-
- // Include a FocusParkingView at the beginning. The rotary controller "parks" the focus here
- // when the user navigates to another window. This is also used to prevent wrap-around.
- view.addView(new FocusParkingView(mContext), 0);
-
- mCachedViewMap.put(type, view);
- return mCachedViewMap.get(type);
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
deleted file mode 100644
index 92cf60006917..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
+++ /dev/null
@@ -1,548 +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.car.navigationbar;
-
-import android.annotation.IntDef;
-import android.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.InsetsState;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
-import com.android.systemui.car.notification.BottomNotificationPanelViewMediator;
-import com.android.systemui.car.notification.TopNotificationPanelViewMediator;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.inject.Inject;
-
-/**
- * Reads configs for system bars for each side (TOP, BOTTOM, LEFT, and RIGHT) and returns the
- * corresponding {@link android.view.WindowManager.LayoutParams} per the configuration.
- */
-@SysUISingleton
-public class SystemBarConfigs {
-
- private static final String TAG = SystemBarConfigs.class.getSimpleName();
- // The z-order from which system bars will start to appear on top of HUN's.
- private static final int HUN_ZORDER = 10;
-
- @IntDef(value = {TOP, BOTTOM, LEFT, RIGHT})
- @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
- private @interface SystemBarSide {
- }
-
- public static final int TOP = 0;
- public static final int BOTTOM = 1;
- public static final int LEFT = 2;
- public static final int RIGHT = 3;
-
- /*
- NOTE: The elements' order in the map below must be preserved as-is since the correct
- corresponding values are obtained by the index.
- */
- private static final int[] BAR_TYPE_MAP = {
- InsetsState.ITYPE_STATUS_BAR,
- InsetsState.ITYPE_NAVIGATION_BAR,
- InsetsState.ITYPE_CLIMATE_BAR,
- InsetsState.ITYPE_EXTRA_NAVIGATION_BAR
- };
-
- private static final Map<@SystemBarSide Integer, Integer> BAR_GRAVITY_MAP = new ArrayMap<>();
- private static final Map<@SystemBarSide Integer, String> BAR_TITLE_MAP = new ArrayMap<>();
- private static final Map<@SystemBarSide Integer, Integer> BAR_GESTURE_MAP = new ArrayMap<>();
-
- private final Resources mResources;
- private final Map<@SystemBarSide Integer, SystemBarConfig> mSystemBarConfigMap =
- new ArrayMap<>();
- private final List<@SystemBarSide Integer> mSystemBarSidesByZOrder = new ArrayList<>();
-
- private boolean mTopNavBarEnabled;
- private boolean mBottomNavBarEnabled;
- private boolean mLeftNavBarEnabled;
- private boolean mRightNavBarEnabled;
-
- @Inject
- public SystemBarConfigs(@Main Resources resources) {
- mResources = resources;
-
- populateMaps();
- readConfigs();
-
- checkEnabledBarsHaveUniqueBarTypes();
- checkAllOverlappingBarsHaveDifferentZOrders();
- checkSystemBarEnabledForNotificationPanel();
- checkHideBottomBarForKeyboardConfigSync();
-
- setInsetPaddingsForOverlappingCorners();
- sortSystemBarSidesByZOrder();
- }
-
- protected WindowManager.LayoutParams getLayoutParamsBySide(@SystemBarSide int side) {
- return mSystemBarConfigMap.get(side) != null
- ? mSystemBarConfigMap.get(side).getLayoutParams() : null;
- }
-
- protected boolean getEnabledStatusBySide(@SystemBarSide int side) {
- switch (side) {
- case TOP:
- return mTopNavBarEnabled;
- case BOTTOM:
- return mBottomNavBarEnabled;
- case LEFT:
- return mLeftNavBarEnabled;
- case RIGHT:
- return mRightNavBarEnabled;
- default:
- return false;
- }
- }
-
- protected boolean getHideForKeyboardBySide(@SystemBarSide int side) {
- return mSystemBarConfigMap.get(side) != null
- && mSystemBarConfigMap.get(side).getHideForKeyboard();
- }
-
- protected void insetSystemBar(@SystemBarSide int side, CarNavigationBarView view) {
- if (mSystemBarConfigMap.get(side) == null) return;
-
- int[] paddings = mSystemBarConfigMap.get(side).getPaddings();
- view.setPadding(paddings[2], paddings[0], paddings[3], paddings[1]);
- }
-
- protected void setInsetUpdater(@SystemBarSide int side, CarNavigationBarView view) {
- view.setOnApplyWindowInsetsListener((v, insets) -> {
- updateInsetPaddings(side, getSystemBarsVisibility(insets));
- insetSystemBar(side, view);
- return insets;
- });
- }
-
- protected List<Integer> getSystemBarSidesByZOrder() {
- return mSystemBarSidesByZOrder;
- }
-
- @VisibleForTesting
- void updateInsetPaddings(@SystemBarSide int side,
- Map<@SystemBarSide Integer, Boolean> barVisibilities) {
- SystemBarConfig currentConfig = mSystemBarConfigMap.get(side);
-
- if (currentConfig == null) return;
-
- if (isHorizontalBar(side)) {
- if (mLeftNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
- LEFT).getZOrder()) {
- currentConfig.setPaddingBySide(LEFT,
- barVisibilities.get(LEFT) ? mSystemBarConfigMap.get(LEFT).getGirth() : 0);
- }
- if (mRightNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
- RIGHT).getZOrder()) {
- currentConfig.setPaddingBySide(RIGHT,
- barVisibilities.get(RIGHT) ? mSystemBarConfigMap.get(RIGHT).getGirth() : 0);
- }
- }
- if (isVerticalBar(side)) {
- if (mTopNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
- TOP).getZOrder()) {
- currentConfig.setPaddingBySide(TOP,
- barVisibilities.get(TOP) ? mSystemBarConfigMap.get(TOP).getGirth() : 0);
- }
- if (mBottomNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
- BOTTOM).getZOrder()) {
- currentConfig.setPaddingBySide(BOTTOM,
- barVisibilities.get(BOTTOM) ? mSystemBarConfigMap.get(BOTTOM).getGirth()
- : 0);
- }
- }
- }
-
- @VisibleForTesting
- static int getHunZOrder() {
- return HUN_ZORDER;
- }
-
- private static void populateMaps() {
- BAR_GRAVITY_MAP.put(TOP, Gravity.TOP);
- BAR_GRAVITY_MAP.put(BOTTOM, Gravity.BOTTOM);
- BAR_GRAVITY_MAP.put(LEFT, Gravity.LEFT);
- BAR_GRAVITY_MAP.put(RIGHT, Gravity.RIGHT);
-
- BAR_TITLE_MAP.put(TOP, "TopCarSystemBar");
- BAR_TITLE_MAP.put(BOTTOM, "BottomCarSystemBar");
- BAR_TITLE_MAP.put(LEFT, "LeftCarSystemBar");
- BAR_TITLE_MAP.put(RIGHT, "RightCarSystemBar");
-
- BAR_GESTURE_MAP.put(TOP, InsetsState.ITYPE_TOP_MANDATORY_GESTURES);
- BAR_GESTURE_MAP.put(BOTTOM, InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES);
- BAR_GESTURE_MAP.put(LEFT, InsetsState.ITYPE_LEFT_MANDATORY_GESTURES);
- BAR_GESTURE_MAP.put(RIGHT, InsetsState.ITYPE_RIGHT_MANDATORY_GESTURES);
- }
-
- private void readConfigs() {
- mTopNavBarEnabled = mResources.getBoolean(R.bool.config_enableTopNavigationBar);
- mBottomNavBarEnabled = mResources.getBoolean(R.bool.config_enableBottomNavigationBar);
- mLeftNavBarEnabled = mResources.getBoolean(R.bool.config_enableLeftNavigationBar);
- mRightNavBarEnabled = mResources.getBoolean(R.bool.config_enableRightNavigationBar);
-
- if (mTopNavBarEnabled) {
- SystemBarConfig topBarConfig =
- new SystemBarConfigBuilder()
- .setSide(TOP)
- .setGirth(mResources.getDimensionPixelSize(
- R.dimen.car_top_navigation_bar_height))
- .setBarType(mResources.getInteger(R.integer.config_topSystemBarType))
- .setZOrder(mResources.getInteger(R.integer.config_topSystemBarZOrder))
- .setHideForKeyboard(mResources.getBoolean(
- R.bool.config_hideTopSystemBarForKeyboard))
- .build();
- mSystemBarConfigMap.put(TOP, topBarConfig);
- }
-
- if (mBottomNavBarEnabled) {
- SystemBarConfig bottomBarConfig =
- new SystemBarConfigBuilder()
- .setSide(BOTTOM)
- .setGirth(mResources.getDimensionPixelSize(
- R.dimen.car_bottom_navigation_bar_height))
- .setBarType(mResources.getInteger(R.integer.config_bottomSystemBarType))
- .setZOrder(
- mResources.getInteger(R.integer.config_bottomSystemBarZOrder))
- .setHideForKeyboard(mResources.getBoolean(
- R.bool.config_hideBottomSystemBarForKeyboard))
- .build();
- mSystemBarConfigMap.put(BOTTOM, bottomBarConfig);
- }
-
- if (mLeftNavBarEnabled) {
- SystemBarConfig leftBarConfig =
- new SystemBarConfigBuilder()
- .setSide(LEFT)
- .setGirth(mResources.getDimensionPixelSize(
- R.dimen.car_left_navigation_bar_width))
- .setBarType(mResources.getInteger(R.integer.config_leftSystemBarType))
- .setZOrder(mResources.getInteger(R.integer.config_leftSystemBarZOrder))
- .setHideForKeyboard(mResources.getBoolean(
- R.bool.config_hideLeftSystemBarForKeyboard))
- .build();
- mSystemBarConfigMap.put(LEFT, leftBarConfig);
- }
-
- if (mRightNavBarEnabled) {
- SystemBarConfig rightBarConfig =
- new SystemBarConfigBuilder()
- .setSide(RIGHT)
- .setGirth(mResources.getDimensionPixelSize(
- R.dimen.car_right_navigation_bar_width))
- .setBarType(mResources.getInteger(R.integer.config_rightSystemBarType))
- .setZOrder(mResources.getInteger(R.integer.config_rightSystemBarZOrder))
- .setHideForKeyboard(mResources.getBoolean(
- R.bool.config_hideRightSystemBarForKeyboard))
- .build();
- mSystemBarConfigMap.put(RIGHT, rightBarConfig);
- }
- }
-
- private void checkEnabledBarsHaveUniqueBarTypes() throws RuntimeException {
- Set<Integer> barTypesUsed = new ArraySet<>();
- int enabledNavBarCount = mSystemBarConfigMap.size();
-
- for (SystemBarConfig systemBarConfig : mSystemBarConfigMap.values()) {
- barTypesUsed.add(systemBarConfig.getBarType());
- }
-
- // The number of bar types used cannot be fewer than that of enabled system bars.
- if (barTypesUsed.size() < enabledNavBarCount) {
- throw new RuntimeException("Each enabled system bar must have a unique bar type. Check "
- + "the configuration in config.xml");
- }
- }
-
- private void checkAllOverlappingBarsHaveDifferentZOrders() {
- checkOverlappingBarsHaveDifferentZOrders(TOP, LEFT);
- checkOverlappingBarsHaveDifferentZOrders(TOP, RIGHT);
- checkOverlappingBarsHaveDifferentZOrders(BOTTOM, LEFT);
- checkOverlappingBarsHaveDifferentZOrders(BOTTOM, RIGHT);
- }
-
- private void checkSystemBarEnabledForNotificationPanel() throws RuntimeException {
- String notificationPanelMediatorName =
- mResources.getString(R.string.config_notificationPanelViewMediator);
- if (notificationPanelMediatorName == null) {
- return;
- }
-
- Class<?> notificationPanelMediatorUsed = null;
- try {
- notificationPanelMediatorUsed = Class.forName(notificationPanelMediatorName);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
-
- if (!mTopNavBarEnabled && TopNotificationPanelViewMediator.class.isAssignableFrom(
- notificationPanelMediatorUsed)) {
- throw new RuntimeException(
- "Top System Bar must be enabled to use " + notificationPanelMediatorName);
- }
-
- if (!mBottomNavBarEnabled && BottomNotificationPanelViewMediator.class.isAssignableFrom(
- notificationPanelMediatorUsed)) {
- throw new RuntimeException("Bottom System Bar must be enabled to use "
- + notificationPanelMediatorName);
- }
- }
-
- private void checkHideBottomBarForKeyboardConfigSync() throws RuntimeException {
- if (mBottomNavBarEnabled) {
- boolean actual = mResources.getBoolean(R.bool.config_hideBottomSystemBarForKeyboard);
- boolean expected = mResources.getBoolean(
- com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard);
-
- if (actual != expected) {
- throw new RuntimeException("config_hideBottomSystemBarForKeyboard must not be "
- + "overlaid directly and should always refer to"
- + "config_automotiveHideNavBarForKeyboard. However, their values "
- + "currently do not sync. Set config_hideBottomSystemBarForKeyguard to "
- + "@*android:bool/config_automotiveHideNavBarForKeyboard. To change its "
- + "value, overlay config_automotiveHideNavBarForKeyboard in "
- + "framework/base/core/res/res.");
- }
- }
- }
-
- private void setInsetPaddingsForOverlappingCorners() {
- Map<@SystemBarSide Integer, Boolean> systemBarVisibilityOnInit =
- getSystemBarsVisibilityOnInit();
- updateInsetPaddings(TOP, systemBarVisibilityOnInit);
- updateInsetPaddings(BOTTOM, systemBarVisibilityOnInit);
- updateInsetPaddings(LEFT, systemBarVisibilityOnInit);
- updateInsetPaddings(RIGHT, systemBarVisibilityOnInit);
- }
-
- private void sortSystemBarSidesByZOrder() {
- List<SystemBarConfig> systemBarsByZOrder = new ArrayList<>(mSystemBarConfigMap.values());
-
- systemBarsByZOrder.sort(new Comparator<SystemBarConfig>() {
- @Override
- public int compare(SystemBarConfig o1, SystemBarConfig o2) {
- return o1.getZOrder() - o2.getZOrder();
- }
- });
-
- systemBarsByZOrder.forEach(systemBarConfig -> {
- mSystemBarSidesByZOrder.add(systemBarConfig.getSide());
- });
- }
-
- @InsetsState.InternalInsetsType
- private int getSystemBarTypeBySide(@SystemBarSide int side) {
- return mSystemBarConfigMap.get(side) != null
- ? mSystemBarConfigMap.get(side).getBarType() : null;
- }
-
- // On init, system bars are visible as long as they are enabled.
- private Map<@SystemBarSide Integer, Boolean> getSystemBarsVisibilityOnInit() {
- ArrayMap<@SystemBarSide Integer, Boolean> visibilityMap = new ArrayMap<>();
- visibilityMap.put(TOP, mTopNavBarEnabled);
- visibilityMap.put(BOTTOM, mBottomNavBarEnabled);
- visibilityMap.put(LEFT, mLeftNavBarEnabled);
- visibilityMap.put(RIGHT, mRightNavBarEnabled);
- return visibilityMap;
- }
-
- private Map<@SystemBarSide Integer, Boolean> getSystemBarsVisibility(WindowInsets insets) {
- ArrayMap<@SystemBarSide Integer, Boolean> visibilityMap = new ArrayMap<>();
- if (mTopNavBarEnabled) {
- visibilityMap.put(TOP, getSystemBarInsetVisibleBySide(TOP, insets));
- }
- if (mBottomNavBarEnabled) {
- visibilityMap.put(BOTTOM, getSystemBarInsetVisibleBySide(BOTTOM, insets));
- }
- if (mLeftNavBarEnabled) {
- visibilityMap.put(LEFT, getSystemBarInsetVisibleBySide(LEFT, insets));
- }
- if (mRightNavBarEnabled) {
- visibilityMap.put(RIGHT, getSystemBarInsetVisibleBySide(RIGHT, insets));
- }
- return visibilityMap;
- }
-
- private boolean getSystemBarInsetVisibleBySide(@SystemBarSide int side, WindowInsets insets) {
- if (mSystemBarConfigMap.get(side) == null) return false;
-
- int internalInsetType = BAR_TYPE_MAP[getSystemBarTypeBySide(side)];
- int publicInsetType = InsetsState.toPublicType(internalInsetType);
-
- return insets.isVisible(publicInsetType);
- }
-
- private void checkOverlappingBarsHaveDifferentZOrders(@SystemBarSide int horizontalSide,
- @SystemBarSide int verticalSide) {
-
- if (isVerticalBar(horizontalSide) || isHorizontalBar(verticalSide)) {
- Log.w(TAG, "configureBarPaddings: Returning immediately since the horizontal and "
- + "vertical sides were not provided correctly.");
- return;
- }
-
- SystemBarConfig horizontalBarConfig = mSystemBarConfigMap.get(horizontalSide);
- SystemBarConfig verticalBarConfig = mSystemBarConfigMap.get(verticalSide);
-
- if (verticalBarConfig != null && horizontalBarConfig != null) {
- int horizontalBarZOrder = horizontalBarConfig.getZOrder();
- int verticalBarZOrder = verticalBarConfig.getZOrder();
-
- if (horizontalBarZOrder == verticalBarZOrder) {
- throw new RuntimeException(
- BAR_TITLE_MAP.get(horizontalSide) + " " + BAR_TITLE_MAP.get(verticalSide)
- + " have the same Z-Order, and so their placing order cannot be "
- + "determined. Determine which bar should be placed on top of the "
- + "other bar and change the Z-order in config.xml accordingly."
- );
- }
- }
- }
-
- private static boolean isHorizontalBar(@SystemBarSide int side) {
- return side == TOP || side == BOTTOM;
- }
-
- private static boolean isVerticalBar(@SystemBarSide int side) {
- return side == LEFT || side == RIGHT;
- }
-
- private static final class SystemBarConfig {
- private final int mSide;
- private final int mBarType;
- private final int mGirth;
- private final int mZOrder;
- private final boolean mHideForKeyboard;
-
- private int[] mPaddings = new int[]{0, 0, 0, 0};
-
- private SystemBarConfig(@SystemBarSide int side, int barType, int girth, int zOrder,
- boolean hideForKeyboard) {
- mSide = side;
- mBarType = barType;
- mGirth = girth;
- mZOrder = zOrder;
- mHideForKeyboard = hideForKeyboard;
- }
-
- private int getSide() {
- return mSide;
- }
-
- private int getBarType() {
- return mBarType;
- }
-
- private int getGirth() {
- return mGirth;
- }
-
- private int getZOrder() {
- return mZOrder;
- }
-
- private boolean getHideForKeyboard() {
- return mHideForKeyboard;
- }
-
- private int[] getPaddings() {
- return mPaddings;
- }
-
- private WindowManager.LayoutParams getLayoutParams() {
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- isHorizontalBar(mSide) ? ViewGroup.LayoutParams.MATCH_PARENT : mGirth,
- isHorizontalBar(mSide) ? mGirth : ViewGroup.LayoutParams.MATCH_PARENT,
- mapZOrderToBarType(mZOrder),
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- lp.setTitle(BAR_TITLE_MAP.get(mSide));
- lp.providesInsetsTypes = new int[]{BAR_TYPE_MAP[mBarType], BAR_GESTURE_MAP.get(mSide)};
- lp.setFitInsetsTypes(0);
- lp.windowAnimations = 0;
- lp.gravity = BAR_GRAVITY_MAP.get(mSide);
- return lp;
- }
-
- private int mapZOrderToBarType(int zOrder) {
- return zOrder >= HUN_ZORDER ? WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL
- : WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
- }
-
- private void setPaddingBySide(@SystemBarSide int side, int padding) {
- mPaddings[side] = padding;
- }
- }
-
- private static final class SystemBarConfigBuilder {
- private int mSide;
- private int mBarType;
- private int mGirth;
- private int mZOrder;
- private boolean mHideForKeyboard;
-
- private SystemBarConfigBuilder setSide(@SystemBarSide int side) {
- mSide = side;
- return this;
- }
-
- private SystemBarConfigBuilder setBarType(int type) {
- mBarType = type;
- return this;
- }
-
- private SystemBarConfigBuilder setGirth(int girth) {
- mGirth = girth;
- return this;
- }
-
- private SystemBarConfigBuilder setZOrder(int zOrder) {
- mZOrder = zOrder;
- return this;
- }
-
- private SystemBarConfigBuilder setHideForKeyboard(boolean hide) {
- mHideForKeyboard = hide;
- return this;
- }
-
- private SystemBarConfig build() {
- return new SystemBarConfig(mSide, mBarType, mGirth, mZOrder, mHideForKeyboard);
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/BottomNotificationPanelViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/BottomNotificationPanelViewMediator.java
deleted file mode 100644
index 8468bef1750c..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/BottomNotificationPanelViewMediator.java
+++ /dev/null
@@ -1,62 +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.car.notification;
-
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.navigationbar.CarNavigationBarController;
-import com.android.systemui.car.window.OverlayPanelViewController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-
-import javax.inject.Inject;
-
-/**
- * Implementation of NotificationPanelViewMediator that sets the notification panel to be opened
- * from the top navigation bar.
- */
-@SysUISingleton
-public class BottomNotificationPanelViewMediator extends NotificationPanelViewMediator {
-
- @Inject
- public BottomNotificationPanelViewMediator(
- CarNavigationBarController carNavigationBarController,
- NotificationPanelViewController notificationPanelViewController,
-
- PowerManagerHelper powerManagerHelper,
- BroadcastDispatcher broadcastDispatcher,
-
- CarDeviceProvisionedController carDeviceProvisionedController,
- ConfigurationController configurationController
- ) {
- super(carNavigationBarController,
- notificationPanelViewController,
- powerManagerHelper,
- broadcastDispatcher,
- carDeviceProvisionedController,
- configurationController);
- notificationPanelViewController.setOverlayDirection(
- OverlayPanelViewController.OVERLAY_FROM_BOTTOM_BAR);
- }
-
- @Override
- public void registerListeners() {
- super.registerListeners();
- getCarNavigationBarController().registerBottomBarTouchListener(
- getNotificationPanelViewController().getDragOpenTouchListener());
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
deleted file mode 100644
index 3b22a30857a9..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
+++ /dev/null
@@ -1,110 +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.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 com.android.car.notification.R;
-import com.android.car.notification.headsup.CarHeadsUpNotificationContainer;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.window.OverlayViewGlobalStateController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-
-import javax.inject.Inject;
-
-/**
- * A controller for SysUI's HUN display.
- */
-@SysUISingleton
-public class CarHeadsUpNotificationSystemContainer implements CarHeadsUpNotificationContainer {
- private final CarDeviceProvisionedController mCarDeviceProvisionedController;
- private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
-
- private final ViewGroup mWindow;
- private final ViewGroup mHeadsUpContentFrame;
-
- @Inject
- CarHeadsUpNotificationSystemContainer(Context context,
- @Main Resources resources,
- CarDeviceProvisionedController deviceProvisionedController,
- WindowManager windowManager,
- OverlayViewGlobalStateController overlayViewGlobalStateController) {
- mCarDeviceProvisionedController = deviceProvisionedController;
- mOverlayViewGlobalStateController = overlayViewGlobalStateController;
-
- boolean showOnBottom = resources.getBoolean(R.bool.config_showHeadsUpNotificationOnBottom);
-
- // Use TYPE_STATUS_BAR_SUB_PANEL window type since we need to find a window that is above
- // status bar but below navigation bar.
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
- PixelFormat.TRANSLUCENT);
-
- lp.gravity = showOnBottom ? Gravity.BOTTOM : Gravity.TOP;
- lp.setTitle("HeadsUpNotification");
-
- int layoutId = showOnBottom
- ? R.layout.headsup_container_bottom
- : R.layout.headsup_container;
- mWindow = (ViewGroup) LayoutInflater.from(context).inflate(layoutId, null, false);
- windowManager.addView(mWindow, lp);
- mWindow.setVisibility(View.INVISIBLE);
- mHeadsUpContentFrame = mWindow.findViewById(R.id.headsup_content);
- }
-
- private void animateShow() {
- if (mCarDeviceProvisionedController.isCurrentUserFullySetup()
- && mOverlayViewGlobalStateController.shouldShowHUN()) {
- 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;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarNotificationModule.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarNotificationModule.java
deleted file mode 100644
index 8a3bcfc5ef3a..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarNotificationModule.java
+++ /dev/null
@@ -1,83 +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.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 com.android.systemui.dagger.SysUISingleton;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-
-/**
- * Module for Car SysUI Notifications
- */
-@Module
-public abstract class CarNotificationModule {
- @Provides
- @SysUISingleton
- static NotificationClickHandlerFactory provideNotificationClickHandlerFactory(
- IStatusBarService barService) {
- return new NotificationClickHandlerFactory(barService);
- }
-
- @Provides
- @SysUISingleton
- static NotificationDataManager provideNotificationDataManager() {
- return new NotificationDataManager();
- }
-
- @Provides
- @SysUISingleton
- static CarUxRestrictionManagerWrapper provideCarUxRestrictionManagerWrapper() {
- return new CarUxRestrictionManagerWrapper();
- }
-
- @Provides
- @SysUISingleton
- static CarNotificationListener provideCarNotificationListener(Context context,
- CarUxRestrictionManagerWrapper carUxRestrictionManagerWrapper,
- CarHeadsUpNotificationManager carHeadsUpNotificationManager,
- NotificationDataManager notificationDataManager) {
- CarNotificationListener listener = new CarNotificationListener();
- listener.registerAsSystemService(context, carUxRestrictionManagerWrapper,
- carHeadsUpNotificationManager, notificationDataManager);
- return listener;
- }
-
- @Provides
- @SysUISingleton
- 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/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
deleted file mode 100644
index 599e69cb6ab4..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
+++ /dev/null
@@ -1,602 +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.car.notification;
-
-import android.app.ActivityManager;
-import android.car.Car;
-import android.car.drivingstate.CarUxRestrictionsManager;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.inputmethodservice.InputMethodService;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.car.notification.CarNotificationListener;
-import com.android.car.notification.CarNotificationView;
-import com.android.car.notification.CarUxRestrictionManagerWrapper;
-import com.android.car.notification.NotificationClickHandlerFactory;
-import com.android.car.notification.NotificationDataManager;
-import com.android.car.notification.NotificationViewController;
-import com.android.car.notification.PreprocessingManager;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.R;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.window.OverlayPanelViewController;
-import com.android.systemui.car.window.OverlayViewController;
-import com.android.systemui.car.window.OverlayViewGlobalStateController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.wm.shell.animation.FlingAnimationUtils;
-
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-
-/** View controller for the notification panel. */
-@SysUISingleton
-public class NotificationPanelViewController extends OverlayPanelViewController
- implements CommandQueue.Callbacks {
-
- private static final boolean DEBUG = true;
- private static final String TAG = "NotificationPanelViewController";
-
- private final Context mContext;
- private final Resources mResources;
- private final CarServiceProvider mCarServiceProvider;
- private final IStatusBarService mBarService;
- private final CommandQueue mCommandQueue;
- private final Executor mUiBgExecutor;
- private final NotificationDataManager mNotificationDataManager;
- private final CarUxRestrictionManagerWrapper mCarUxRestrictionManagerWrapper;
- private final CarNotificationListener mCarNotificationListener;
- private final NotificationClickHandlerFactory mNotificationClickHandlerFactory;
- private final StatusBarStateController mStatusBarStateController;
- private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
- private final NotificationVisibilityLogger mNotificationVisibilityLogger;
-
- private final boolean mFitTopSystemBarInset;
- private final boolean mFitBottomSystemBarInset;
- private final boolean mFitLeftSystemBarInset;
- private final boolean mFitRightSystemBarInset;
-
- private float mInitialBackgroundAlpha;
- private float mBackgroundAlphaDiff;
-
- private CarNotificationView mNotificationView;
- private View mHandleBar;
- private RecyclerView mNotificationList;
- private NotificationViewController mNotificationViewController;
-
- private boolean mNotificationListAtEnd;
- private float mFirstTouchDownOnGlassPane;
- private boolean mNotificationListAtEndAtTimeOfTouch;
- private boolean mIsSwipingVerticallyToClose;
- private boolean mIsNotificationCardSwiping;
- private boolean mImeVisible = false;
-
- private OnUnseenCountUpdateListener mUnseenCountUpdateListener;
-
- @Inject
- public NotificationPanelViewController(
- Context context,
- @Main Resources resources,
- OverlayViewGlobalStateController overlayViewGlobalStateController,
- FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
- @UiBackground Executor uiBgExecutor,
-
- /* Other things */
- CarServiceProvider carServiceProvider,
- CarDeviceProvisionedController carDeviceProvisionedController,
-
- /* Things needed for notifications */
- IStatusBarService barService,
- CommandQueue commandQueue,
- NotificationDataManager notificationDataManager,
- CarUxRestrictionManagerWrapper carUxRestrictionManagerWrapper,
- CarNotificationListener carNotificationListener,
- NotificationClickHandlerFactory notificationClickHandlerFactory,
- NotificationVisibilityLogger notificationVisibilityLogger,
-
- /* Things that need to be replaced */
- StatusBarStateController statusBarStateController
- ) {
- super(context, resources, R.id.notification_panel_stub, overlayViewGlobalStateController,
- flingAnimationUtilsBuilder, carDeviceProvisionedController);
- mContext = context;
- mResources = resources;
- mCarServiceProvider = carServiceProvider;
- mBarService = barService;
- mCommandQueue = commandQueue;
- mUiBgExecutor = uiBgExecutor;
- mNotificationDataManager = notificationDataManager;
- mCarUxRestrictionManagerWrapper = carUxRestrictionManagerWrapper;
- mCarNotificationListener = carNotificationListener;
- mNotificationClickHandlerFactory = notificationClickHandlerFactory;
- mStatusBarStateController = statusBarStateController;
- mNotificationVisibilityLogger = notificationVisibilityLogger;
-
- mCommandQueue.addCallback(this);
-
- // Notification background setup.
- mInitialBackgroundAlpha = (float) mResources.getInteger(
- R.integer.config_initialNotificationBackgroundAlpha) / 100;
- if (mInitialBackgroundAlpha < 0 || mInitialBackgroundAlpha > 100) {
- throw new RuntimeException(
- "Unable to setup notification bar due to incorrect initial background alpha"
- + " percentage");
- }
- float finalBackgroundAlpha = Math.max(
- mInitialBackgroundAlpha,
- (float) mResources.getInteger(
- R.integer.config_finalNotificationBackgroundAlpha) / 100);
- if (finalBackgroundAlpha < 0 || finalBackgroundAlpha > 100) {
- throw new RuntimeException(
- "Unable to setup notification bar due to incorrect final background alpha"
- + " percentage");
- }
- mBackgroundAlphaDiff = finalBackgroundAlpha - mInitialBackgroundAlpha;
-
- mEnableHeadsUpNotificationWhenNotificationShadeOpen = mResources.getBoolean(
- com.android.car.notification.R.bool
- .config_enableHeadsUpNotificationWhenNotificationShadeOpen);
-
- mFitTopSystemBarInset = mResources.getBoolean(
- R.bool.config_notif_panel_inset_by_top_systembar);
- mFitBottomSystemBarInset = mResources.getBoolean(
- R.bool.config_notif_panel_inset_by_bottom_systembar);
- mFitLeftSystemBarInset = mResources.getBoolean(
- R.bool.config_notif_panel_inset_by_left_systembar);
- mFitRightSystemBarInset = mResources.getBoolean(
- R.bool.config_notif_panel_inset_by_right_systembar);
- }
-
- // CommandQueue.Callbacks
-
- @Override
- public void animateExpandNotificationsPanel() {
- if (!isPanelExpanded()) {
- toggle();
- }
- }
-
- @Override
- public void animateCollapsePanels(int flags, boolean force) {
- if (isPanelExpanded()) {
- toggle();
- }
- }
-
- @Override
- public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
- boolean showImeSwitcher) {
- if (mContext.getDisplayId() != displayId) {
- return;
- }
- mImeVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
- }
-
- // OverlayViewController
-
- @Override
- protected void onFinishInflate() {
- reinflate();
- }
-
- @Override
- protected void hideInternal() {
- super.hideInternal();
- mNotificationVisibilityLogger.stop();
- }
-
- @Override
- protected boolean shouldShowNavigationBarInsets() {
- return true;
- }
-
- @Override
- protected boolean shouldShowStatusBarInsets() {
- return true;
- }
-
- @Override
- protected int getInsetSidesToFit() {
- int insetSidesToFit = OverlayViewController.NO_INSET_SIDE;
-
- if (mFitTopSystemBarInset) {
- insetSidesToFit = insetSidesToFit | WindowInsets.Side.TOP;
- }
-
- if (mFitBottomSystemBarInset) {
- insetSidesToFit = insetSidesToFit | WindowInsets.Side.BOTTOM;
- }
-
- if (mFitLeftSystemBarInset) {
- insetSidesToFit = insetSidesToFit | WindowInsets.Side.LEFT;
- }
-
- if (mFitRightSystemBarInset) {
- insetSidesToFit = insetSidesToFit | WindowInsets.Side.RIGHT;
- }
-
- return insetSidesToFit;
- }
-
- @Override
- protected boolean shouldShowHUN() {
- return mEnableHeadsUpNotificationWhenNotificationShadeOpen;
- }
-
- @Override
- protected boolean shouldUseStableInsets() {
- // When IME is visible, then the inset from the nav bar should not be applied.
- return !mImeVisible;
- }
-
- /** Reinflates the view. */
- public void reinflate() {
- ViewGroup container = (ViewGroup) getLayout();
- container.removeView(mNotificationView);
-
- mNotificationView = (CarNotificationView) LayoutInflater.from(mContext).inflate(
- R.layout.notification_center_activity, container,
- /* attachToRoot= */ false);
-
- container.addView(mNotificationView);
- onNotificationViewInflated();
- }
-
- private void onNotificationViewInflated() {
- // Find views.
- mNotificationView = getLayout().findViewById(R.id.notification_view);
- setupHandleBar();
- setupNotificationPanel();
-
- mNotificationClickHandlerFactory.registerClickListener((launchResult, alertEntry) -> {
- if (launchResult == ActivityManager.START_TASK_TO_FRONT
- || launchResult == ActivityManager.START_SUCCESS) {
- animateCollapsePanel();
- }
- });
-
- mNotificationDataManager.setOnUnseenCountUpdateListener(() -> {
- if (mUnseenCountUpdateListener != null) {
- mUnseenCountUpdateListener.onUnseenCountUpdate(
- mNotificationDataManager.getUnseenNotificationCount());
- }
- mCarNotificationListener.setNotificationsShown(
- mNotificationDataManager.getSeenNotifications());
- // This logs both when the notification panel is expanded and when the notification
- // panel is scrolled.
- mNotificationVisibilityLogger.log(isPanelExpanded());
- });
-
- mNotificationClickHandlerFactory.setNotificationDataManager(mNotificationDataManager);
- mNotificationView.setClickHandlerFactory(mNotificationClickHandlerFactory);
- mNotificationView.setNotificationDataManager(mNotificationDataManager);
-
- mCarServiceProvider.addListener(car -> {
- CarUxRestrictionsManager carUxRestrictionsManager =
- (CarUxRestrictionsManager)
- car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
- mCarUxRestrictionManagerWrapper.setCarUxRestrictionsManager(
- carUxRestrictionsManager);
-
- mNotificationViewController = new NotificationViewController(
- mNotificationView,
- PreprocessingManager.getInstance(mContext),
- mCarNotificationListener,
- mCarUxRestrictionManagerWrapper,
- mNotificationDataManager);
- mNotificationViewController.enable();
- });
- }
-
- private void setupHandleBar() {
- mHandleBar = mNotificationView.findViewById(R.id.handle_bar);
- GestureDetector handleBarCloseNotificationGestureDetector = new GestureDetector(mContext,
- new HandleBarCloseGestureListener());
- mHandleBar.setOnTouchListener((v, event) -> {
- handleBarCloseNotificationGestureDetector.onTouchEvent(event);
- maybeCompleteAnimation(event);
- return true;
- });
- }
-
- private void setupNotificationPanel() {
- View glassPane = mNotificationView.findViewById(R.id.glass_pane);
- mNotificationList = mNotificationView.findViewById(R.id.notifications);
- GestureDetector closeGestureDetector = new GestureDetector(mContext,
- new CloseGestureListener() {
- @Override
- protected void close() {
- if (isPanelExpanded()) {
- animateCollapsePanel();
- }
- }
- });
-
- // The glass pane is used to view touch events before passed to the notification list.
- // This allows us to initialize gesture listeners and detect when to close the notifications
- glassPane.setOnTouchListener((v, event) -> {
- if (isClosingAction(event)) {
- mNotificationListAtEndAtTimeOfTouch = false;
- }
- if (isOpeningAction(event)) {
- mFirstTouchDownOnGlassPane = event.getRawX();
- mNotificationListAtEndAtTimeOfTouch = mNotificationListAtEnd;
- // Reset the tracker when there is a touch down on the glass pane.
- setIsTracking(false);
- // Pass the down event to gesture detector so that it knows where the touch event
- // started.
- closeGestureDetector.onTouchEvent(event);
- }
- return false;
- });
-
- mNotificationList.addOnScrollListener(new RecyclerView.OnScrollListener() {
- @Override
- public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
- super.onScrolled(recyclerView, dx, dy);
- // Check if we can scroll vertically in the animation direction.
- if (!mNotificationList.canScrollVertically(mAnimateDirection)) {
- mNotificationListAtEnd = true;
- return;
- }
- mNotificationListAtEnd = false;
- mIsSwipingVerticallyToClose = false;
- mNotificationListAtEndAtTimeOfTouch = false;
- }
- });
-
- mNotificationList.setOnTouchListener((v, event) -> {
- mIsNotificationCardSwiping = Math.abs(mFirstTouchDownOnGlassPane - event.getRawX())
- > SWIPE_MAX_OFF_PATH;
- if (mNotificationListAtEndAtTimeOfTouch && mNotificationListAtEnd) {
- // We need to save the state here as if notification card is swiping we will
- // change the mNotificationListAtEndAtTimeOfTouch. This is to protect
- // closing the notification shade while the notification card is being swiped.
- mIsSwipingVerticallyToClose = true;
- }
-
- // If the card is swiping we should not allow the notification shade to close.
- // Hence setting mNotificationListAtEndAtTimeOfTouch to false will stop that
- // for us. We are also checking for isTracking() because while swiping the
- // notification shade to close if the user goes a bit horizontal while swiping
- // upwards then also this should close.
- if (mIsNotificationCardSwiping && !isTracking()) {
- mNotificationListAtEndAtTimeOfTouch = false;
- }
-
- boolean handled = closeGestureDetector.onTouchEvent(event);
- boolean isTracking = isTracking();
- Rect rect = getLayout().getClipBounds();
- float clippedHeight = 0;
- if (rect != null) {
- clippedHeight = rect.bottom;
- }
- if (!handled && isClosingAction(event) && mIsSwipingVerticallyToClose) {
- if (getSettleClosePercentage() < getPercentageFromEndingEdge() && isTracking) {
- animatePanel(DEFAULT_FLING_VELOCITY, false);
- } else if (clippedHeight != getLayout().getHeight() && isTracking) {
- // this can be caused when user is at the end of the list and trying to
- // fling to top of the list by scrolling down.
- animatePanel(DEFAULT_FLING_VELOCITY, true);
- }
- }
-
- // Updating the mNotificationListAtEndAtTimeOfTouch state has to be done after
- // the event has been passed to the closeGestureDetector above, such that the
- // closeGestureDetector sees the up event before the state has changed.
- if (isClosingAction(event)) {
- mNotificationListAtEndAtTimeOfTouch = false;
- }
- return handled || isTracking;
- });
- }
-
- /** Called when the car power state is changed to ON. */
- public void onCarPowerStateOn() {
- if (mNotificationClickHandlerFactory != null) {
- mNotificationClickHandlerFactory.clearAllNotifications();
- }
- mNotificationDataManager.clearAll();
- }
-
- // OverlayPanelViewController
-
- @Override
- protected boolean shouldAnimateCollapsePanel() {
- return true;
- }
-
- @Override
- protected void onAnimateCollapsePanel() {
- // No op.
- }
-
- @Override
- protected boolean shouldAnimateExpandPanel() {
- return mCommandQueue.panelsEnabled();
- }
-
- @Override
- protected void onAnimateExpandPanel() {
- mNotificationList.scrollToPosition(0);
- }
-
- @Override
- protected void onCollapseAnimationEnd() {
- mNotificationViewController.onVisibilityChanged(false);
- }
-
- @Override
- protected void onExpandAnimationEnd() {
- mNotificationViewController.onVisibilityChanged(true);
- mNotificationView.setVisibleNotificationsAsSeen();
- }
-
- @Override
- protected void onPanelVisible(boolean visible) {
- super.onPanelVisible(visible);
- mUiBgExecutor.execute(() -> {
- try {
- if (visible) {
- // When notification panel is open even just a bit, we want to clear
- // notification effects.
- boolean clearNotificationEffects =
- mStatusBarStateController.getState() != StatusBarState.KEYGUARD;
- mBarService.onPanelRevealed(clearNotificationEffects,
- mNotificationDataManager.getVisibleNotifications().size());
- } else {
- mBarService.onPanelHidden();
- }
- } catch (RemoteException ex) {
- // Won't fail unless the world has ended.
- Log.e(TAG, String.format(
- "Unable to notify StatusBarService of panel visibility: %s", visible));
- }
- });
-
- }
-
- @Override
- protected void onPanelExpanded(boolean expand) {
- super.onPanelExpanded(expand);
-
- if (expand && mStatusBarStateController.getState() != StatusBarState.KEYGUARD) {
- if (DEBUG) {
- Log.v(TAG, "clearing notification effects from setExpandedHeight");
- }
- clearNotificationEffects();
- }
- if (!expand) {
- mNotificationVisibilityLogger.log(isPanelExpanded());
- }
- }
-
- /**
- * Clear Buzz/Beep/Blink.
- */
- private void clearNotificationEffects() {
- try {
- mBarService.clearNotificationEffects();
- } catch (RemoteException e) {
- // Won't fail unless the world has ended.
- }
- }
-
- @Override
- protected void onOpenScrollStart() {
- mNotificationList.scrollToPosition(0);
- }
-
- @Override
- protected void onScroll(int y) {
- if (mHandleBar != null) {
- ViewGroup.MarginLayoutParams lp =
- (ViewGroup.MarginLayoutParams) mHandleBar.getLayoutParams();
- // Adjust handlebar to new pointer position, and a little more depending on the
- // animate direction so the bar can be seen fully.
- if (mAnimateDirection > 0) {
- mHandleBar.setTranslationY(y - mHandleBar.getHeight() - lp.bottomMargin);
- } else {
- mHandleBar.setTranslationY(y + mHandleBar.getHeight() + lp.topMargin);
- }
- }
-
- if (mNotificationView.getHeight() > 0) {
- Drawable background = mNotificationView.getBackground().mutate();
- background.setAlpha((int) (getBackgroundAlpha(y) * 255));
- mNotificationView.setBackground(background);
- }
- }
-
- @Override
- protected boolean shouldAllowClosingScroll() {
- // Unless the notification list is at the end, the panel shouldn't be allowed to
- // collapse on scroll.
- return mNotificationListAtEndAtTimeOfTouch;
- }
-
- /**
- * Calculates the alpha value for the background based on how much of the notification
- * shade is visible to the user. When the notification shade is completely open then
- * alpha value will be 1.
- */
- private float getBackgroundAlpha(int y) {
- float fractionCovered =
- ((float) (mAnimateDirection > 0 ? y : mNotificationView.getHeight() - y))
- / mNotificationView.getHeight();
- return mInitialBackgroundAlpha + fractionCovered * mBackgroundAlphaDiff;
- }
-
- /** Sets the unseen count listener. */
- public void setOnUnseenCountUpdateListener(OnUnseenCountUpdateListener listener) {
- mUnseenCountUpdateListener = listener;
- }
-
- /** Listener that is updated when the number of unseen notifications changes. */
- public interface OnUnseenCountUpdateListener {
- /**
- * This method is automatically called whenever there is an update to the number of unseen
- * notifications. This method can be extended by OEMs to customize the desired logic.
- */
- void onUnseenCountUpdate(int unseenNotificationCount);
- }
-
- /**
- * To be installed on the handle bar.
- */
- private class HandleBarCloseGestureListener extends
- GestureDetector.SimpleOnGestureListener {
-
- @Override
- public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
- float distanceY) {
- calculatePercentageFromEndingEdge(event2.getRawY());
- // To prevent the jump in the clip bounds while closing the notification panel using
- // the handle bar we should calculate the height using the diff of event1 and event2.
- // This will help the notification shade to clip smoothly as the event2 value changes
- // as event1 value will be fixed.
- float diff = mAnimateDirection * (event1.getRawY() - event2.getRawY());
- float y = mAnimateDirection > 0
- ? getLayout().getHeight() - diff
- : diff;
- // Ensure the position is within the overlay panel.
- y = Math.max(0, Math.min(y, getLayout().getHeight()));
- setViewClipBounds((int) y);
- return true;
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java
deleted file mode 100644
index 17b6b74014e4..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java
+++ /dev/null
@@ -1,174 +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.car.notification;
-
-import android.car.hardware.power.CarPowerManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.os.UserHandle;
-import android.util.Log;
-
-import androidx.annotation.CallSuper;
-
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.navigationbar.CarNavigationBarController;
-import com.android.systemui.car.window.OverlayViewMediator;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-
-import javax.inject.Inject;
-
-/**
- * The view mediator which attaches the view controller to other elements of the system ui. Disables
- * drag open behavior of the notification panel from any navigation bar.
- */
-@SysUISingleton
-public class NotificationPanelViewMediator implements OverlayViewMediator,
- ConfigurationController.ConfigurationListener {
-
- private static final boolean DEBUG = false;
- private static final String TAG = "NotificationPanelVM";
-
- private final CarNavigationBarController mCarNavigationBarController;
- private final NotificationPanelViewController mNotificationPanelViewController;
- private final PowerManagerHelper mPowerManagerHelper;
- private final BroadcastDispatcher mBroadcastDispatcher;
- private final CarDeviceProvisionedController mCarDeviceProvisionedController;
- private final ConfigurationController mConfigurationController;
-
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) Log.v(TAG, "onReceive: " + intent);
- String action = intent.getAction();
- if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- if (mNotificationPanelViewController.isPanelExpanded()) {
- mNotificationPanelViewController.toggle();
- }
- }
- }
- };
-
- @Inject
- public NotificationPanelViewMediator(
- CarNavigationBarController carNavigationBarController,
- NotificationPanelViewController notificationPanelViewController,
-
- PowerManagerHelper powerManagerHelper,
- BroadcastDispatcher broadcastDispatcher,
-
- CarDeviceProvisionedController carDeviceProvisionedController,
- ConfigurationController configurationController
- ) {
- mCarNavigationBarController = carNavigationBarController;
- mNotificationPanelViewController = notificationPanelViewController;
- mPowerManagerHelper = powerManagerHelper;
- mBroadcastDispatcher = broadcastDispatcher;
- mCarDeviceProvisionedController = carDeviceProvisionedController;
- mConfigurationController = configurationController;
- }
-
- @Override
- @CallSuper
- public void registerListeners() {
- mCarNavigationBarController.registerTopBarTouchListener(
- mNotificationPanelViewController.getDragCloseTouchListener());
- mCarNavigationBarController.registerBottomBarTouchListener(
- mNotificationPanelViewController.getDragCloseTouchListener());
- mCarNavigationBarController.registerLeftBarTouchListener(
- mNotificationPanelViewController.getDragCloseTouchListener());
- mCarNavigationBarController.registerRightBarTouchListener(
- mNotificationPanelViewController.getDragCloseTouchListener());
-
- mCarNavigationBarController.registerNotificationController(
- new CarNavigationBarController.NotificationsShadeController() {
- @Override
- public void togglePanel() {
- mNotificationPanelViewController.toggle();
- }
-
- @Override
- public boolean isNotificationPanelOpen() {
- return mNotificationPanelViewController.isPanelExpanded();
- }
- });
-
- mBroadcastDispatcher.registerReceiver(mBroadcastReceiver,
- new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), null, UserHandle.ALL);
- }
-
- @Override
- public void setupOverlayContentViewControllers() {
- mNotificationPanelViewController.setOnUnseenCountUpdateListener(unseenNotificationCount -> {
- boolean hasUnseen = unseenNotificationCount > 0;
- mCarNavigationBarController.toggleAllNotificationsUnseenIndicator(
- mCarDeviceProvisionedController.isCurrentUserFullySetup(), hasUnseen);
- });
-
- mPowerManagerHelper.setCarPowerStateListener(state -> {
- if (state == CarPowerManager.CarPowerStateListener.ON) {
- mNotificationPanelViewController.onCarPowerStateOn();
- }
- });
- mPowerManagerHelper.connectToCarService();
-
- mConfigurationController.addCallback(this);
- }
-
- @Override
- public void onConfigChanged(Configuration newConfig) {
- // No op.
- }
-
- @Override
- public void onDensityOrFontScaleChanged() {
- registerListeners();
- }
-
- @Override
- public void onOverlayChanged() {
- // No op.
- }
-
- @Override
- public void onUiModeChanged() {
- // No op.
- }
-
- @Override
- public void onThemeChanged() {
- // No op.
- }
-
- @Override
- public void onLocaleListChanged() {
- mNotificationPanelViewController.reinflate();
- registerListeners();
- }
-
- protected final CarNavigationBarController getCarNavigationBarController() {
- return mCarNavigationBarController;
- }
-
- protected final NotificationPanelViewController getNotificationPanelViewController() {
- return mNotificationPanelViewController;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationShadeWindowControllerImpl.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationShadeWindowControllerImpl.java
deleted file mode 100644
index 1a1da89f147a..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationShadeWindowControllerImpl.java
+++ /dev/null
@@ -1,46 +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.car.notification;
-
-import com.android.systemui.car.window.OverlayViewGlobalStateController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-
-import javax.inject.Inject;
-
-/** The automotive version of the notification shade window controller. */
-@SysUISingleton
-public class NotificationShadeWindowControllerImpl implements
- NotificationShadeWindowController {
-
- private final OverlayViewGlobalStateController mController;
-
- @Inject
- public NotificationShadeWindowControllerImpl(OverlayViewGlobalStateController controller) {
- mController = controller;
- }
-
- @Override
- public void setForceDozeBrightness(boolean forceDozeBrightness) {
- // No-op since dozing is not supported in Automotive devices.
- }
-
- @Override
- public void setNotificationShadeFocusable(boolean focusable) {
- mController.setWindowFocusable(focusable);
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationVisibilityLogger.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationVisibilityLogger.java
deleted file mode 100644
index b263f721d29a..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationVisibilityLogger.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 com.android.systemui.car.notification;
-
-import android.os.RemoteException;
-import android.util.ArraySet;
-import android.util.Log;
-
-import com.android.car.notification.AlertEntry;
-import com.android.car.notification.NotificationDataManager;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.UiBackground;
-
-import java.util.Set;
-import java.util.concurrent.Executor;
-
-import javax.inject.Inject;
-
-/**
- * Handles notification logging, in particular, logging which notifications are visible and which
- * are not.
- */
-@SysUISingleton
-public class NotificationVisibilityLogger {
-
- private static final String TAG = "NotificationVisibilityLogger";
-
- private final ArraySet<NotificationVisibility> mCurrentlyVisible = new ArraySet<>();
- private final ArraySet<NotificationVisibility> mNewlyVisible = new ArraySet<>();
- private final ArraySet<NotificationVisibility> mPreviouslyVisible = new ArraySet<>();
- private final ArraySet<NotificationVisibility> mTmpCurrentlyVisible = new ArraySet<>();
-
- private final IStatusBarService mBarService;
- private final Executor mUiBgExecutor;
- private final NotificationDataManager mNotificationDataManager;
-
- private boolean mIsVisible;
-
- private final Runnable mVisibilityReporter = new Runnable() {
-
- @Override
- public void run() {
- if (mIsVisible) {
- int count = mNotificationDataManager.getVisibleNotifications().size();
- for (AlertEntry alertEntry : mNotificationDataManager.getVisibleNotifications()) {
- NotificationVisibility visObj = NotificationVisibility.obtain(
- alertEntry.getKey(),
- /* rank= */ -1,
- count,
- mIsVisible,
- NotificationVisibility.NotificationLocation.LOCATION_MAIN_AREA);
- mTmpCurrentlyVisible.add(visObj);
- if (!mCurrentlyVisible.contains(visObj)) {
- mNewlyVisible.add(visObj);
- }
- }
- }
- mPreviouslyVisible.addAll(mCurrentlyVisible);
- mPreviouslyVisible.removeAll(mTmpCurrentlyVisible);
- onNotificationVisibilityChanged(mNewlyVisible, mPreviouslyVisible);
-
- recycleAllVisibilityObjects(mCurrentlyVisible);
- mCurrentlyVisible.addAll(mTmpCurrentlyVisible);
-
- recycleAllVisibilityObjects(mPreviouslyVisible);
- recycleAllVisibilityObjects(mNewlyVisible);
- recycleAllVisibilityObjects(mTmpCurrentlyVisible);
- }
- };
-
- @Inject
- public NotificationVisibilityLogger(
- @UiBackground Executor uiBgExecutor,
- IStatusBarService barService,
- NotificationDataManager notificationDataManager) {
- mUiBgExecutor = uiBgExecutor;
- mBarService = barService;
- mNotificationDataManager = notificationDataManager;
- }
-
- /** Triggers a visibility report update to be sent to StatusBarService. */
- public void log(boolean isVisible) {
- mIsVisible = isVisible;
- mUiBgExecutor.execute(mVisibilityReporter);
- }
-
- /** Stops logging, clearing all visibility objects. */
- public void stop() {
- recycleAllVisibilityObjects(mCurrentlyVisible);
- }
-
- /**
- * Notify StatusBarService of change in notifications' visibility.
- */
- private void onNotificationVisibilityChanged(
- Set<NotificationVisibility> newlyVisible, Set<NotificationVisibility> noLongerVisible) {
- if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
- return;
- }
-
- try {
- mBarService.onNotificationVisibilityChanged(
- cloneVisibilitiesAsArr(newlyVisible), cloneVisibilitiesAsArr(noLongerVisible));
- } catch (RemoteException e) {
- // Won't fail unless the world has ended.
- Log.e(TAG, "Failed to notify StatusBarService of notification visibility change");
- }
- }
-
- /**
- * Clears array and recycles NotificationVisibility objects for reuse.
- */
- private static void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
- for (int i = 0; i < array.size(); i++) {
- array.valueAt(i).recycle();
- }
- array.clear();
- }
-
- /**
- * Converts Set of NotificationVisibility objects to primitive array.
- */
- private static NotificationVisibility[] cloneVisibilitiesAsArr(Set<NotificationVisibility> c) {
- NotificationVisibility[] array = new NotificationVisibility[c.size()];
- int i = 0;
- for (NotificationVisibility nv : c) {
- if (nv != null) {
- array[i] = nv.clone();
- }
- i++;
- }
- return array;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/PowerManagerHelper.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/PowerManagerHelper.java
deleted file mode 100644
index da43c5487623..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/PowerManagerHelper.java
+++ /dev/null
@@ -1,71 +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.car.notification;
-
-import android.annotation.NonNull;
-import android.car.Car;
-import android.car.hardware.power.CarPowerManager;
-import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
-import android.util.Log;
-
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.dagger.SysUISingleton;
-
-import javax.inject.Inject;
-
-/**
- * Helper class for connecting to the {@link CarPowerManager} and listening for power state changes.
- */
-@SysUISingleton
-public class PowerManagerHelper {
- public static final String TAG = "PowerManagerHelper";
-
- private final CarServiceProvider mCarServiceProvider;
-
- private CarPowerManager mCarPowerManager;
- private CarPowerStateListener mCarPowerStateListener;
-
- private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener;
-
- @Inject
- public PowerManagerHelper(CarServiceProvider carServiceProvider) {
- mCarServiceProvider = carServiceProvider;
- mCarServiceLifecycleListener = car -> {
- Log.d(TAG, "Car Service connected");
- mCarPowerManager = (CarPowerManager) car.getCarManager(Car.POWER_SERVICE);
- if (mCarPowerManager != null) {
- mCarPowerManager.setListener(mCarPowerStateListener);
- } else {
- Log.e(TAG, "CarPowerManager service not available");
- }
- };
- }
-
- /**
- * Sets a {@link CarPowerStateListener}. Should be set before {@link #connectToCarService()}.
- */
- public void setCarPowerStateListener(@NonNull CarPowerStateListener listener) {
- mCarPowerStateListener = listener;
- }
-
- /**
- * Connect to Car service.
- */
- public void connectToCarService() {
- mCarServiceProvider.addListener(mCarServiceLifecycleListener);
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/TopNotificationPanelViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/TopNotificationPanelViewMediator.java
deleted file mode 100644
index 9bc5b74cda6c..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/TopNotificationPanelViewMediator.java
+++ /dev/null
@@ -1,62 +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.car.notification;
-
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.navigationbar.CarNavigationBarController;
-import com.android.systemui.car.window.OverlayPanelViewController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-
-import javax.inject.Inject;
-
-/**
- * Implementation of NotificationPanelViewMediator that sets the notification panel to be opened
- * from the top navigation bar.
- */
-@SysUISingleton
-public class TopNotificationPanelViewMediator extends NotificationPanelViewMediator {
-
- @Inject
- public TopNotificationPanelViewMediator(
- CarNavigationBarController carNavigationBarController,
- NotificationPanelViewController notificationPanelViewController,
-
- PowerManagerHelper powerManagerHelper,
- BroadcastDispatcher broadcastDispatcher,
-
- CarDeviceProvisionedController carDeviceProvisionedController,
- ConfigurationController configurationController
- ) {
- super(carNavigationBarController,
- notificationPanelViewController,
- powerManagerHelper,
- broadcastDispatcher,
- carDeviceProvisionedController,
- configurationController);
- notificationPanelViewController.setOverlayDirection(
- OverlayPanelViewController.OVERLAY_FROM_TOP_BAR);
- }
-
- @Override
- public void registerListeners() {
- super.registerListeners();
- getCarNavigationBarController().registerTopBarTouchListener(
- getNotificationPanelViewController().getDragOpenTouchListener());
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/rvc/RearViewCameraViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/rvc/RearViewCameraViewController.java
deleted file mode 100644
index d63463309ec5..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/rvc/RearViewCameraViewController.java
+++ /dev/null
@@ -1,141 +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.car.rvc;
-
-import android.app.ActivityView;
-import android.app.ActivityView.StateCallback;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.util.Slog;
-import android.view.ViewGroup;
-import android.widget.LinearLayout.LayoutParams;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
-import com.android.systemui.car.window.OverlayViewController;
-import com.android.systemui.car.window.OverlayViewGlobalStateController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-
-import javax.inject.Inject;
-
-/** View controller for the rear view camera. */
-@SysUISingleton
-public class RearViewCameraViewController extends OverlayViewController {
- private static final String TAG = "RearViewCameraView";
- private static final boolean DBG = false;
-
- private final ComponentName mRearViewCameraActivity;
- private ViewGroup mRvcView;
- private final LayoutParams mRvcViewLayoutParams = new LayoutParams(
- LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, /* weight= */ 1.0f);
- @VisibleForTesting
- ActivityView mActivityView;
- @VisibleForTesting
- final StateCallback mActivityViewCallback = new StateCallback() {
- @Override
- public void onActivityViewReady(ActivityView view) {
- Intent intent = new Intent(Intent.ACTION_MAIN)
- .setComponent(mRearViewCameraActivity)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
- .addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- // TODO(b/170899079): Migrate this to FixedActivityService.
- view.startActivity(intent);
- }
-
- @Override
- public void onActivityViewDestroyed(ActivityView view) {}
- };
-
- @Inject
- public RearViewCameraViewController(
- @Main Resources resources,
- OverlayViewGlobalStateController overlayViewGlobalStateController) {
- super(R.id.rear_view_camera_stub, overlayViewGlobalStateController);
- String rearViewCameraActivityName = resources.getString(
- R.string.config_rearViewCameraActivity);
- if (!rearViewCameraActivityName.isEmpty()) {
- mRearViewCameraActivity = ComponentName.unflattenFromString(rearViewCameraActivityName);
- if (DBG) Slog.d(TAG, "mRearViewCameraActivity=" + mRearViewCameraActivity);
- } else {
- mRearViewCameraActivity = null;
- Slog.e(TAG, "RearViewCameraViewController is disabled, since no Activity is defined");
- }
- }
-
- @Override
- protected void onFinishInflate() {
- mRvcView = (ViewGroup) getLayout().findViewById(R.id.rear_view_camera_container);
- getLayout().findViewById(R.id.close_button).setOnClickListener(v -> {
- stop();
- });
- }
-
- @Override
- protected void hideInternal() {
- super.hideInternal();
- if (DBG) Slog.d(TAG, "hideInternal: mActivityView=" + mActivityView);
- if (mActivityView == null) return;
- mRvcView.removeView(mActivityView);
- // Release ActivityView since the Activity on ActivityView (with showWhenLocked flag) keeps
- // running even if ActivityView is hidden.
- mActivityView.release();
- mActivityView = null;
- }
-
- @Override
- protected void showInternal() {
- super.showInternal();
- if (DBG) Slog.d(TAG, "showInternal: mActivityView=" + mActivityView);
- if (mActivityView != null) return;
- mActivityView = new ActivityView(mRvcView.getContext());
- mActivityView.setCallback(mActivityViewCallback);
- mActivityView.setLayoutParams(mRvcViewLayoutParams);
- mRvcView.addView(mActivityView, /* index= */ 0);
- }
-
- boolean isShown() {
- return mActivityView != null;
- }
-
- boolean isEnabled() {
- return mRearViewCameraActivity != null;
- }
-
- @Override
- protected boolean shouldShowHUN() {
- return false;
- }
-
- @Override
- protected boolean shouldShowWhenOccluded() {
- // Returns true to show it on top of Keylock.
- return true;
- }
-
- @Override
- protected boolean shouldShowNavigationBarInsets() {
- return true;
- }
-
- @Override
- protected boolean shouldShowStatusBarInsets() {
- return true;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/rvc/RearViewCameraViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/rvc/RearViewCameraViewMediator.java
deleted file mode 100644
index c575c423b256..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/rvc/RearViewCameraViewMediator.java
+++ /dev/null
@@ -1,121 +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.car.rvc;
-
-import android.car.Car;
-import android.car.VehicleGear;
-import android.car.VehiclePropertyIds;
-import android.car.hardware.CarPropertyValue;
-import android.car.hardware.property.CarPropertyManager;
-import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.UserHandle;
-import android.util.Slog;
-
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.window.OverlayViewMediator;
-import com.android.systemui.dagger.SysUISingleton;
-
-import javax.inject.Inject;
-
-/**
- * View mediator for the rear view camera (RVC), which monitors the gear changes and shows
- * the RVC when the gear position is R and otherwise it hides the RVC.
- */
-@SysUISingleton
-public class RearViewCameraViewMediator implements OverlayViewMediator {
- private static final String TAG = "RearViewCameraView";
- private static final boolean DBG = false;
-
- private final RearViewCameraViewController mRearViewCameraViewController;
- private final CarServiceProvider mCarServiceProvider;
- private final BroadcastDispatcher mBroadcastDispatcher;
-
- private CarPropertyManager mCarPropertyManager;
- // TODO(b/170792252): Replace the following with the callback from CarEvsManager if it's ready.
- private final CarPropertyEventCallback mPropertyEventCallback = new CarPropertyEventCallback() {
- @Override
- public void onChangeEvent(CarPropertyValue value) {
- if (DBG) Slog.d(TAG, "onChangeEvent value=" + value);
- if (value.getPropertyId() != VehiclePropertyIds.GEAR_SELECTION) {
- Slog.w(TAG, "Got the event for non-registered property: " + value.getPropertyId());
- return;
- }
- if ((Integer) value.getValue() == VehicleGear.GEAR_REVERSE) {
- mRearViewCameraViewController.start();
- } else {
- mRearViewCameraViewController.stop();
- }
- }
- @Override
- public void onErrorEvent(int propId, int zone) {
- Slog.e(TAG, "onErrorEvent propId=" + propId + ", zone=" + zone);
- }
- };
-
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DBG) Slog.d(TAG, "onReceive: " + intent);
- if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())
- && mRearViewCameraViewController.isShown()) {
- mRearViewCameraViewController.stop();
- }
- }
- };
-
- @Inject
- public RearViewCameraViewMediator(
- RearViewCameraViewController rearViewCameraViewController,
- CarServiceProvider carServiceProvider,
- BroadcastDispatcher broadcastDispatcher) {
- if (DBG) Slog.d(TAG, "RearViewCameraViewMediator:init");
- mRearViewCameraViewController = rearViewCameraViewController;
- mCarServiceProvider = carServiceProvider;
- mBroadcastDispatcher = broadcastDispatcher;
- }
-
- @Override
- public void registerListeners() {
- if (DBG) Slog.d(TAG, "RearViewCameraViewMediator:registerListeners");
- if (!mRearViewCameraViewController.isEnabled()) {
- Slog.i(TAG, "RearViewCameraViewController isn't enabled");
- return;
- }
-
- mCarServiceProvider.addListener(car -> {
- mCarPropertyManager = (CarPropertyManager) car.getCarManager(Car.PROPERTY_SERVICE);
- if (mCarPropertyManager == null) {
- Slog.e(TAG, "Unable to get CarPropertyManager");
- return;
- }
- if (DBG) Slog.d(TAG, "Registering mPropertyEventCallback.");
- mCarPropertyManager.registerCallback(mPropertyEventCallback,
- VehiclePropertyIds.GEAR_SELECTION, CarPropertyManager.SENSOR_RATE_UI);
- });
- mBroadcastDispatcher.registerReceiver(mBroadcastReceiver,
- new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), /* executor= */ null,
- UserHandle.ALL);
- }
-
- @Override
- public void setupOverlayContentViewControllers() {}
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppController.java b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppController.java
deleted file mode 100644
index b8d6964fa32d..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppController.java
+++ /dev/null
@@ -1,73 +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.car.sideloaded;
-
-import android.app.IActivityTaskManager;
-import android.content.Context;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.SysUISingleton;
-
-import javax.inject.Inject;
-
-/**
- * Controller responsible for detecting unsafe apps.
- */
-@SysUISingleton
-public class SideLoadedAppController extends SystemUI {
- private static final String TAG = SideLoadedAppController.class.getSimpleName();
-
- private IActivityTaskManager mActivityTaskManager;
- private SideLoadedAppListener mSideLoadedAppListener;
- private SideLoadedAppDetector mSideLoadedAppDetector;
- private SideLoadedAppStateController mSideLoadedAppStateController;
-
- @Inject
- public SideLoadedAppController(Context context,
- IActivityTaskManager activityTaskManager,
- SideLoadedAppDetector sideLoadedAppDetector,
- SideLoadedAppListener sideLoadedAppListener,
- SideLoadedAppStateController sideLoadedAppStateController) {
- super(context);
-
- mSideLoadedAppDetector = sideLoadedAppDetector;
- mActivityTaskManager = activityTaskManager;
- mSideLoadedAppListener = sideLoadedAppListener;
- mSideLoadedAppStateController = sideLoadedAppStateController;
- }
-
- @Override
- public void start() {
- }
-
- @Override
- protected void onBootCompleted() {
- Log.i(TAG, "OnBootCompleted");
-
- try {
- mActivityTaskManager.registerTaskStackListener(mSideLoadedAppListener);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not register car side loaded app listener.", e);
- }
-
- if (mSideLoadedAppDetector.hasUnsafeInstalledApps()) {
- mSideLoadedAppStateController.onUnsafeInstalledAppsDetected();
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java
deleted file mode 100644
index f96ee0f73dc0..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java
+++ /dev/null
@@ -1,136 +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.car.sideloaded;
-
-import android.annotation.NonNull;
-import android.app.ActivityTaskManager.RootTaskInfo;
-import android.content.ComponentName;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.InstallSourceInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.os.UserHandle;
-import android.util.Log;
-
-import com.android.systemui.R;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-
-import java.util.Arrays;
-import java.util.List;
-
-import javax.inject.Inject;
-
-/**
- * A class that detects unsafe apps.
- * An app is considered safe if is a system app or installed through allowed sources.
- */
-@SysUISingleton
-public class SideLoadedAppDetector {
- private static final String TAG = SideLoadedAppDetector.class.getSimpleName();
-
- private final PackageManager mPackageManager;
- private final CarDeviceProvisionedController mCarDeviceProvisionedController;
- private final List<String> mAllowedAppInstallSources;
-
- @Inject
- public SideLoadedAppDetector(@Main Resources resources, PackageManager packageManager,
- CarDeviceProvisionedController deviceProvisionedController) {
- mAllowedAppInstallSources = Arrays.asList(
- resources.getStringArray(R.array.config_allowedAppInstallSources));
- mPackageManager = packageManager;
- mCarDeviceProvisionedController = deviceProvisionedController;
- }
-
- boolean hasUnsafeInstalledApps() {
- int userId = mCarDeviceProvisionedController.getCurrentUser();
-
- List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- userId);
- for (PackageInfo info : packages) {
- if (info.applicationInfo == null) {
- Log.w(TAG, info.packageName + " does not have application info.");
- return true;
- }
-
- if (!isSafe(info.applicationInfo)) {
- return true;
- }
- }
- return false;
- }
-
- boolean isSafe(@NonNull RootTaskInfo taskInfo) {
- ComponentName componentName = taskInfo.topActivity;
- if (componentName == null) {
- Log.w(TAG, "Task info does not have top activity: " + taskInfo.taskId);
- return false;
- }
- return isSafe(componentName.getPackageName());
- }
-
- private boolean isSafe(@NonNull String packageName) {
- if (packageName == null) {
- return false;
- }
-
- ApplicationInfo applicationInfo;
- try {
- int userId = mCarDeviceProvisionedController.getCurrentUser();
- applicationInfo = mPackageManager.getApplicationInfoAsUser(packageName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- UserHandle.of(userId));
-
- if (applicationInfo == null) {
- Log.e(TAG, packageName + " did not have an application info!");
- return false;
- }
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Could not get application info for package:" + packageName, e);
- return false;
- }
-
- return isSafe(applicationInfo);
- }
-
- private boolean isSafe(@NonNull ApplicationInfo applicationInfo) {
- String packageName = applicationInfo.packageName;
-
- if (applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp()) {
- return true;
- }
-
- String initiatingPackageName;
- try {
- InstallSourceInfo sourceInfo = mPackageManager.getInstallSourceInfo(packageName);
- initiatingPackageName = sourceInfo.getInitiatingPackageName();
- if (initiatingPackageName == null) {
- Log.w(TAG, packageName + " does not have an installer name.");
- return false;
- }
-
- return mAllowedAppInstallSources.contains(initiatingPackageName);
- } catch (IllegalArgumentException | PackageManager.NameNotFoundException e) {
- return false;
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppListener.java b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppListener.java
deleted file mode 100644
index db7718bc166b..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppListener.java
+++ /dev/null
@@ -1,127 +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.car.sideloaded;
-
-import android.app.ActivityTaskManager.RootTaskInfo;
-import android.app.IActivityTaskManager;
-import android.app.TaskStackListener;
-import android.content.ComponentName;
-import android.hardware.display.DisplayManager;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.Display;
-
-import java.util.List;
-
-import javax.inject.Inject;
-
-/**
- * A TaskStackListener to detect when an unsafe app is launched/foregrounded.
- */
-public class SideLoadedAppListener extends TaskStackListener {
- private static final String TAG = SideLoadedAppListener.class.getSimpleName();
-
- private IActivityTaskManager mActivityTaskManager;
- private DisplayManager mDisplayManager;
- private SideLoadedAppDetector mSideLoadedAppDetector;
- private SideLoadedAppStateController mSideLoadedAppStateController;
-
- @Inject
- SideLoadedAppListener(SideLoadedAppDetector sideLoadedAppDetector,
- IActivityTaskManager activityTaskManager,
- DisplayManager displayManager,
- SideLoadedAppStateController sideLoadedAppStateController) {
- mSideLoadedAppDetector = sideLoadedAppDetector;
- mActivityTaskManager = activityTaskManager;
- mDisplayManager = displayManager;
- mSideLoadedAppStateController = sideLoadedAppStateController;
- }
-
- @Override
- public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
- super.onTaskCreated(taskId, componentName);
-
- List<RootTaskInfo> taskInfoList = mActivityTaskManager.getAllRootTaskInfos();
- RootTaskInfo taskInfo = getStackInfo(taskInfoList, taskId);
- if (taskInfo == null) {
- Log.e(TAG, "Stack info was not available for taskId: " + taskId);
- return;
- }
-
- if (!mSideLoadedAppDetector.isSafe(taskInfo)) {
- Display display = mDisplayManager.getDisplay(taskInfo.displayId);
- mSideLoadedAppStateController.onUnsafeTaskCreatedOnDisplay(display);
- }
- }
-
- @Override
- public void onTaskStackChanged() throws RemoteException {
- super.onTaskStackChanged();
-
- Display[] displays = mDisplayManager.getDisplays();
- for (Display display : displays) {
- // Note that the taskInfoList is ordered by recency.
- List<RootTaskInfo> taskInfoList =
- mActivityTaskManager.getAllRootTaskInfosOnDisplay(display.getDisplayId());
-
- if (taskInfoList == null) {
- continue;
- }
- RootTaskInfo taskInfo = getTopVisibleStackInfo(taskInfoList);
- if (taskInfo == null) {
- continue;
- }
- if (mSideLoadedAppDetector.isSafe(taskInfo)) {
- mSideLoadedAppStateController.onSafeTaskDisplayedOnDisplay(display);
- } else {
- mSideLoadedAppStateController.onUnsafeTaskDisplayedOnDisplay(display);
- }
- }
- }
-
- /**
- * Returns stack info for a given taskId.
- */
- private RootTaskInfo getStackInfo(List<RootTaskInfo> taskInfoList, int taskId) {
- if (taskInfoList == null) {
- return null;
- }
- for (RootTaskInfo taskInfo : taskInfoList) {
- if (taskInfo.childTaskIds == null) {
- continue;
- }
- for (int taskTaskId : taskInfo.childTaskIds) {
- if (taskId == taskTaskId) {
- return taskInfo;
- }
- }
- }
- return null;
- }
-
- /**
- * Returns the first visible stackInfo.
- */
- private RootTaskInfo getTopVisibleStackInfo(List<RootTaskInfo> taskInfoList) {
- for (RootTaskInfo taskInfo : taskInfoList) {
- if (taskInfo.visible) {
- return taskInfo;
- }
- }
- return null;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppStateController.java
deleted file mode 100644
index 5b4faa152685..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppStateController.java
+++ /dev/null
@@ -1,52 +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.car.sideloaded;
-
-import android.util.Log;
-import android.view.Display;
-
-import com.android.systemui.dagger.SysUISingleton;
-
-import javax.inject.Inject;
-
-/**
- * Manager responsible for displaying proper UI when an unsafe app is detected.
- */
-@SysUISingleton
-public class SideLoadedAppStateController {
- private static final String TAG = SideLoadedAppStateController.class.getSimpleName();
-
- @Inject
- SideLoadedAppStateController() {
- }
-
- void onUnsafeInstalledAppsDetected() {
- Log.d(TAG, "Unsafe installed apps detected.");
- }
-
- void onUnsafeTaskCreatedOnDisplay(Display display) {
- Log.d(TAG, "Unsafe task created on display " + display.getDisplayId() + ".");
- }
-
- void onSafeTaskDisplayedOnDisplay(Display display) {
- Log.d(TAG, "Safe task displayed on display " + display.getDisplayId() + ".");
- }
-
- void onUnsafeTaskDisplayedOnDisplay(Display display) {
- Log.d(TAG, "Unsafe task displayed on display " + display.getDisplayId() + ".");
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/DozeServiceHost.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/DozeServiceHost.java
deleted file mode 100644
index 3fb3cd8833b9..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/DozeServiceHost.java
+++ /dev/null
@@ -1,130 +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.car.statusbar;
-
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.doze.DozeHost;
-
-import javax.inject.Inject;
-
-/** No-op implementation of {@link DozeHost} for use by car sysui, which does not support dozing. */
-@SysUISingleton
-public class DozeServiceHost implements DozeHost {
-
- @Inject
- public DozeServiceHost() {}
-
- @Override
- public void addCallback(Callback callback) {
- // No op.
- }
-
- @Override
- public void removeCallback(Callback callback) {
- // No op.
- }
-
- @Override
- public void startDozing() {
- // No op.
- }
-
- @Override
- public void pulseWhileDozing(PulseCallback callback, int reason) {
- // No op.
- }
-
- @Override
- public void stopDozing() {
- // No op.
- }
-
- @Override
- public void dozeTimeTick() {
- // No op.
- }
-
- @Override
- public boolean isPowerSaveActive() {
- return false;
- }
-
- @Override
- public boolean isPulsingBlocked() {
- return true;
- }
-
- @Override
- public boolean isProvisioned() {
- return false;
- }
-
- @Override
- public boolean isBlockingDoze() {
- return true;
- }
-
- @Override
- public void extendPulse(int reason) {
- // No op.
- }
-
- @Override
- public void setAnimateWakeup(boolean animateWakeup) {
- // No op.
- }
-
- @Override
- public void setAnimateScreenOff(boolean animateScreenOff) {
- // No op.
- }
-
- @Override
- public void onSlpiTap(float x, float y) {
- // No op.
- }
-
- @Override
- public void setDozeScreenBrightness(int value) {
- // No op.
- }
-
- @Override
- public void prepareForGentleSleep(Runnable onDisplayOffCallback) {
- // No op.
- }
-
- @Override
- public void cancelGentleSleep() {
- // No op.
- }
-
- @Override
- public void onIgnoreTouchWhilePulsing(boolean ignore) {
- // No op.
- }
-
- @Override
- public void stopPulsing() {
- // No op.
- }
-
- @Override
- public boolean isDozeSuppressed() {
- return true;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java
deleted file mode 100644
index 1b1a118d6ba1..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java
+++ /dev/null
@@ -1,139 +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.car.statusbar;
-
-import android.car.Car;
-import android.car.user.CarUserManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.UserInfo;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import android.view.View;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.dagger.SysUISingleton;
-
-import javax.inject.Inject;
-
-/**
- * Controls a TextView with the current driver's username
- */
-@SysUISingleton
-public class UserNameViewController {
- private static final String TAG = "UserNameViewController";
-
- private Context mContext;
- private UserManager mUserManager;
- private CarUserManager mCarUserManager;
- private CarServiceProvider mCarServiceProvider;
- private CarDeviceProvisionedController mCarDeviceProvisionedController;
- private BroadcastDispatcher mBroadcastDispatcher;
- private TextView mUserNameView;
-
- private final BroadcastReceiver mUserUpdateReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- updateUser(mCarDeviceProvisionedController.getCurrentUser());
- }
- };
-
- private boolean mUserLifecycleListenerRegistered = false;
-
- private final CarUserManager.UserLifecycleListener mUserLifecycleListener =
- new CarUserManager.UserLifecycleListener() {
- @Override
- public void onEvent(CarUserManager.UserLifecycleEvent event) {
- if (event.getEventType()
- == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
- updateUser(event.getUserId());
- }
- }
- };
-
- @Inject
- public UserNameViewController(Context context, CarServiceProvider carServiceProvider,
- UserManager userManager, BroadcastDispatcher broadcastDispatcher,
- CarDeviceProvisionedController carDeviceProvisionedController) {
- mContext = context;
- mCarServiceProvider = carServiceProvider;
- mUserManager = userManager;
- mBroadcastDispatcher = broadcastDispatcher;
- mCarDeviceProvisionedController = carDeviceProvisionedController;
- }
-
- /**
- * Find the {@link TextView} for the driver's user name from a view and if found set it with the
- * current driver's user name.
- */
- public void addUserNameView(View v) {
- TextView userNameView = v.findViewById(R.id.user_name_text);
- if (userNameView != null) {
- if (mUserNameView == null) {
- registerForUserChangeEvents();
- }
- mUserNameView = userNameView;
- updateUser(mCarDeviceProvisionedController.getCurrentUser());
- }
- }
-
- /**
- * Clean up the controller and unregister receiver.
- */
- public void removeAll() {
- mUserNameView = null;
- if (mUserLifecycleListenerRegistered) {
- mBroadcastDispatcher.unregisterReceiver(mUserUpdateReceiver);
- if (mCarUserManager != null) {
- mCarUserManager.removeListener(mUserLifecycleListener);
- }
- mUserLifecycleListenerRegistered = false;
- }
- }
-
- private void registerForUserChangeEvents() {
- // Register for user switching
- mCarServiceProvider.addListener(car -> {
- mCarUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
- if (mCarUserManager != null) {
- mCarUserManager.addListener(Runnable::run, mUserLifecycleListener);
- mUserLifecycleListenerRegistered = true;
- } else {
- Log.e(TAG, "CarUserManager could not be obtained.");
- }
- });
- // Also register for user info changing
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
- mBroadcastDispatcher.registerReceiver(mUserUpdateReceiver, filter, /* executor= */ null,
- UserHandle.ALL);
- }
-
- private void updateUser(int userId) {
- if (mUserNameView != null) {
- UserInfo currentUserInfo = mUserManager.getUserInfo(userId);
- mUserNameView.setText(currentUserInfo.name);
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java
deleted file mode 100644
index 0a677bfaa742..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java
+++ /dev/null
@@ -1,60 +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.car.userswitcher;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import androidx.annotation.IdRes;
-
-import com.android.settingslib.Utils;
-import com.android.systemui.R;
-import com.android.systemui.plugins.DarkIconDispatcher;
-
-/**
- * A view that forms the header of the notification panel. This view will ensure that any
- * status icons that are displayed are tinted accordingly to the current theme.
- */
-public class CarStatusBarHeader extends LinearLayout {
- public CarStatusBarHeader(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- // Set the light/dark theming on the header status UI to match the current theme.
- int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
- android.R.attr.colorForeground);
- float intensity = colorForeground == Color.WHITE ? 0f : 1f;
- Rect tintArea = new Rect(0, 0, 0, 0);
-
- applyDarkness(R.id.clock, tintArea, intensity, colorForeground);
- }
-
- private void applyDarkness(@IdRes int id, Rect tintArea, float intensity, int color) {
- View v = findViewById(id);
- if (v instanceof DarkIconDispatcher.DarkReceiver) {
- ((DarkIconDispatcher.DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java
deleted file mode 100644
index 3a7fac9c0e79..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java
+++ /dev/null
@@ -1,123 +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.car.userswitcher;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.car.Car;
-import android.car.user.CarUserManager;
-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.car.CarServiceProvider;
-import com.android.systemui.car.window.OverlayViewController;
-import com.android.systemui.car.window.OverlayViewGlobalStateController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-
-import javax.inject.Inject;
-
-/**
- * Controller for {@link R.layout#car_fullscreen_user_switcher}.
- */
-@SysUISingleton
-public class FullScreenUserSwitcherViewController extends OverlayViewController {
- private final Context mContext;
- private final Resources mResources;
- private final CarServiceProvider mCarServiceProvider;
- private final int mShortAnimationDuration;
- private CarUserManager mCarUserManager;
- private UserGridRecyclerView mUserGridView;
- private UserGridRecyclerView.UserSelectionListener mUserSelectionListener;
-
- @Inject
- public FullScreenUserSwitcherViewController(
- Context context,
- @Main Resources resources,
- CarServiceProvider carServiceProvider,
- OverlayViewGlobalStateController overlayViewGlobalStateController) {
- super(R.id.fullscreen_user_switcher_stub, overlayViewGlobalStateController);
- mContext = context;
- mResources = resources;
- mCarServiceProvider = carServiceProvider;
- mCarServiceProvider.addListener(car -> {
- mCarUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
- registerCarUserManagerIfPossible();
- });
- 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);
- registerCarUserManagerIfPossible();
- }
-
- @Override
- protected boolean shouldFocusWindow() {
- return false;
- }
-
- @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);
- }
- });
-
- }
-
- /**
- * Set {@link UserGridRecyclerView.UserSelectionListener}.
- */
- void setUserGridSelectionListener(
- UserGridRecyclerView.UserSelectionListener userGridSelectionListener) {
- mUserSelectionListener = userGridSelectionListener;
- }
-
- private void registerCarUserManagerIfPossible() {
- if (mUserGridView != null && mCarUserManager != null) {
- mUserGridView.setCarUserManager(mCarUserManager);
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
deleted file mode 100644
index 165fe63c7f37..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java
+++ /dev/null
@@ -1,97 +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.car.userswitcher;
-
-import com.android.systemui.car.keyguard.CarKeyguardViewController;
-import com.android.systemui.car.window.OverlayViewMediator;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarState;
-
-import javax.inject.Inject;
-
-/**
- * Manages the fullscreen user switcher and it's interactions with the keyguard.
- */
-@SysUISingleton
-public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator {
- private static final String TAG = FullscreenUserSwitcherViewMediator.class.getSimpleName();
-
- private final StatusBarStateController mStatusBarStateController;
- private final FullScreenUserSwitcherViewController mFullScreenUserSwitcherViewController;
- private final CarKeyguardViewController mCarKeyguardViewController;
- private final UserSwitchTransitionViewController mUserSwitchTransitionViewController;
-
- @Inject
- public FullscreenUserSwitcherViewMediator(
- StatusBarStateController statusBarStateController,
- CarKeyguardViewController carKeyguardViewController,
- UserSwitchTransitionViewController userSwitchTransitionViewController,
- FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController) {
-
- mStatusBarStateController = statusBarStateController;
- mCarKeyguardViewController = carKeyguardViewController;
- mUserSwitchTransitionViewController = userSwitchTransitionViewController;
- mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController;
- }
-
- @Override
- public void registerListeners() {
- registerUserSwitcherHideListeners();
- }
-
- private void registerUserSwitcherHideListeners() {
- mStatusBarStateController.addCallback(new StatusBarStateController.StateListener() {
- @Override
- public void onStateChanged(int newState) {
- if (newState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
- return;
- }
- hide();
- }
- });
- }
-
- @Override
- public void setupOverlayContentViewControllers() {
- mFullScreenUserSwitcherViewController.setUserGridSelectionListener(this::onUserSelected);
- }
-
- /**
- * Every time user clicks on an item in the switcher, we hide the switcher.
- */
- private void onUserSelected(UserGridRecyclerView.UserRecord record) {
- if (record.mType != UserGridRecyclerView.UserRecord.FOREGROUND_USER) {
- mCarKeyguardViewController.hideKeyguardToPrepareBouncer();
- // If guest user, we cannot use record.mInfo.id and should listen to the User lifecycle
- // event instead.
- if (record.mType != UserGridRecyclerView.UserRecord.START_GUEST) {
- mUserSwitchTransitionViewController.handleShow(record.mInfo.id);
- }
- }
-
- hide();
- }
-
- private void hide() {
- mFullScreenUserSwitcherViewController.stop();
- }
-
- private void show() {
- mFullScreenUserSwitcherViewController.start();
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
deleted file mode 100644
index 6d63e31d79b5..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
+++ /dev/null
@@ -1,657 +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.car.userswitcher;
-
-import static android.content.DialogInterface.BUTTON_NEGATIVE;
-import static android.content.DialogInterface.BUTTON_POSITIVE;
-import static android.os.UserManager.DISALLOW_ADD_USER;
-import static android.os.UserManager.SWITCHABILITY_STATUS_OK;
-import static android.view.WindowInsets.Type.statusBars;
-
-import android.annotation.IntDef;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.app.AlertDialog.Builder;
-import android.app.Dialog;
-import android.car.user.CarUserManager;
-import android.car.user.UserCreationResult;
-import android.car.user.UserSwitchResult;
-import android.car.userlib.UserHelper;
-import android.car.util.concurrent.AsyncFuture;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.os.AsyncTask;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.sysprop.CarProperties;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.core.graphics.drawable.RoundedBitmapDrawable;
-import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.internal.util.UserIcons;
-import com.android.systemui.R;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-/**
- * Displays a GridLayout with icons for the users in the system to allow switching between users.
- * One of the uses of this is for the lock screen in auto.
- */
-public class UserGridRecyclerView extends RecyclerView {
- private static final String TAG = UserGridRecyclerView.class.getSimpleName();
- private static final int TIMEOUT_MS = CarProperties.user_hal_timeout().orElse(5_000) + 500;
-
- private UserSelectionListener mUserSelectionListener;
- private UserAdapter mAdapter;
- private CarUserManager mCarUserManager;
- private UserManager mUserManager;
- private Context mContext;
- private UserIconProvider mUserIconProvider;
-
- private final BroadcastReceiver mUserUpdateReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- onUsersUpdate();
- }
- };
-
- public UserGridRecyclerView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- mUserManager = UserManager.get(mContext);
- mUserIconProvider = new UserIconProvider();
-
- addItemDecoration(new ItemSpacingDecoration(mContext.getResources().getDimensionPixelSize(
- R.dimen.car_user_switcher_vertical_spacing_between_users)));
- }
-
- /**
- * Register listener for any update to the users
- */
- @Override
- public void onFinishInflate() {
- super.onFinishInflate();
- registerForUserEvents();
- }
-
- /**
- * Unregisters listener checking for any change to the users
- */
- @Override
- public void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- unregisterForUserEvents();
- }
-
- /**
- * Initializes the adapter that populates the grid layout
- */
- public void buildAdapter() {
- List<UserRecord> userRecords = createUserRecords(getUsersForUserGrid());
- mAdapter = new UserAdapter(mContext, userRecords);
- super.setAdapter(mAdapter);
- }
-
- private List<UserInfo> getUsersForUserGrid() {
- return mUserManager.getAliveUsers()
- .stream()
- .filter(UserInfo::supportsSwitchToByUser)
- .collect(Collectors.toList());
- }
-
- private List<UserRecord> createUserRecords(List<UserInfo> userInfoList) {
- int fgUserId = ActivityManager.getCurrentUser();
- UserHandle fgUserHandle = UserHandle.of(fgUserId);
- List<UserRecord> userRecords = new ArrayList<>();
-
- // If the foreground user CANNOT switch to other users, only display the foreground user.
- if (mUserManager.getUserSwitchability(fgUserHandle) != SWITCHABILITY_STATUS_OK) {
- userRecords.add(createForegroundUserRecord());
- return userRecords;
- }
-
- for (UserInfo userInfo : userInfoList) {
- if (userInfo.isGuest()) {
- // Don't display guests in the switcher.
- continue;
- }
-
- boolean isForeground = fgUserId == userInfo.id;
- UserRecord record = new UserRecord(userInfo,
- isForeground ? UserRecord.FOREGROUND_USER : UserRecord.BACKGROUND_USER);
- userRecords.add(record);
- }
-
- // Add button for starting guest session.
- userRecords.add(createStartGuestUserRecord());
-
- // Add add user record if the foreground user can add users
- if (!mUserManager.hasUserRestriction(DISALLOW_ADD_USER, fgUserHandle)) {
- userRecords.add(createAddUserRecord());
- }
-
- return userRecords;
- }
-
- private UserRecord createForegroundUserRecord() {
- return new UserRecord(mUserManager.getUserInfo(ActivityManager.getCurrentUser()),
- UserRecord.FOREGROUND_USER);
- }
-
- /**
- * Create guest user record
- */
- private UserRecord createStartGuestUserRecord() {
- return new UserRecord(null /* userInfo */, UserRecord.START_GUEST);
- }
-
- /**
- * Create add user record
- */
- private UserRecord createAddUserRecord() {
- return new UserRecord(null /* userInfo */, UserRecord.ADD_USER);
- }
-
- public void setUserSelectionListener(UserSelectionListener userSelectionListener) {
- mUserSelectionListener = userSelectionListener;
- }
-
- /** Sets a {@link CarUserManager}. */
- public void setCarUserManager(CarUserManager carUserManager) {
- mCarUserManager = carUserManager;
- }
-
- private void onUsersUpdate() {
- mAdapter.clearUsers();
- mAdapter.updateUsers(createUserRecords(getUsersForUserGrid()));
- mAdapter.notifyDataSetChanged();
- }
-
- private void registerForUserEvents() {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_REMOVED);
- filter.addAction(Intent.ACTION_USER_ADDED);
- filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- mContext.registerReceiverAsUser(
- mUserUpdateReceiver,
- UserHandle.ALL, // Necessary because CarSystemUi lives in User 0
- filter,
- /* broadcastPermission= */ null,
- /* scheduler= */ null);
- }
-
- private void unregisterForUserEvents() {
- mContext.unregisterReceiver(mUserUpdateReceiver);
- }
-
- /**
- * Adapter to populate the grid layout with the available user profiles
- */
- public final class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserAdapterViewHolder>
- implements Dialog.OnClickListener, Dialog.OnCancelListener {
-
- private final Context mContext;
- private List<UserRecord> mUsers;
- private final Resources mRes;
- private final String mGuestName;
- private final String mNewUserName;
- // View that holds the add user button. Used to enable/disable the view
- private View mAddUserView;
- // User record for the add user. Need to call notifyUserSelected only if the user
- // confirms adding a user
- private UserRecord mAddUserRecord;
-
- public UserAdapter(Context context, List<UserRecord> users) {
- mRes = context.getResources();
- mContext = context;
- updateUsers(users);
- mGuestName = mRes.getString(R.string.car_guest);
- 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;
- }
-
- @Override
- public UserAdapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- View view = LayoutInflater.from(mContext)
- .inflate(R.layout.car_fullscreen_user_pod, parent, false);
- view.setAlpha(1f);
- view.bringToFront();
- return new UserAdapterViewHolder(view);
- }
-
- @Override
- public void onBindViewHolder(UserAdapterViewHolder holder, int position) {
- UserRecord userRecord = mUsers.get(position);
- RoundedBitmapDrawable circleIcon = getCircularUserRecordIcon(userRecord);
- holder.mUserAvatarImageView.setImageDrawable(circleIcon);
- holder.mUserNameTextView.setText(getUserRecordName(userRecord));
-
- holder.mView.setOnClickListener(v -> {
- if (userRecord == null) {
- return;
- }
-
- switch (userRecord.mType) {
- case UserRecord.START_GUEST:
- notifyUserSelected(userRecord);
- UserInfo guest = createNewOrFindExistingGuest(mContext);
- if (guest != null) {
- if (!switchUser(guest.id)) {
- Log.e(TAG, "Failed to switch to guest user: " + guest.id);
- }
- }
- break;
- case UserRecord.ADD_USER:
- // If the user wants to add a user, show dialog to confirm adding a user
- // Disable button so it cannot be clicked multiple times
- mAddUserView = holder.mView;
- mAddUserView.setEnabled(false);
- mAddUserRecord = userRecord;
-
- handleAddUserClicked();
- break;
- default:
- // If the user doesn't want to be a guest or add a user, switch to the user
- // selected
- notifyUserSelected(userRecord);
- if (!switchUser(userRecord.mInfo.id)) {
- Log.e(TAG, "Failed to switch users: " + userRecord.mInfo.id);
- }
- }
- });
-
- }
-
- private void handleAddUserClicked() {
- if (!mUserManager.canAddMoreUsers()) {
- mAddUserView.setEnabled(true);
- showMaxUserLimitReachedDialog();
- } else {
- showConfirmAddUserDialog();
- }
- }
-
- /**
- * Get the maximum number of real (non-guest, non-managed profile) users that can be created
- * on the device. This is a dynamic value and it decreases with the increase of the number
- * of managed profiles on the device.
- *
- * <p> It excludes system user in headless system user model.
- *
- * @return Maximum number of real users that can be created.
- */
- private int getMaxSupportedRealUsers() {
- int maxSupportedUsers = UserManager.getMaxSupportedUsers();
- if (UserManager.isHeadlessSystemUserMode()) {
- maxSupportedUsers -= 1;
- }
-
- List<UserInfo> users = mUserManager.getAliveUsers();
-
- // Count all users that are managed profiles of another user.
- int managedProfilesCount = 0;
- for (UserInfo user : users) {
- if (user.isManagedProfile()) {
- managedProfilesCount++;
- }
- }
-
- return maxSupportedUsers - managedProfilesCount;
- }
-
- private void showMaxUserLimitReachedDialog() {
- AlertDialog maxUsersDialog = new Builder(mContext,
- com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert)
- .setTitle(R.string.user_limit_reached_title)
- .setMessage(getResources().getQuantityString(
- R.plurals.user_limit_reached_message,
- getMaxSupportedRealUsers(),
- getMaxSupportedRealUsers()))
- .setPositiveButton(android.R.string.ok, null)
- .create();
- // Sets window flags for the SysUI dialog
- applyCarSysUIDialogFlags(maxUsersDialog);
- maxUsersDialog.show();
- }
-
- private void showConfirmAddUserDialog() {
- String message = mRes.getString(R.string.user_add_user_message_setup)
- .concat(System.getProperty("line.separator"))
- .concat(System.getProperty("line.separator"))
- .concat(mRes.getString(R.string.user_add_user_message_update));
-
- AlertDialog addUserDialog = new Builder(mContext,
- com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert)
- .setTitle(R.string.user_add_user_title)
- .setMessage(message)
- .setNegativeButton(android.R.string.cancel, this)
- .setPositiveButton(android.R.string.ok, this)
- .setOnCancelListener(this)
- .create();
- // Sets window flags for the SysUI dialog
- applyCarSysUIDialogFlags(addUserDialog);
- addUserDialog.show();
- }
-
- private void applyCarSysUIDialogFlags(AlertDialog dialog) {
- final Window window = dialog.getWindow();
- window.setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
- | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
- window.getAttributes().setFitInsetsTypes(
- window.getAttributes().getFitInsetsTypes() & ~statusBars());
- }
-
- private void notifyUserSelected(UserRecord userRecord) {
- // Notify the listener which user was selected
- if (mUserSelectionListener != null) {
- mUserSelectionListener.onUserSelected(userRecord);
- }
- }
-
- private RoundedBitmapDrawable getCircularUserRecordIcon(UserRecord userRecord) {
- Resources resources = mContext.getResources();
- RoundedBitmapDrawable circleIcon;
- switch (userRecord.mType) {
- case UserRecord.START_GUEST:
- circleIcon = mUserIconProvider.getRoundedGuestDefaultIcon(resources);
- break;
- case UserRecord.ADD_USER:
- circleIcon = getCircularAddUserIcon();
- break;
- default:
- circleIcon = mUserIconProvider.getRoundedUserIcon(userRecord.mInfo, mContext);
- break;
- }
- return circleIcon;
- }
-
- private RoundedBitmapDrawable getCircularAddUserIcon() {
- RoundedBitmapDrawable circleIcon =
- RoundedBitmapDrawableFactory.create(mRes, UserIcons.convertToBitmap(
- mContext.getDrawable(R.drawable.car_add_circle_round)));
- circleIcon.setCircular(true);
- return circleIcon;
- }
-
- private String getUserRecordName(UserRecord userRecord) {
- String recordName;
- switch (userRecord.mType) {
- case UserRecord.START_GUEST:
- recordName = mContext.getString(R.string.start_guest_session);
- break;
- case UserRecord.ADD_USER:
- recordName = mContext.getString(R.string.car_add_user);
- break;
- default:
- recordName = userRecord.mInfo.name;
- break;
- }
- return recordName;
- }
-
- /**
- * Finds the existing Guest user, or creates one if it doesn't exist.
- * @param context App context
- * @return UserInfo representing the Guest user
- */
- @Nullable
- public UserInfo createNewOrFindExistingGuest(Context context) {
- AsyncFuture<UserCreationResult> future = mCarUserManager.createGuest(mGuestName);
- // CreateGuest will return null if a guest already exists.
- UserInfo newGuest = getUserInfo(future);
- if (newGuest != null) {
- new UserIconProvider().assignDefaultIcon(
- mUserManager, context.getResources(), newGuest);
- return newGuest;
- }
-
- return mUserManager.findCurrentGuestUser();
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == BUTTON_POSITIVE) {
- new AddNewUserTask().execute(mNewUserName);
- } else if (which == BUTTON_NEGATIVE) {
- // Enable the add button only if cancel
- if (mAddUserView != null) {
- mAddUserView.setEnabled(true);
- }
- }
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- // Enable the add button again if user cancels dialog by clicking outside the dialog
- if (mAddUserView != null) {
- mAddUserView.setEnabled(true);
- }
- }
-
- @Nullable
- private UserInfo getUserInfo(AsyncFuture<UserCreationResult> future) {
- UserCreationResult userCreationResult;
- try {
- userCreationResult = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (Exception e) {
- Log.w(TAG, "Could not create user.", e);
- return null;
- }
-
- if (userCreationResult == null) {
- Log.w(TAG, "Timed out while creating user: " + TIMEOUT_MS + "ms");
- return null;
- }
- if (!userCreationResult.isSuccess() || userCreationResult.getUser() == null) {
- Log.w(TAG, "Could not create user: " + userCreationResult);
- return null;
- }
-
- return userCreationResult.getUser();
- }
-
- private boolean switchUser(@UserIdInt int userId) {
- AsyncFuture<UserSwitchResult> userSwitchResultFuture =
- mCarUserManager.switchUser(userId);
- UserSwitchResult userSwitchResult;
- try {
- userSwitchResult = userSwitchResultFuture.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (Exception e) {
- Log.w(TAG, "Could not switch user.", e);
- return false;
- }
-
- if (userSwitchResult == null) {
- Log.w(TAG, "Timed out while switching user: " + TIMEOUT_MS + "ms");
- return false;
- }
- if (!userSwitchResult.isSuccess()) {
- Log.w(TAG, "Could not switch user: " + userSwitchResult);
- return false;
- }
-
- return true;
- }
-
- // TODO(b/161539497): Replace AsyncTask with standard {@link java.util.concurrent} code.
- private class AddNewUserTask extends AsyncTask<String, Void, UserInfo> {
-
- @Override
- protected UserInfo doInBackground(String... userNames) {
- AsyncFuture<UserCreationResult> future = mCarUserManager.createUser(userNames[0],
- /* flags= */ 0);
- try {
- UserInfo user = getUserInfo(future);
- if (user != null) {
- UserHelper.setDefaultNonAdminRestrictions(mContext, user,
- /* enable= */ true);
- UserHelper.assignDefaultIcon(mContext, user);
- mAddUserRecord = new UserRecord(user, UserRecord.ADD_USER);
- return user;
- } else {
- Log.e(TAG, "Failed to create user in the background");
- return user;
- }
- } catch (Exception e) {
- if (e instanceof InterruptedException) {
- Thread.currentThread().interrupt();
- }
- Log.e(TAG, "Error creating new user: ", e);
- }
- return null;
- }
-
- @Override
- protected void onPreExecute() {
- }
-
- @Override
- protected void onPostExecute(UserInfo user) {
- if (user != null) {
- notifyUserSelected(mAddUserRecord);
- mAddUserView.setEnabled(true);
- if (!switchUser(user.id)) {
- Log.e(TAG, "Failed to switch to new user: " + user.id);
- }
- }
- if (mAddUserView != null) {
- mAddUserView.setEnabled(true);
- }
- }
- }
-
- @Override
- public int getItemCount() {
- 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;
- public TextView mUserNameTextView;
- public View mView;
-
- public UserAdapterViewHolder(View view) {
- super(view);
- mView = view;
- mUserAvatarImageView = (ImageView) view.findViewById(R.id.user_avatar);
- mUserNameTextView = (TextView) view.findViewById(R.id.user_name);
- }
- }
- }
-
- /**
- * Object wrapper class for the userInfo. Use it to distinguish if a profile is a
- * guest profile, add user profile, or the foreground user.
- */
- public static final class UserRecord {
- public final UserInfo mInfo;
- public final @UserRecordType int mType;
-
- public static final int START_GUEST = 0;
- public static final int ADD_USER = 1;
- public static final int FOREGROUND_USER = 2;
- public static final int BACKGROUND_USER = 3;
-
- @IntDef({START_GUEST, ADD_USER, FOREGROUND_USER, BACKGROUND_USER})
- @Retention(RetentionPolicy.SOURCE)
- public @interface UserRecordType{}
-
- public UserRecord(@Nullable UserInfo userInfo, @UserRecordType int recordType) {
- mInfo = userInfo;
- mType = recordType;
- }
- }
-
- /**
- * Listener used to notify when a user has been selected
- */
- interface UserSelectionListener {
-
- void onUserSelected(UserRecord record);
- }
-
- /**
- * A {@link RecyclerView.ItemDecoration} that will add spacing between each item in the
- * RecyclerView that it is added to.
- */
- private static class ItemSpacingDecoration extends RecyclerView.ItemDecoration {
- private int mItemSpacing;
-
- private ItemSpacingDecoration(int itemSpacing) {
- mItemSpacing = itemSpacing;
- }
-
- @Override
- public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
- RecyclerView.State state) {
- super.getItemOffsets(outRect, view, parent, state);
- int position = parent.getChildAdapterPosition(view);
-
- // Skip offset for last item except for GridLayoutManager.
- if (position == state.getItemCount() - 1
- && !(parent.getLayoutManager() instanceof GridLayoutManager)) {
- return;
- }
-
- outRect.bottom = mItemSpacing;
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserIconProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserIconProvider.java
deleted file mode 100644
index dc5953e38ccb..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserIconProvider.java
+++ /dev/null
@@ -1,116 +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.car.userswitcher;
-
-import android.annotation.UserIdInt;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.os.UserManager;
-
-import androidx.core.graphics.drawable.RoundedBitmapDrawable;
-import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
-
-import com.android.internal.util.UserIcons;
-import com.android.systemui.R;
-
-/**
- * Simple class for providing icons for users.
- */
-public class UserIconProvider {
- /**
- * Gets a scaled rounded icon for the given user. If a user does not have an icon saved, this
- * method will default to a generic icon and update UserManager to use that icon.
- *
- * @param userInfo User for which the icon is requested.
- * @param context Context to use for resources
- * @return {@link RoundedBitmapDrawable} representing the icon for the user.
- */
- public RoundedBitmapDrawable getRoundedUserIcon(UserInfo userInfo, Context context) {
- UserManager userManager = UserManager.get(context);
- Resources res = context.getResources();
- Bitmap icon = userManager.getUserIcon(userInfo.id);
-
- if (icon == null) {
- icon = assignDefaultIcon(userManager, res, userInfo);
- }
-
- return createScaledRoundIcon(res, icon);
- }
-
- /** Returns a scaled, rounded, default icon for the Guest user */
- public RoundedBitmapDrawable getRoundedGuestDefaultIcon(Resources resources) {
- return createScaledRoundIcon(resources, getGuestUserDefaultIcon(resources));
- }
-
- private RoundedBitmapDrawable createScaledRoundIcon(Resources resources, Bitmap icon) {
- BitmapDrawable scaledIcon = scaleUserIcon(resources, icon);
- RoundedBitmapDrawable circleIcon =
- RoundedBitmapDrawableFactory.create(resources, scaledIcon.getBitmap());
- circleIcon.setCircular(true);
- return circleIcon;
- }
-
- /**
- * Returns a {@link Drawable} for the given {@code icon} scaled to the appropriate size.
- */
- private static BitmapDrawable scaleUserIcon(Resources res, Bitmap icon) {
- int desiredSize = res.getDimensionPixelSize(R.dimen.car_primary_icon_size);
- Bitmap scaledIcon =
- Bitmap.createScaledBitmap(icon, desiredSize, desiredSize, /*filter=*/ true);
- return new BitmapDrawable(res, scaledIcon);
- }
-
- /**
- * Assigns a default icon to a user according to the user's id. Handles Guest icon and non-guest
- * user icons.
- *
- * @param userManager {@link UserManager} to set user icon
- * @param resources {@link Resources} to grab icons from
- * @param userInfo User whose avatar is set to default icon.
- * @return Bitmap of the user icon.
- */
- public Bitmap assignDefaultIcon(
- UserManager userManager, Resources resources, UserInfo userInfo) {
- Bitmap bitmap = userInfo.isGuest()
- ? getGuestUserDefaultIcon(resources)
- : getUserDefaultIcon(resources, userInfo.id);
- userManager.setUserIcon(userInfo.id, bitmap);
- return bitmap;
- }
-
- /**
- * Gets a bitmap representing the user's default avatar.
- *
- * @param resources The resources to pull from
- * @param id The id of the user to get the icon for. Pass {@link UserHandle#USER_NULL} for
- * Guest user.
- * @return Default user icon
- */
- private Bitmap getUserDefaultIcon(Resources resources, @UserIdInt int id) {
- return UserIcons.convertToBitmap(
- UserIcons.getDefaultUserIcon(resources, id, /* light= */ false));
- }
-
- private Bitmap getGuestUserDefaultIcon(Resources resources) {
- return getUserDefaultIcon(resources, UserHandle.USER_NULL);
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
deleted file mode 100644
index 6178cbd3a599..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
+++ /dev/null
@@ -1,166 +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.car.userswitcher;
-
-import static android.car.settings.CarSettings.Global.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE;
-
-import android.annotation.UserIdInt;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.IWindowManager;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.settingslib.drawable.CircleFramedDrawable;
-import com.android.systemui.R;
-import com.android.systemui.car.window.OverlayViewController;
-import com.android.systemui.car.window.OverlayViewGlobalStateController;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-
-import javax.inject.Inject;
-
-/**
- * Handles showing and hiding UserSwitchTransitionView that is mounted to SystemUiOverlayWindow.
- */
-@SysUISingleton
-public class UserSwitchTransitionViewController extends OverlayViewController {
- private static final String TAG = "UserSwitchTransition";
- private static final String ENABLE_DEVELOPER_MESSAGE_TRUE = "true";
- private static final boolean DEBUG = false;
-
- private final Context mContext;
- private final Handler mHandler;
- private final Resources mResources;
- private final UserManager mUserManager;
- private final IWindowManager mWindowManagerService;
- private final int mWindowShownTimeoutMs;
- private final Runnable mWindowShownTimeoutCallback = () -> {
- if (DEBUG) {
- Log.w(TAG, "Window was not hidden within " + getWindowShownTimeoutMs() + " ms, so it"
- + "was hidden by mWindowShownTimeoutCallback.");
- }
-
- handleHide();
- };
-
- @GuardedBy("this")
- private boolean mShowing;
- private int mPreviousUserId = UserHandle.USER_NULL;
-
- @Inject
- public UserSwitchTransitionViewController(
- Context context,
- @Main Handler handler,
- @Main Resources resources,
- UserManager userManager,
- IWindowManager windowManagerService,
- OverlayViewGlobalStateController overlayViewGlobalStateController) {
-
- super(R.id.user_switching_dialog_stub, overlayViewGlobalStateController);
-
- mContext = context;
- mHandler = handler;
- mResources = resources;
- mUserManager = userManager;
- mWindowManagerService = windowManagerService;
- mWindowShownTimeoutMs = mResources.getInteger(
- R.integer.config_userSwitchTransitionViewShownTimeoutMs);
- }
-
- @Override
- protected int getInsetTypesToFit() {
- return 0;
- }
-
- /**
- * Makes the user switch transition view appear and draws the content inside of it if a user
- * that is different from the previous user is provided and if the dialog is not already
- * showing.
- */
- void handleShow(@UserIdInt int newUserId) {
- if (mPreviousUserId == newUserId || mShowing) return;
- mShowing = true;
- mHandler.post(() -> {
- try {
- mWindowManagerService.setSwitchingUser(true);
- mWindowManagerService.lockNow(null);
- } catch (RemoteException e) {
- Log.e(TAG, "unable to notify window manager service regarding user switch");
- }
-
- start();
- populateDialog(mPreviousUserId, newUserId);
- // next time a new user is selected, this current new user will be the previous user.
- mPreviousUserId = newUserId;
- // In case the window is still showing after WINDOW_SHOWN_TIMEOUT_MS, then hide the
- // window and log a warning message.
- mHandler.postDelayed(mWindowShownTimeoutCallback, mWindowShownTimeoutMs);
- });
- }
-
- void handleHide() {
- if (!mShowing) return;
- mShowing = false;
- mHandler.post(this::stop);
- mHandler.removeCallbacks(mWindowShownTimeoutCallback);
- }
-
- @VisibleForTesting
- int getWindowShownTimeoutMs() {
- return mWindowShownTimeoutMs;
- }
-
- private void populateDialog(@UserIdInt int previousUserId, @UserIdInt int newUserId) {
- drawUserIcon(newUserId);
- populateLoadingText(previousUserId, newUserId);
- }
-
- private void drawUserIcon(int newUserId) {
- Bitmap bitmap = mUserManager.getUserIcon(newUserId);
- if (bitmap != null) {
- CircleFramedDrawable drawable = CircleFramedDrawable.getInstance(mContext, bitmap);
- ((ImageView) getLayout().findViewById(R.id.user_loading_avatar))
- .setImageDrawable(drawable);
- }
- }
-
- private void populateLoadingText(@UserIdInt int previousUserId, @UserIdInt int newUserId) {
- TextView msgView = getLayout().findViewById(R.id.user_loading);
-
- boolean showInfo = ENABLE_DEVELOPER_MESSAGE_TRUE.equals(
- Settings.Global.getString(mContext.getContentResolver(),
- ENABLE_USER_SWITCH_DEVELOPER_MESSAGE));
-
- if (showInfo && mPreviousUserId != UserHandle.USER_NULL) {
- msgView.setText(
- mResources.getString(R.string.car_loading_profile_developer_message,
- previousUserId, newUserId));
- } else {
- msgView.setText(mResources.getString(R.string.car_loading_profile));
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
deleted file mode 100644
index 7db2823dc3b9..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java
+++ /dev/null
@@ -1,88 +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.car.userswitcher;
-
-import android.car.Car;
-import android.car.user.CarUserManager;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.window.OverlayViewMediator;
-
-import javax.inject.Inject;
-
-/**
- * Registers listeners that subscribe to events that show or hide CarUserSwitchingDialog that is
- * mounted to SystemUiOverlayWindow.
- */
-public class UserSwitchTransitionViewMediator implements OverlayViewMediator,
- CarUserManager.UserSwitchUiCallback {
- private static final String TAG = "UserSwitchTransitionViewMediator";
-
- private final CarServiceProvider mCarServiceProvider;
- private final CarDeviceProvisionedController mCarDeviceProvisionedController;
- private final UserSwitchTransitionViewController mUserSwitchTransitionViewController;
-
- @Inject
- public UserSwitchTransitionViewMediator(
- CarServiceProvider carServiceProvider,
- CarDeviceProvisionedController carDeviceProvisionedController,
- UserSwitchTransitionViewController userSwitchTransitionViewController) {
- mCarServiceProvider = carServiceProvider;
- mCarDeviceProvisionedController = carDeviceProvisionedController;
- mUserSwitchTransitionViewController = userSwitchTransitionViewController;
- }
-
- @Override
- public void registerListeners() {
- mCarServiceProvider.addListener(car -> {
- CarUserManager carUserManager =
- (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
-
- if (carUserManager != null) {
- carUserManager.setUserSwitchUiCallback(this);
- carUserManager.addListener(Runnable::run, this::handleUserLifecycleEvent);
- } else {
- Log.e(TAG, "registerListeners: CarUserManager could not be obtained.");
- }
- });
- }
-
- @Override
- public void setupOverlayContentViewControllers() {
- // no-op.
- }
-
- @Override
- public void showUserSwitchDialog(int userId) {
- mUserSwitchTransitionViewController.handleShow(userId);
- }
-
- @VisibleForTesting
- void handleUserLifecycleEvent(CarUserManager.UserLifecycleEvent event) {
- if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING
- && mCarDeviceProvisionedController.getCurrentUser() == event.getUserId()) {
- mUserSwitchTransitionViewController.handleShow(event.getUserId());
- }
-
- if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
- mUserSwitchTransitionViewController.handleHide();
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifier.java b/packages/CarSystemUI/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifier.java
deleted file mode 100644
index c054d204af98..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifier.java
+++ /dev/null
@@ -1,95 +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.car.voicerecognition;
-
-import android.bluetooth.BluetoothHeadsetClient;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
-import com.android.systemui.SysUIToast;
-import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.qualifiers.Main;
-
-import javax.inject.Inject;
-
-/**
- * Controller responsible for showing toast message when voice recognition over bluetooth device
- * getting activated.
- */
-public class ConnectedDeviceVoiceRecognitionNotifier extends SystemUI {
-
- private static final String TAG = "CarVoiceRecognition";
- @VisibleForTesting
- static final int INVALID_VALUE = -1;
- @VisibleForTesting
- static final int VOICE_RECOGNITION_STARTED = 1;
-
- private Handler mHandler;
-
- private final BroadcastReceiver mVoiceRecognitionReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Voice recognition received an intent!");
- }
- if (intent == null
- || intent.getAction() == null
- || !BluetoothHeadsetClient.ACTION_AG_EVENT.equals(intent.getAction())
- || !intent.hasExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION)) {
- return;
- }
-
- int voiceRecognitionState = intent.getIntExtra(
- BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, INVALID_VALUE);
-
- if (voiceRecognitionState == VOICE_RECOGNITION_STARTED) {
- showToastMessage();
- }
- }
- };
-
- private void showToastMessage() {
- mHandler.post(() -> SysUIToast.makeText(mContext, R.string.voice_recognition_toast,
- Toast.LENGTH_LONG).show());
- }
-
- @Inject
- public ConnectedDeviceVoiceRecognitionNotifier(Context context, @Main Handler handler) {
- super(context);
- mHandler = handler;
- }
-
- @Override
- public void start() {
- }
-
- @Override
- protected void onBootCompleted() {
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT);
- mContext.registerReceiverAsUser(mVoiceRecognitionReceiver, UserHandle.ALL, filter,
- /* broadcastPermission= */ null, /* scheduler= */ null);
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogComponent.java b/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogComponent.java
deleted file mode 100644
index 4cdbfa3236c8..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogComponent.java
+++ /dev/null
@@ -1,54 +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.car.volume;
-
-import android.content.Context;
-
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.demomode.DemoModeController;
-import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.plugins.VolumeDialog;
-import com.android.systemui.volume.VolumeDialogComponent;
-import com.android.systemui.volume.VolumeDialogControllerImpl;
-
-import javax.inject.Inject;
-
-/**
- * Allows for adding car specific dialog when the volume dialog is created.
- */
-@SysUISingleton
-public class CarVolumeDialogComponent extends VolumeDialogComponent {
-
- private CarVolumeDialogImpl mCarVolumeDialog;
-
- @Inject
- public CarVolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator,
- VolumeDialogControllerImpl volumeDialogController,
- DemoModeController demoModeController,
- CarServiceProvider carServiceProvider) {
- super(context, keyguardViewMediator, volumeDialogController, demoModeController);
- mCarVolumeDialog.setCarServiceProvider(carServiceProvider);
- }
-
- /** This method is called while calling the super constructor. */
- @Override
- protected VolumeDialog createDefault() {
- mCarVolumeDialog = new CarVolumeDialogImpl(mContext);
- return mCarVolumeDialog;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogImpl.java
deleted file mode 100644
index 12818840af9a..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogImpl.java
+++ /dev/null
@@ -1,658 +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.car.volume;
-
-import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.animation.AnimatorSet;
-import android.annotation.DrawableRes;
-import android.annotation.Nullable;
-import android.app.Dialog;
-import android.app.KeyguardManager;
-import android.car.Car;
-import android.car.media.CarAudioManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.os.Debug;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.UserHandle;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.Xml;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
-
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.systemui.R;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.plugins.VolumeDialog;
-import com.android.systemui.volume.Events;
-import com.android.systemui.volume.SystemUIInterpolators;
-import com.android.systemui.volume.VolumeDialogImpl;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Car version of the volume dialog.
- *
- * Methods ending in "H" must be called on the (ui) handler.
- */
-public class CarVolumeDialogImpl implements VolumeDialog {
-
- private static final String TAG = "CarVolumeDialog";
- private static final boolean DEBUG = false;
-
- private static final String XML_TAG_VOLUME_ITEMS = "carVolumeItems";
- private static final String XML_TAG_VOLUME_ITEM = "item";
- private static final int LISTVIEW_ANIMATION_DURATION_IN_MILLIS = 250;
- private static final int DISMISS_DELAY_IN_MILLIS = 50;
- private static final int ARROW_FADE_IN_START_DELAY_IN_MILLIS = 100;
-
- private final Context mContext;
- private final H mHandler = new H();
- // All the volume items.
- private final SparseArray<VolumeItem> mVolumeItems = new SparseArray<>();
- // Available volume items in car audio manager.
- private final List<VolumeItem> mAvailableVolumeItems = new ArrayList<>();
- // Volume items in the RecyclerView.
- private final List<CarVolumeItem> mCarVolumeLineItems = new ArrayList<>();
- private final KeyguardManager mKeyguard;
- private final int mNormalTimeout;
- private final int mHoveringTimeout;
- private final int mExpNormalTimeout;
- private final int mExpHoveringTimeout;
-
- private Window mWindow;
- private CustomDialog mDialog;
- private RecyclerView mListView;
- private CarVolumeItemAdapter mVolumeItemsAdapter;
- private CarAudioManager mCarAudioManager;
- private boolean mHovering;
- private int mCurrentlyDisplayingGroupId;
- private int mPreviouslyDisplayingGroupId;
- private boolean mShowing;
- private boolean mDismissing;
- private boolean mExpanded;
- private View mExpandIcon;
-
- private final CarAudioManager.CarVolumeCallback mVolumeChangeCallback =
- new CarAudioManager.CarVolumeCallback() {
- @Override
- public void onGroupVolumeChanged(int zoneId, int groupId, int flags) {
- // TODO: Include zoneId into consideration.
- // For instance
- // - single display + single-zone, ignore zoneId
- // - multi-display + single-zone, zoneId is fixed, may show volume bar on all
- // displays
- // - single-display + multi-zone, may show volume bar on primary display only
- // - multi-display + multi-zone, may show volume bar on display specified by
- // zoneId
- VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
- int value = getSeekbarValue(mCarAudioManager, groupId);
- // find if the group id for which the volume changed is currently being
- // displayed.
- boolean isShowing = mCarVolumeLineItems.stream().anyMatch(
- item -> item.getGroupId() == groupId);
- // Do not update the progress if it is the same as before. When car audio
- // manager sets
- // its group volume caused by the seekbar progress changed, it also triggers
- // this
- // callback. Updating the seekbar at the same time could block the continuous
- // seeking.
- if (value != volumeItem.mProgress && isShowing) {
- volumeItem.mCarVolumeItem.setProgress(value);
- volumeItem.mProgress = value;
- }
- if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
- mPreviouslyDisplayingGroupId = mCurrentlyDisplayingGroupId;
- mCurrentlyDisplayingGroupId = groupId;
- mHandler.obtainMessage(H.SHOW,
- Events.SHOW_REASON_VOLUME_CHANGED).sendToTarget();
- }
- }
-
- @Override
- public void onMasterMuteChanged(int zoneId, int flags) {
- // ignored
- }
- };
-
- private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceOnConnectedListener =
- car -> {
- mExpanded = false;
- mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
- int volumeGroupCount = mCarAudioManager.getVolumeGroupCount();
- // Populates volume slider items from volume groups to UI.
- for (int groupId = 0; groupId < volumeGroupCount; groupId++) {
- VolumeItem volumeItem = getVolumeItemForUsages(
- mCarAudioManager.getUsagesForVolumeGroupId(groupId));
- mAvailableVolumeItems.add(volumeItem);
- // The first one is the default item.
- if (groupId == 0) {
- clearAllAndSetupDefaultCarVolumeLineItem(0);
- }
- }
-
- // If list is already initiated, update its content.
- if (mVolumeItemsAdapter != null) {
- mVolumeItemsAdapter.notifyDataSetChanged();
- }
- mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
- };
-
- private final BroadcastReceiver mHomeButtonPressedBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
- return;
- }
-
- dismissH(Events.DISMISS_REASON_VOLUME_CONTROLLER);
- }
- };
-
- public CarVolumeDialogImpl(Context context) {
- mContext = context;
- mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- mNormalTimeout = mContext.getResources().getInteger(
- R.integer.car_volume_dialog_display_normal_timeout);
- mHoveringTimeout = mContext.getResources().getInteger(
- R.integer.car_volume_dialog_display_hovering_timeout);
- mExpNormalTimeout = mContext.getResources().getInteger(
- R.integer.car_volume_dialog_display_expanded_normal_timeout);
- mExpHoveringTimeout = mContext.getResources().getInteger(
- R.integer.car_volume_dialog_display_expanded_hovering_timeout);
- }
-
- /** Sets a {@link CarServiceProvider} which connects to the audio service. */
- public void setCarServiceProvider(CarServiceProvider carServiceProvider) {
- carServiceProvider.addListener(mCarServiceOnConnectedListener);
- }
-
- private static int getSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) {
- return carAudioManager.getGroupVolume(volumeGroupId);
- }
-
- private static int getMaxSeekbarValue(CarAudioManager carAudioManager, int volumeGroupId) {
- return carAudioManager.getGroupMaxVolume(volumeGroupId);
- }
-
- /**
- * Build the volume window and connect to the CarService which registers with car audio
- * manager.
- */
- @Override
- public void init(int windowType, Callback callback) {
- initDialog();
-
- mContext.registerReceiverAsUser(mHomeButtonPressedBroadcastReceiver, UserHandle.CURRENT,
- new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), /* broadcastPermission= */
- null, /* scheduler= */ null);
- }
-
- @Override
- public void destroy() {
- mHandler.removeCallbacksAndMessages(/* token= */ null);
-
- mContext.unregisterReceiver(mHomeButtonPressedBroadcastReceiver);
-
- cleanupAudioManager();
- }
-
- /**
- * Reveals volume dialog.
- */
- public void show(int reason) {
- mHandler.obtainMessage(H.SHOW, reason).sendToTarget();
- }
-
- /**
- * Hides volume dialog.
- */
- public void dismiss(int reason) {
- mHandler.obtainMessage(H.DISMISS, reason).sendToTarget();
- }
-
- private void initDialog() {
- loadAudioUsageItems();
- mCarVolumeLineItems.clear();
- mDialog = new CustomDialog(mContext);
-
- mHovering = false;
- mShowing = false;
- mDismissing = false;
- mExpanded = false;
- mWindow = mDialog.getWindow();
- mWindow.requestFeature(Window.FEATURE_NO_TITLE);
- mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
- mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
- | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
- mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
- mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
- mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
- final WindowManager.LayoutParams lp = mWindow.getAttributes();
- lp.format = PixelFormat.TRANSLUCENT;
- lp.setTitle(VolumeDialogImpl.class.getSimpleName());
- lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
- lp.windowAnimations = -1;
- mWindow.setAttributes(lp);
-
- mDialog.setContentView(R.layout.car_volume_dialog);
- mWindow.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-
- mDialog.setCanceledOnTouchOutside(true);
- mDialog.setOnShowListener(dialog -> {
- mListView.setTranslationY(-mListView.getHeight());
- mListView.setAlpha(0);
- mListView.animate()
- .alpha(1)
- .translationY(0)
- .setDuration(LISTVIEW_ANIMATION_DURATION_IN_MILLIS)
- .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
- .start();
- });
- mListView = mWindow.findViewById(R.id.volume_list);
- mListView.setOnHoverListener((v, event) -> {
- int action = event.getActionMasked();
- mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
- || (action == MotionEvent.ACTION_HOVER_MOVE);
- rescheduleTimeoutH();
- return true;
- });
-
- mVolumeItemsAdapter = new CarVolumeItemAdapter(mContext, mCarVolumeLineItems);
- mListView.setAdapter(mVolumeItemsAdapter);
- mListView.setLayoutManager(new LinearLayoutManager(mContext));
- }
-
-
- private void showH(int reason) {
- if (DEBUG) {
- Log.d(TAG, "showH r=" + Events.DISMISS_REASONS[reason]);
- }
-
- mHandler.removeMessages(H.SHOW);
- mHandler.removeMessages(H.DISMISS);
-
- rescheduleTimeoutH();
-
- // Refresh the data set before showing.
- mVolumeItemsAdapter.notifyDataSetChanged();
-
- if (mShowing) {
- if (mPreviouslyDisplayingGroupId == mCurrentlyDisplayingGroupId || mExpanded) {
- return;
- }
-
- clearAllAndSetupDefaultCarVolumeLineItem(mCurrentlyDisplayingGroupId);
- return;
- }
-
- mShowing = true;
- clearAllAndSetupDefaultCarVolumeLineItem(mCurrentlyDisplayingGroupId);
- mDialog.show();
- Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
- }
-
- private void clearAllAndSetupDefaultCarVolumeLineItem(int groupId) {
- mCarVolumeLineItems.clear();
- VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
- volumeItem.mDefaultItem = true;
- addCarVolumeListItem(volumeItem, /* volumeGroupId = */ groupId,
- R.drawable.car_ic_keyboard_arrow_down, new ExpandIconListener());
- }
-
- protected void rescheduleTimeoutH() {
- mHandler.removeMessages(H.DISMISS);
- final int timeout = computeTimeoutH();
- mHandler.sendMessageDelayed(mHandler
- .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT), timeout);
-
- if (DEBUG) {
- Log.d(TAG, "rescheduleTimeout " + timeout + " " + Debug.getCaller());
- }
- }
-
- private int computeTimeoutH() {
- if (mExpanded) {
- return mHovering ? mExpHoveringTimeout : mExpNormalTimeout;
- } else {
- return mHovering ? mHoveringTimeout : mNormalTimeout;
- }
- }
-
- private void dismissH(int reason) {
- if (DEBUG) {
- Log.d(TAG, "dismissH r=" + Events.DISMISS_REASONS[reason]);
- }
-
- mHandler.removeMessages(H.DISMISS);
- mHandler.removeMessages(H.SHOW);
- if (!mShowing || mDismissing) {
- return;
- }
-
- mDismissing = true;
- mListView.animate()
- .alpha(0)
- .translationY(-mListView.getHeight())
- .setDuration(LISTVIEW_ANIMATION_DURATION_IN_MILLIS)
- .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
- .withEndAction(() -> mHandler.postDelayed(() -> {
- if (DEBUG) {
- Log.d(TAG, "mDialog.dismiss()");
- }
- mDialog.dismiss();
- mShowing = false;
- mDismissing = false;
- // if mExpandIcon is null that means user never clicked on the expanded arrow
- // which implies that the dialog is still not expanded. In that case we do
- // not want to reset the state
- if (mExpandIcon != null && mExpanded) {
- toggleDialogExpansion(/* isClicked = */ false);
- }
- }, DISMISS_DELAY_IN_MILLIS))
- .start();
-
- Events.writeEvent(Events.EVENT_DISMISS_DIALOG, reason);
- }
-
- private void loadAudioUsageItems() {
- try (XmlResourceParser parser = mContext.getResources().getXml(R.xml.car_volume_items)) {
- AttributeSet attrs = Xml.asAttributeSet(parser);
- int type;
- // Traverse to the first start tag
- while ((type = parser.next()) != XmlResourceParser.END_DOCUMENT
- && type != XmlResourceParser.START_TAG) {
- // Do Nothing (moving parser to start element)
- }
-
- if (!XML_TAG_VOLUME_ITEMS.equals(parser.getName())) {
- throw new RuntimeException("Meta-data does not start with carVolumeItems tag");
- }
- int outerDepth = parser.getDepth();
- int rank = 0;
- while ((type = parser.next()) != XmlResourceParser.END_DOCUMENT
- && (type != XmlResourceParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlResourceParser.END_TAG) {
- continue;
- }
- if (XML_TAG_VOLUME_ITEM.equals(parser.getName())) {
- TypedArray item = mContext.getResources().obtainAttributes(
- attrs, R.styleable.carVolumeItems_item);
- int usage = item.getInt(R.styleable.carVolumeItems_item_usage,
- /* defValue= */ -1);
- if (usage >= 0) {
- VolumeItem volumeItem = new VolumeItem();
- volumeItem.mRank = rank;
- volumeItem.mIcon = item.getResourceId(
- R.styleable.carVolumeItems_item_icon, /* defValue= */ 0);
- mVolumeItems.put(usage, volumeItem);
- rank++;
- }
- item.recycle();
- }
- }
- } catch (XmlPullParserException | IOException e) {
- Log.e(TAG, "Error parsing volume groups configuration", e);
- }
- }
-
- private VolumeItem getVolumeItemForUsages(int[] usages) {
- int rank = Integer.MAX_VALUE;
- VolumeItem result = null;
- for (int usage : usages) {
- VolumeItem volumeItem = mVolumeItems.get(usage);
- if (volumeItem.mRank < rank) {
- rank = volumeItem.mRank;
- result = volumeItem;
- }
- }
- return result;
- }
-
- private CarVolumeItem createCarVolumeListItem(VolumeItem volumeItem, int volumeGroupId,
- Drawable supplementalIcon, int seekbarProgressValue,
- @Nullable View.OnClickListener supplementalIconOnClickListener) {
- CarVolumeItem carVolumeItem = new CarVolumeItem();
- carVolumeItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId));
- carVolumeItem.setProgress(seekbarProgressValue);
- carVolumeItem.setOnSeekBarChangeListener(
- new CarVolumeDialogImpl.VolumeSeekBarChangeListener(volumeGroupId,
- mCarAudioManager));
- carVolumeItem.setGroupId(volumeGroupId);
-
- int color = mContext.getColor(R.color.car_volume_dialog_tint);
- Drawable primaryIcon = mContext.getDrawable(volumeItem.mIcon);
- primaryIcon.mutate().setTint(color);
- carVolumeItem.setPrimaryIcon(primaryIcon);
- if (supplementalIcon != null) {
- supplementalIcon.mutate().setTint(color);
- carVolumeItem.setSupplementalIcon(supplementalIcon,
- /* showSupplementalIconDivider= */ true);
- carVolumeItem.setSupplementalIconListener(supplementalIconOnClickListener);
- } else {
- carVolumeItem.setSupplementalIcon(/* drawable= */ null,
- /* showSupplementalIconDivider= */ false);
- }
-
- volumeItem.mCarVolumeItem = carVolumeItem;
- volumeItem.mProgress = seekbarProgressValue;
-
- return carVolumeItem;
- }
-
- private CarVolumeItem addCarVolumeListItem(VolumeItem volumeItem, int volumeGroupId,
- int supplementalIconId,
- @Nullable View.OnClickListener supplementalIconOnClickListener) {
- int seekbarProgressValue = getSeekbarValue(mCarAudioManager, volumeGroupId);
- Drawable supplementalIcon = supplementalIconId == 0 ? null : mContext.getDrawable(
- supplementalIconId);
- CarVolumeItem carVolumeItem = createCarVolumeListItem(volumeItem, volumeGroupId,
- supplementalIcon, seekbarProgressValue, supplementalIconOnClickListener);
- mCarVolumeLineItems.add(carVolumeItem);
- return carVolumeItem;
- }
-
- private void cleanupAudioManager() {
- mCarAudioManager.unregisterCarVolumeCallback(mVolumeChangeCallback);
- mCarVolumeLineItems.clear();
- mCarAudioManager = null;
- }
-
- /**
- * Wrapper class which contains information of each volume group.
- */
- private static class VolumeItem {
- private int mRank;
- private boolean mDefaultItem = false;
- @DrawableRes
- private int mIcon;
- private CarVolumeItem mCarVolumeItem;
- private int mProgress;
- }
-
- private final class H extends Handler {
-
- private static final int SHOW = 1;
- private static final int DISMISS = 2;
-
- private H() {
- super(Looper.getMainLooper());
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case SHOW:
- showH(msg.arg1);
- break;
- case DISMISS:
- dismissH(msg.arg1);
- break;
- default:
- }
- }
- }
-
- private final class CustomDialog extends Dialog implements DialogInterface {
-
- private CustomDialog(Context context) {
- super(context, com.android.systemui.R.style.qs_theme);
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- rescheduleTimeoutH();
- return super.dispatchTouchEvent(ev);
- }
-
- @Override
- protected void onStart() {
- super.setCanceledOnTouchOutside(true);
- super.onStart();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (isShowing()) {
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- mHandler.obtainMessage(
- H.DISMISS, Events.DISMISS_REASON_TOUCH_OUTSIDE).sendToTarget();
- return true;
- }
- }
- return false;
- }
- }
-
- private final class ExpandIconListener implements View.OnClickListener {
- @Override
- public void onClick(final View v) {
- mExpandIcon = v;
- toggleDialogExpansion(true);
- rescheduleTimeoutH();
- }
- }
-
- private void toggleDialogExpansion(boolean isClicked) {
- mExpanded = !mExpanded;
- Animator inAnimator;
- if (mExpanded) {
- for (int groupId = 0; groupId < mAvailableVolumeItems.size(); ++groupId) {
- if (groupId != mCurrentlyDisplayingGroupId) {
- VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
- addCarVolumeListItem(volumeItem, groupId, /* supplementalIconId= */ 0,
- /* supplementalIconOnClickListener= */ null);
- }
- }
- inAnimator = AnimatorInflater.loadAnimator(
- mContext, R.anim.car_arrow_fade_in_rotate_up);
-
- } else {
- clearAllAndSetupDefaultCarVolumeLineItem(mCurrentlyDisplayingGroupId);
- inAnimator = AnimatorInflater.loadAnimator(
- mContext, R.anim.car_arrow_fade_in_rotate_down);
- }
-
- Animator outAnimator = AnimatorInflater.loadAnimator(
- mContext, R.anim.car_arrow_fade_out);
- inAnimator.setStartDelay(ARROW_FADE_IN_START_DELAY_IN_MILLIS);
- AnimatorSet animators = new AnimatorSet();
- animators.playTogether(outAnimator, inAnimator);
- if (!isClicked) {
- // Do not animate when the state is called to reset the dialogs view and not clicked
- // by user.
- animators.setDuration(0);
- }
- animators.setTarget(mExpandIcon);
- animators.start();
- mVolumeItemsAdapter.notifyDataSetChanged();
- }
-
- private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
-
- private final int mVolumeGroupId;
- private final CarAudioManager mCarAudioManager;
-
- private VolumeSeekBarChangeListener(int volumeGroupId, CarAudioManager carAudioManager) {
- mVolumeGroupId = volumeGroupId;
- mCarAudioManager = carAudioManager;
- }
-
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (!fromUser) {
- // For instance, if this event is originated from AudioService,
- // we can ignore it as it has already been handled and doesn't need to be
- // sent back down again.
- return;
- }
- if (mCarAudioManager == null) {
- Log.w(TAG, "Ignoring volume change event because the car isn't connected");
- return;
- }
- mAvailableVolumeItems.get(mVolumeGroupId).mProgress = progress;
- mAvailableVolumeItems.get(
- mVolumeGroupId).mCarVolumeItem.setProgress(progress);
- mCarAudioManager.setGroupVolume(mVolumeGroupId, progress, 0);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeItem.java b/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeItem.java
deleted file mode 100644
index 1e7e5348b7fa..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeItem.java
+++ /dev/null
@@ -1,135 +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.car.volume;
-
-import android.graphics.drawable.Drawable;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.SeekBar;
-
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.systemui.R;
-
-/** Holds all related data to represent a volume group. */
-public class CarVolumeItem {
-
- private Drawable mPrimaryIcon;
- private Drawable mSupplementalIcon;
- private View.OnClickListener mSupplementalIconOnClickListener;
- private boolean mShowSupplementalIconDivider;
- private int mGroupId;
-
- private int mMax;
- private int mProgress;
- private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener;
-
- /**
- * Called when {@link CarVolumeItem} is bound to its ViewHolder.
- */
- void bind(CarVolumeItemViewHolder viewHolder) {
- viewHolder.bind(/* carVolumeItem= */ this);
- }
-
- /** Sets progress of seekbar. */
- public void setProgress(int progress) {
- mProgress = progress;
- }
-
- /** Sets max value of seekbar. */
- public void setMax(int max) {
- mMax = max;
- }
-
- /** Sets {@link SeekBar.OnSeekBarChangeListener}. */
- public void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) {
- mOnSeekBarChangeListener = listener;
- }
-
- /** Sets the primary icon. */
- public void setPrimaryIcon(Drawable drawable) {
- mPrimaryIcon = drawable;
- }
-
- /** Sets the supplemental icon and the visibility of the supplemental icon divider. */
- public void setSupplementalIcon(Drawable drawable, boolean showSupplementalIconDivider) {
- mSupplementalIcon = drawable;
- mShowSupplementalIconDivider = showSupplementalIconDivider;
- }
-
- /**
- * Gets the group id associated.
- */
- public int getGroupId() {
- return mGroupId;
- }
-
- /**
- * Sets the group id associated.
- */
- public void setGroupId(int groupId) {
- this.mGroupId = groupId;
- }
-
- /** Sets {@code OnClickListener} for the supplemental icon. */
- public void setSupplementalIconListener(View.OnClickListener listener) {
- mSupplementalIconOnClickListener = listener;
- }
-
- /** Defines the view holder which shows the information held by {@link CarVolumeItem}. */
- public static class CarVolumeItemViewHolder extends RecyclerView.ViewHolder {
-
- private SeekBar mSeekBar;
- private ImageView mPrimaryIcon;
- private View mSupplementalIconDivider;
- private ImageView mSupplementalIcon;
-
- public CarVolumeItemViewHolder(@NonNull View itemView) {
- super(itemView);
-
- mSeekBar = itemView.findViewById(R.id.seek_bar);
- mPrimaryIcon = itemView.findViewById(R.id.primary_icon);
- mSupplementalIcon = itemView.findViewById(R.id.supplemental_icon);
- mSupplementalIconDivider = itemView.findViewById(R.id.supplemental_icon_divider);
- }
-
- /**
- * Binds {@link CarVolumeItem} to the {@link CarVolumeItemViewHolder}.
- */
- void bind(CarVolumeItem carVolumeItem) {
- // Progress bar
- mSeekBar.setMax(carVolumeItem.mMax);
- mSeekBar.setProgress(carVolumeItem.mProgress);
- mSeekBar.setOnSeekBarChangeListener(carVolumeItem.mOnSeekBarChangeListener);
-
- // Primary icon
- mPrimaryIcon.setVisibility(View.VISIBLE);
- mPrimaryIcon.setImageDrawable(carVolumeItem.mPrimaryIcon);
-
- // Supplemental icon
- mSupplementalIcon.setVisibility(View.VISIBLE);
- mSupplementalIconDivider.setVisibility(
- carVolumeItem.mShowSupplementalIconDivider ? View.VISIBLE : View.INVISIBLE);
- mSupplementalIcon.setImageDrawable(carVolumeItem.mSupplementalIcon);
- mSupplementalIcon.setOnClickListener(
- carVolumeItem.mSupplementalIconOnClickListener);
- mSupplementalIcon.setClickable(
- carVolumeItem.mSupplementalIconOnClickListener != null);
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeItemAdapter.java b/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeItemAdapter.java
deleted file mode 100644
index 7f336b5250a7..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeItemAdapter.java
+++ /dev/null
@@ -1,59 +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.car.volume;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.systemui.R;
-
-import java.util.List;
-
-/** The {@link RecyclerView.Adapter} to show the volume items in the sysUI volume dialog. */
-public class CarVolumeItemAdapter extends
- RecyclerView.Adapter<CarVolumeItem.CarVolumeItemViewHolder> {
-
- private final Context mContext;
- private final List<CarVolumeItem> mItems;
-
- public CarVolumeItemAdapter(Context context, List<CarVolumeItem> items) {
- mContext = context;
- mItems = items;
- }
-
- @Override
- public CarVolumeItem.CarVolumeItemViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
- LayoutInflater inflater = LayoutInflater.from(mContext);
- View view = inflater.inflate(R.layout.car_volume_item, parent, false);
- return new CarVolumeItem.CarVolumeItemViewHolder(view);
- }
-
- @Override
- public void onBindViewHolder(CarVolumeItem.CarVolumeItemViewHolder holder, int position) {
- mItems.get(position).bind(holder);
- }
-
- @Override
- public int getItemCount() {
- return mItems.size();
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/volume/VolumeUI.java b/packages/CarSystemUI/src/com/android/systemui/car/volume/VolumeUI.java
deleted file mode 100644
index b0321abfedd4..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/volume/VolumeUI.java
+++ /dev/null
@@ -1,129 +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.car.volume;
-
-import android.car.Car;
-import android.car.media.CarAudioManager;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.util.Log;
-
-import com.android.systemui.R;
-import com.android.systemui.SystemUI;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.volume.VolumeDialogComponent;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-import javax.inject.Inject;
-
-import dagger.Lazy;
-
-/** The entry point for controlling the volume ui in cars. */
-@SysUISingleton
-public class VolumeUI extends SystemUI {
-
- private static final String TAG = "VolumeUI";
- private final Resources mResources;
- private final Handler mMainHandler;
- private final CarServiceProvider mCarServiceProvider;
- private final Lazy<VolumeDialogComponent> mVolumeDialogComponentLazy;
-
- private final CarAudioManager.CarVolumeCallback mVolumeChangeCallback =
- new CarAudioManager.CarVolumeCallback() {
- @Override
- public void onGroupVolumeChanged(int zoneId, int groupId, int flags) {
- initVolumeDialogComponent();
- }
-
- @Override
- public void onMasterMuteChanged(int zoneId, int flags) {
- initVolumeDialogComponent();
- }
-
- private void initVolumeDialogComponent() {
- if (mVolumeDialogComponent == null) {
- mMainHandler.post(() -> {
- mVolumeDialogComponent = mVolumeDialogComponentLazy.get();
- mVolumeDialogComponent.register();
- });
- mCarAudioManager.unregisterCarVolumeCallback(mVolumeChangeCallback);
- }
- }
- };
-
- private boolean mEnabled;
- private CarAudioManager mCarAudioManager;
- private VolumeDialogComponent mVolumeDialogComponent;
-
- @Inject
- public VolumeUI(
- Context context,
- @Main Resources resources,
- @Main Handler mainHandler,
- CarServiceProvider carServiceProvider,
- Lazy<VolumeDialogComponent> volumeDialogComponentLazy
- ) {
- super(context);
- mResources = resources;
- mMainHandler = mainHandler;
- mCarServiceProvider = carServiceProvider;
- mVolumeDialogComponentLazy = volumeDialogComponentLazy;
- }
-
- @Override
- public void start() {
- boolean enableVolumeUi = mResources.getBoolean(R.bool.enable_volume_ui);
- mEnabled = enableVolumeUi;
- if (!mEnabled) return;
-
- mCarServiceProvider.addListener(car -> {
- if (mCarAudioManager != null) {
- return;
- }
-
- mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE);
- Log.d(TAG, "Registering mVolumeChangeCallback.");
- // This volume call back is never unregistered because CarStatusBar is
- // never destroyed.
- mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
- });
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (!mEnabled) return;
- if (mVolumeDialogComponent != null) {
- mVolumeDialogComponent.onConfigurationChanged(newConfig);
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.print("mEnabled="); pw.println(mEnabled);
- if (!mEnabled) return;
- if (mVolumeDialogComponent != null) {
- mVolumeDialogComponent.dump(fd, pw, args);
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
deleted file mode 100644
index 44cb5cf9cb54..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
+++ /dev/null
@@ -1,685 +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.car.window;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.IntDef;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewTreeObserver;
-
-import androidx.annotation.CallSuper;
-
-import com.android.systemui.R;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.wm.shell.animation.FlingAnimationUtils;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * The {@link OverlayPanelViewController} provides additional dragging animation capabilities to
- * {@link OverlayViewController}.
- */
-public abstract class OverlayPanelViewController extends OverlayViewController {
-
- /** @hide */
- @IntDef(flag = true, prefix = { "OVERLAY_" }, value = {
- OVERLAY_FROM_TOP_BAR,
- OVERLAY_FROM_BOTTOM_BAR
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface OverlayDirection {}
-
- /**
- * Indicates that the overlay panel should be opened from the top bar and expanded by dragging
- * towards the bottom bar.
- */
- public static final int OVERLAY_FROM_TOP_BAR = 0;
-
- /**
- * Indicates that the overlay panel should be opened from the bottom bar and expanded by
- * dragging towards the top bar.
- */
- public static final int OVERLAY_FROM_BOTTOM_BAR = 1;
-
- private static final boolean DEBUG = false;
- private static final String TAG = "OverlayPanelViewController";
-
- // used to calculate how fast to open or close the window
- protected static final float DEFAULT_FLING_VELOCITY = 0;
- // max time a fling animation takes
- protected static final float FLING_ANIMATION_MAX_TIME = 0.5f;
- // acceleration rate for the fling animation
- protected static final float FLING_SPEED_UP_FACTOR = 0.6f;
-
- protected static final int SWIPE_DOWN_MIN_DISTANCE = 25;
- protected static final int SWIPE_MAX_OFF_PATH = 75;
- protected static final int SWIPE_THRESHOLD_VELOCITY = 200;
- private static final int POSITIVE_DIRECTION = 1;
- private static final int NEGATIVE_DIRECTION = -1;
-
- private final FlingAnimationUtils mFlingAnimationUtils;
- private final CarDeviceProvisionedController mCarDeviceProvisionedController;
- private final View.OnTouchListener mDragOpenTouchListener;
- private final View.OnTouchListener mDragCloseTouchListener;
-
- protected int mAnimateDirection = POSITIVE_DIRECTION;
-
- private final int mSettleClosePercentage;
- private int mPercentageFromEndingEdge;
-
- private boolean mPanelVisible;
- private boolean mPanelExpanded;
-
- private float mOpeningVelocity = DEFAULT_FLING_VELOCITY;
- private float mClosingVelocity = DEFAULT_FLING_VELOCITY;
-
- private boolean mIsAnimating;
- private boolean mIsTracking;
-
- public OverlayPanelViewController(
- Context context,
- @Main Resources resources,
- int stubId,
- OverlayViewGlobalStateController overlayViewGlobalStateController,
- FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
- CarDeviceProvisionedController carDeviceProvisionedController
- ) {
- super(stubId, overlayViewGlobalStateController);
-
- mFlingAnimationUtils = flingAnimationUtilsBuilder
- .setMaxLengthSeconds(FLING_ANIMATION_MAX_TIME)
- .setSpeedUpFactor(FLING_SPEED_UP_FACTOR)
- .build();
- mCarDeviceProvisionedController = carDeviceProvisionedController;
-
- mSettleClosePercentage = resources.getInteger(
- R.integer.notification_settle_close_percentage);
-
- // Attached to a navigation bar to open the overlay panel
- GestureDetector openGestureDetector = new GestureDetector(context,
- new OpenGestureListener() {
- @Override
- protected void open() {
- animateExpandPanel();
- }
- });
-
- // Attached to the other navigation bars to close the overlay panel
- GestureDetector closeGestureDetector = new GestureDetector(context,
- new SystemBarCloseGestureListener() {
- @Override
- protected void close() {
- if (isPanelExpanded()) {
- animateCollapsePanel();
- }
- }
- });
-
- mDragOpenTouchListener = (v, event) -> {
- if (!mCarDeviceProvisionedController.isCurrentUserFullySetup()) {
- return true;
- }
- if (!isInflated()) {
- getOverlayViewGlobalStateController().inflateView(this);
- }
-
- boolean consumed = openGestureDetector.onTouchEvent(event);
- if (consumed) {
- return true;
- }
- maybeCompleteAnimation(event);
- return true;
- };
-
- mDragCloseTouchListener = (v, event) -> {
- if (!isInflated()) {
- return true;
- }
- boolean consumed = closeGestureDetector.onTouchEvent(event);
- if (consumed) {
- return true;
- }
- maybeCompleteAnimation(event);
- return true;
- };
- }
-
- /** Sets the overlay panel animation direction along the x or y axis. */
- public void setOverlayDirection(@OverlayDirection int direction) {
- if (direction == OVERLAY_FROM_TOP_BAR) {
- mAnimateDirection = POSITIVE_DIRECTION;
- } else if (direction == OVERLAY_FROM_BOTTOM_BAR) {
- mAnimateDirection = NEGATIVE_DIRECTION;
- } else {
- throw new IllegalArgumentException("Direction not supported");
- }
- }
-
- /** Toggles the visibility of the panel. */
- public void toggle() {
- if (!isInflated()) {
- getOverlayViewGlobalStateController().inflateView(this);
- }
- if (isPanelExpanded()) {
- animateCollapsePanel();
- } else {
- animateExpandPanel();
- }
- }
-
- /** Checks if a {@link MotionEvent} is an action to open the panel.
- * @param e {@link MotionEvent} to check.
- * @return true only if opening action.
- */
- protected boolean isOpeningAction(MotionEvent e) {
- if (mAnimateDirection == POSITIVE_DIRECTION) {
- return e.getActionMasked() == MotionEvent.ACTION_DOWN;
- }
-
- if (mAnimateDirection == NEGATIVE_DIRECTION) {
- return e.getActionMasked() == MotionEvent.ACTION_UP;
- }
-
- return false;
- }
-
- /** Checks if a {@link MotionEvent} is an action to close the panel.
- * @param e {@link MotionEvent} to check.
- * @return true only if closing action.
- */
- protected boolean isClosingAction(MotionEvent e) {
- if (mAnimateDirection == POSITIVE_DIRECTION) {
- return e.getActionMasked() == MotionEvent.ACTION_UP;
- }
-
- if (mAnimateDirection == NEGATIVE_DIRECTION) {
- return e.getActionMasked() == MotionEvent.ACTION_DOWN;
- }
-
- return false;
- }
-
- /* ***************************************************************************************** *
- * Panel Animation
- * ***************************************************************************************** */
-
- /** Animates the closing of the panel. */
- protected void animateCollapsePanel() {
- if (!shouldAnimateCollapsePanel()) {
- return;
- }
-
- if (!isPanelExpanded() || !isPanelVisible()) {
- return;
- }
-
- onAnimateCollapsePanel();
- animatePanel(mClosingVelocity, /* isClosing= */ true);
- }
-
- /** Determines whether {@link #animateCollapsePanel()} should collapse the panel. */
- protected abstract boolean shouldAnimateCollapsePanel();
-
- /** Called when the panel is beginning to collapse. */
- protected abstract void onAnimateCollapsePanel();
-
- /** Animates the expansion of the panel. */
- protected void animateExpandPanel() {
- if (!shouldAnimateExpandPanel()) {
- return;
- }
-
- if (!mCarDeviceProvisionedController.isCurrentUserFullySetup()) {
- return;
- }
-
- onAnimateExpandPanel();
- setPanelVisible(true);
- animatePanel(mOpeningVelocity, /* isClosing= */ false);
-
- setPanelExpanded(true);
- }
-
- /** Determines whether {@link #animateExpandPanel()}} should expand the panel. */
- protected abstract boolean shouldAnimateExpandPanel();
-
- /** Called when the panel is beginning to expand. */
- protected abstract void onAnimateExpandPanel();
-
- /**
- * Depending on certain conditions, determines whether to fully expand or collapse the panel.
- */
- protected void maybeCompleteAnimation(MotionEvent event) {
- if (isClosingAction(event) && isPanelVisible()) {
- if (mSettleClosePercentage < mPercentageFromEndingEdge) {
- animatePanel(DEFAULT_FLING_VELOCITY, false);
- } else {
- animatePanel(DEFAULT_FLING_VELOCITY, true);
- }
- }
- }
-
- /**
- * Animates the panel from one position to other. This is used to either open or
- * close the panel completely with a velocity. If the animation is to close the
- * panel this method also makes the view invisible after animation ends.
- */
- protected void animatePanel(float velocity, boolean isClosing) {
- float to = getEndPosition(isClosing);
-
- Rect rect = getLayout().getClipBounds();
- if (rect != null) {
- float from = getCurrentStartPosition(rect);
- if (from != to) {
- animate(from, to, velocity, isClosing);
- }
-
- // If we swipe down the notification panel all the way to the bottom of the screen
- // (i.e. from == to), then we have finished animating the panel.
- return;
- }
-
- // We will only be here if the shade is being opened programmatically or via button when
- // height of the layout was not calculated.
- ViewTreeObserver panelTreeObserver = getLayout().getViewTreeObserver();
- panelTreeObserver.addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- ViewTreeObserver obs = getLayout().getViewTreeObserver();
- obs.removeOnGlobalLayoutListener(this);
- animate(
- getDefaultStartPosition(),
- getEndPosition(/* isClosing= */ false),
- velocity,
- isClosing
- );
- }
- });
- }
-
- /* Returns the start position if the user has not started swiping. */
- private int getDefaultStartPosition() {
- return mAnimateDirection > 0 ? 0 : getLayout().getHeight();
- }
-
- /** Returns the start position if we are in the middle of swiping. */
- private int getCurrentStartPosition(Rect clipBounds) {
- return mAnimateDirection > 0 ? clipBounds.bottom : clipBounds.top;
- }
-
- private int getEndPosition(boolean isClosing) {
- return (mAnimateDirection > 0 && !isClosing) || (mAnimateDirection == -1 && isClosing)
- ? getLayout().getHeight()
- : 0;
- }
-
- private void animate(float from, float to, float velocity, boolean isClosing) {
- if (mIsAnimating) {
- return;
- }
- mIsAnimating = true;
- mIsTracking = true;
- ValueAnimator animator = ValueAnimator.ofFloat(from, to);
- animator.addUpdateListener(
- animation -> {
- float animatedValue = (Float) animation.getAnimatedValue();
- setViewClipBounds((int) animatedValue);
- });
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- mIsAnimating = false;
- mIsTracking = false;
- mOpeningVelocity = DEFAULT_FLING_VELOCITY;
- mClosingVelocity = DEFAULT_FLING_VELOCITY;
- if (isClosing) {
- setPanelVisible(false);
- getLayout().setClipBounds(null);
- onCollapseAnimationEnd();
- setPanelExpanded(false);
- } else {
- onExpandAnimationEnd();
- setPanelExpanded(true);
- }
- }
- });
- getFlingAnimationUtils().apply(animator, from, to, Math.abs(velocity));
- animator.start();
- }
-
- /**
- * Called in {@link Animator.AnimatorListener#onAnimationEnd(Animator)} when the panel is
- * closing.
- */
- protected abstract void onCollapseAnimationEnd();
-
- /**
- * Called in {@link Animator.AnimatorListener#onAnimationEnd(Animator)} when the panel is
- * opening.
- */
- protected abstract void onExpandAnimationEnd();
-
- /* ***************************************************************************************** *
- * Panel Visibility
- * ***************************************************************************************** */
-
- /** Set the panel view to be visible. */
- protected final void setPanelVisible(boolean visible) {
- mPanelVisible = visible;
- onPanelVisible(visible);
- }
-
- /** Returns {@code true} if panel is visible. */
- public final boolean isPanelVisible() {
- return mPanelVisible;
- }
-
- /** Business logic run when panel visibility is set. */
- @CallSuper
- protected void onPanelVisible(boolean visible) {
- if (DEBUG) {
- Log.e(TAG, "onPanelVisible: " + visible);
- }
-
- if (visible && !getOverlayViewGlobalStateController().isWindowVisible()) {
- getOverlayViewGlobalStateController().showView(/* panelViewController= */ this);
- }
- if (!visible && getOverlayViewGlobalStateController().isWindowVisible()) {
- getOverlayViewGlobalStateController().hideView(/* panelViewController= */ this);
- }
- getLayout().setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- }
-
- /* ***************************************************************************************** *
- * Panel Expansion
- * ***************************************************************************************** */
-
- /**
- * Set the panel state to expanded. This will expand or collapse the overlay window if
- * necessary.
- */
- protected final void setPanelExpanded(boolean expand) {
- mPanelExpanded = expand;
- onPanelExpanded(expand);
- }
-
- /** Returns {@code true} if panel is expanded. */
- public final boolean isPanelExpanded() {
- return mPanelExpanded;
- }
-
- @CallSuper
- protected void onPanelExpanded(boolean expand) {
- if (DEBUG) {
- Log.e(TAG, "onPanelExpanded: " + expand);
- }
- }
-
- /* ***************************************************************************************** *
- * Misc
- * ***************************************************************************************** */
-
- /**
- * Given the position of the pointer dragging the panel, return the percentage of its closeness
- * to the ending edge.
- */
- protected void calculatePercentageFromEndingEdge(float y) {
- if (getLayout().getHeight() > 0) {
- float height = getVisiblePanelHeight(y);
- mPercentageFromEndingEdge = (int) Math.abs(height / getLayout().getHeight() * 100);
- }
- }
-
- private float getVisiblePanelHeight(float y) {
- return mAnimateDirection > 0 ? y : getLayout().getHeight() - y;
- }
-
- /** Sets the boundaries of the overlay panel that can be seen based on pointer position. */
- protected void setViewClipBounds(int y) {
- // Bound the pointer position to be within the overlay panel.
- y = Math.max(0, Math.min(y, getLayout().getHeight()));
- Rect clipBounds = new Rect();
- int top, bottom;
- if (mAnimateDirection > 0) {
- top = 0;
- bottom = y;
- } else {
- top = y;
- bottom = getLayout().getHeight();
- }
- clipBounds.set(0, top, getLayout().getWidth(), bottom);
- getLayout().setClipBounds(clipBounds);
- onScroll(y);
- }
-
- /**
- * Called while scrolling, this passes the position of the clip boundary that is currently
- * changing.
- */
- protected abstract void onScroll(int y);
-
- /* ***************************************************************************************** *
- * Getters
- * ***************************************************************************************** */
-
- /** Returns the open touch listener. */
- public final View.OnTouchListener getDragOpenTouchListener() {
- return mDragOpenTouchListener;
- }
-
- /** Returns the close touch listener. */
- public final View.OnTouchListener getDragCloseTouchListener() {
- return mDragCloseTouchListener;
- }
-
- /** Gets the fling animation utils used for animating this panel. */
- protected final FlingAnimationUtils getFlingAnimationUtils() {
- return mFlingAnimationUtils;
- }
-
- /** Returns {@code true} if the panel is currently tracking. */
- protected final boolean isTracking() {
- return mIsTracking;
- }
-
- /** Sets whether the panel is currently tracking or not. */
- protected final void setIsTracking(boolean isTracking) {
- mIsTracking = isTracking;
- }
-
- /** Returns {@code true} if the panel is currently animating. */
- protected final boolean isAnimating() {
- return mIsAnimating;
- }
-
- /** Returns the percentage of the panel that is open from the bottom. */
- protected final int getPercentageFromEndingEdge() {
- return mPercentageFromEndingEdge;
- }
-
- /** Returns the percentage at which we've determined whether to open or close the panel. */
- protected final int getSettleClosePercentage() {
- return mSettleClosePercentage;
- }
-
- /* ***************************************************************************************** *
- * Gesture Listeners
- * ***************************************************************************************** */
-
- /** Called when the user is beginning to scroll down the panel. */
- protected abstract void onOpenScrollStart();
-
- /**
- * Only responsible for open hooks. Since once the panel opens it covers all elements
- * there is no need to merge with close.
- */
- protected abstract class OpenGestureListener extends
- GestureDetector.SimpleOnGestureListener {
-
- @Override
- public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
- float distanceY) {
-
- if (!isPanelVisible()) {
- onOpenScrollStart();
- }
- setPanelVisible(true);
-
- // clips the view for the panel when the user scrolls to open.
- setViewClipBounds((int) event2.getRawY());
-
- // Initially the scroll starts with height being zero. This checks protects from divide
- // by zero error.
- calculatePercentageFromEndingEdge(event2.getRawY());
-
- mIsTracking = true;
- return true;
- }
-
-
- @Override
- public boolean onFling(MotionEvent event1, MotionEvent event2,
- float velocityX, float velocityY) {
- if (mAnimateDirection * velocityY > SWIPE_THRESHOLD_VELOCITY) {
- mOpeningVelocity = velocityY;
- open();
- return true;
- }
- animatePanel(DEFAULT_FLING_VELOCITY, true);
-
- return false;
- }
-
- protected abstract void open();
- }
-
- /** Determines whether the scroll event should allow closing of the panel. */
- protected abstract boolean shouldAllowClosingScroll();
-
- protected abstract class CloseGestureListener extends
- GestureDetector.SimpleOnGestureListener {
-
- @Override
- public boolean onSingleTapUp(MotionEvent motionEvent) {
- if (isPanelExpanded()) {
- animatePanel(DEFAULT_FLING_VELOCITY, true);
- }
- return true;
- }
-
- @Override
- public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
- float distanceY) {
- if (!shouldAllowClosingScroll()) {
- return false;
- }
- float y = getYPositionOfPanelEndingEdge(event1, event2);
- if (getLayout().getHeight() > 0) {
- mPercentageFromEndingEdge = (int) Math.abs(
- y / getLayout().getHeight() * 100);
- boolean isInClosingDirection = mAnimateDirection * distanceY > 0;
-
- // This check is to figure out if onScroll was called while swiping the card at
- // bottom of the panel. At that time we should not allow panel to
- // close. We are also checking for the upwards swipe gesture here because it is
- // possible if a user is closing the panel and while swiping starts
- // to open again but does not fling. At that time we should allow the
- // panel to close fully or else it would stuck in between.
- if (Math.abs(getLayout().getHeight() - y)
- > SWIPE_DOWN_MIN_DISTANCE && isInClosingDirection) {
- setViewClipBounds((int) y);
- mIsTracking = true;
- } else if (!isInClosingDirection) {
- setViewClipBounds((int) y);
- }
- }
- // if we return true the items in RV won't be scrollable.
- return false;
- }
-
- /**
- * To prevent the jump in the clip bounds while closing the panel we should calculate the y
- * position using the diff of event1 and event2. This will help the panel clip smoothly as
- * the event2 value changes while event1 value will be fixed.
- * @param event1 MotionEvent that contains the position of where the event2 started.
- * @param event2 MotionEvent that contains the position of where the user has scrolled to
- * on the screen.
- */
- private float getYPositionOfPanelEndingEdge(MotionEvent event1, MotionEvent event2) {
- float diff = mAnimateDirection * (event1.getRawY() - event2.getRawY());
- float y = mAnimateDirection > 0 ? getLayout().getHeight() - diff : diff;
- y = Math.max(0, Math.min(y, getLayout().getHeight()));
- return y;
- }
-
- @Override
- public boolean onFling(MotionEvent event1, MotionEvent event2,
- float velocityX, float velocityY) {
- // should not fling if the touch does not start when view is at the end of the list.
- if (!shouldAllowClosingScroll()) {
- return false;
- }
- if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
- || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
- // swipe was not vertical or was not fast enough
- return false;
- }
- boolean isInClosingDirection = mAnimateDirection * velocityY < 0;
- if (isInClosingDirection) {
- close();
- return true;
- } else {
- // we should close the shade
- animatePanel(velocityY, false);
- }
- return false;
- }
-
- protected abstract void close();
- }
-
- protected abstract class SystemBarCloseGestureListener extends CloseGestureListener {
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- mClosingVelocity = DEFAULT_FLING_VELOCITY;
- if (isPanelExpanded()) {
- close();
- }
- return super.onSingleTapUp(e);
- }
-
- @Override
- public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX,
- float distanceY) {
- calculatePercentageFromEndingEdge(event2.getRawY());
- setViewClipBounds((int) event2.getRawY());
- return true;
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
deleted file mode 100644
index b989c421c780..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
+++ /dev/null
@@ -1,218 +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.car.window;
-
-import static android.view.WindowInsets.Type.statusBars;
-
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewStub;
-import android.view.WindowInsets;
-
-/**
- * Owns a {@link View} that is present in SystemUIOverlayWindow.
- */
-public class OverlayViewController {
- protected static final int INVALID_INSET_SIDE = -1;
- protected static final int NO_INSET_SIDE = 0;
-
- 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;
- }
-
- /** Returns the {@link OverlayViewGlobalStateController}. */
- protected final OverlayViewGlobalStateController getOverlayViewGlobalStateController() {
- return mOverlayViewGlobalStateController;
- }
-
- /**
- * Returns {@code true} if heads up notifications should be displayed over this view.
- */
- protected boolean shouldShowHUN() {
- return true;
- }
-
- /**
- * Returns {@code true} if navigation bar insets should be displayed over this view. Has no
- * effect if {@link #shouldFocusWindow} returns {@code false}.
- */
- protected boolean shouldShowNavigationBarInsets() {
- return false;
- }
-
- /**
- * Returns {@code true} if status bar insets should be displayed over this view. Has no
- * effect if {@link #shouldFocusWindow} returns {@code false}.
- */
- protected boolean shouldShowStatusBarInsets() {
- return false;
- }
-
- /**
- * Returns {@code true} if this view should be hidden during the occluded state.
- */
- protected boolean shouldShowWhenOccluded() {
- return false;
- }
-
- /**
- * Returns {@code true} if the window should be focued when this view is visible. Note that
- * returning {@code false} here means that {@link #shouldShowStatusBarInsets} and
- * {@link #shouldShowNavigationBarInsets} will have no effect.
- */
- protected boolean shouldFocusWindow() {
- return true;
- }
-
- /**
- * Returns {@code true} if the window should use stable insets. Using stable insets means that
- * even when system bars are temporarily not visible, inset from the system bars will still be
- * applied.
- *
- * NOTE: When system bars are hidden in transient mode, insets from them will not be applied
- * even when the system bars become visible. Setting the return value to {@true} here can
- * prevent the OverlayView from overlapping with the system bars when that happens.
- */
- protected boolean shouldUseStableInsets() {
- return false;
- }
-
- /**
- * Returns the insets types to fit to the sysui overlay window when this
- * {@link OverlayViewController} is in the foreground.
- */
- @WindowInsets.Type.InsetsType
- protected int getInsetTypesToFit() {
- return statusBars();
- }
-
- /**
- * Optionally returns the sides of enabled system bar insets to fit to the sysui overlay window
- * when this {@link OverlayViewController} is in the foreground.
- *
- * For example, if the bottom and left system bars are enabled and this method returns
- * WindowInsets.Side.LEFT, then the inset from the bottom system bar will be ignored.
- *
- * NOTE: By default, this method returns {@link #INVALID_INSET_SIDE}, so insets to fit are
- * defined by {@link #getInsetTypesToFit()}, and not by this method, unless it is overridden
- * by subclasses.
- *
- * NOTE: {@link #NO_INSET_SIDE} signifies no insets from any system bars will be honored. Each
- * {@link OverlayViewController} can first take this value and add sides of the system bar
- * insets to honor to it.
- *
- * NOTE: If getInsetSidesToFit is overridden to return {@link WindowInsets.Side}, it always
- * takes precedence over {@link #getInsetTypesToFit()}. That is, the return value of {@link
- * #getInsetTypesToFit()} will be ignored.
- */
- @WindowInsets.Side.InsetsSide
- protected int getInsetSidesToFit() {
- return INVALID_INSET_SIDE;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
deleted file mode 100644
index 10f436b5e717..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
+++ /dev/null
@@ -1,384 +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.car.window;
-
-import static android.view.WindowInsets.Type.navigationBars;
-import static android.view.WindowInsets.Type.statusBars;
-
-import android.annotation.Nullable;
-import android.util.Log;
-import android.view.WindowInsets;
-import android.view.WindowInsets.Side.InsetsSide;
-import android.view.WindowInsets.Type.InsetsType;
-import android.view.WindowInsetsController;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.systemui.dagger.SysUISingleton;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.inject.Inject;
-
-/**
- * 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>
- */
-@SysUISingleton
-public class OverlayViewGlobalStateController {
- private static final boolean DEBUG = false;
- private static final String TAG = OverlayViewGlobalStateController.class.getSimpleName();
- private static final int UNKNOWN_Z_ORDER = -1;
- private final SystemUIOverlayWindowController mSystemUIOverlayWindowController;
- private final WindowInsetsController mWindowInsetsController;
- @VisibleForTesting
- Map<OverlayViewController, Integer> mZOrderMap;
- @VisibleForTesting
- SortedMap<Integer, OverlayViewController> mZOrderVisibleSortedMap;
- @VisibleForTesting
- Set<OverlayViewController> mViewsHiddenForOcclusion;
- @VisibleForTesting
- OverlayViewController mHighestZOrder;
- private boolean mIsOccluded;
-
- @Inject
- public OverlayViewGlobalStateController(
- SystemUIOverlayWindowController systemUIOverlayWindowController) {
- mSystemUIOverlayWindowController = systemUIOverlayWindowController;
- mSystemUIOverlayWindowController.attach();
- mWindowInsetsController =
- mSystemUIOverlayWindowController.getBaseLayout().getWindowInsetsController();
- mZOrderMap = new HashMap<>();
- mZOrderVisibleSortedMap = new TreeMap<>();
- mViewsHiddenForOcclusion = 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 using {@link OverlayPanelViewController}.
- *
- * This calls {@link OverlayViewGlobalStateController#showView(OverlayViewController, Runnable)}
- * where the runnable is nullified since the actual showing of the panel is handled by the
- * controller itself.
- */
- public void showView(OverlayPanelViewController panelViewController) {
- showView(panelViewController, /* show= */ null);
- }
-
- /**
- * Show content in Overlay Window using {@link OverlayViewController}.
- */
- public void showView(OverlayViewController viewController, @Nullable Runnable show) {
- debugLog();
- if (mIsOccluded && !viewController.shouldShowWhenOccluded()) {
- mViewsHiddenForOcclusion.add(viewController);
- return;
- }
- if (mZOrderVisibleSortedMap.isEmpty()) {
- setWindowVisible(true);
- }
-
- if (!(viewController instanceof OverlayPanelViewController)) {
- inflateView(viewController);
- }
-
- if (show != null) {
- show.run();
- }
-
- updateInternalsWhenShowingView(viewController);
- refreshUseStableInsets();
- refreshInsetsToFit();
- refreshWindowFocus();
- refreshNavigationBarVisibility();
- refreshStatusBarVisibility();
-
- Log.d(TAG, "Content shown: " + viewController.getClass().getName());
- debugLog();
- }
-
- private void updateInternalsWhenShowingView(OverlayViewController viewController) {
- int zOrder;
- if (mZOrderMap.containsKey(viewController)) {
- zOrder = mZOrderMap.get(viewController);
- } else {
- zOrder = mSystemUIOverlayWindowController.getBaseLayout().indexOfChild(
- viewController.getLayout());
- mZOrderMap.put(viewController, zOrder);
- }
-
- mZOrderVisibleSortedMap.put(zOrder, viewController);
-
- refreshHighestZOrderWhenShowingView(viewController);
- }
-
- private void refreshHighestZOrderWhenShowingView(OverlayViewController viewController) {
- if (mZOrderMap.getOrDefault(mHighestZOrder, UNKNOWN_Z_ORDER) < mZOrderMap.get(
- viewController)) {
- mHighestZOrder = viewController;
- }
- }
-
- /**
- * Hide content in Overlay Window using {@link OverlayPanelViewController}.
- *
- * This calls {@link OverlayViewGlobalStateController#hideView(OverlayViewController, Runnable)}
- * where the runnable is nullified since the actual hiding of the panel is handled by the
- * controller itself.
- */
- public void hideView(OverlayPanelViewController panelViewController) {
- hideView(panelViewController, /* hide= */ null);
- }
-
- /**
- * Hide content in Overlay Window using {@link OverlayViewController}.
- */
- public void hideView(OverlayViewController viewController, @Nullable Runnable hide) {
- debugLog();
- if (mIsOccluded && mViewsHiddenForOcclusion.contains(viewController)) {
- mViewsHiddenForOcclusion.remove(viewController);
- return;
- }
- if (!viewController.isInflated()) {
- Log.d(TAG, "Content cannot be hidden since it isn't inflated: "
- + viewController.getClass().getName());
- return;
- }
- if (!mZOrderMap.containsKey(viewController)) {
- Log.d(TAG, "Content cannot be hidden since it has never been shown: "
- + viewController.getClass().getName());
- return;
- }
- if (!mZOrderVisibleSortedMap.containsKey(mZOrderMap.get(viewController))) {
- Log.d(TAG, "Content cannot be hidden since it isn't currently shown: "
- + viewController.getClass().getName());
- return;
- }
-
- if (hide != null) {
- hide.run();
- }
-
- mZOrderVisibleSortedMap.remove(mZOrderMap.get(viewController));
- refreshHighestZOrderWhenHidingView(viewController);
- refreshUseStableInsets();
- refreshInsetsToFit();
- refreshWindowFocus();
- refreshNavigationBarVisibility();
- refreshStatusBarVisibility();
-
- if (mZOrderVisibleSortedMap.isEmpty()) {
- setWindowVisible(false);
- }
-
- Log.d(TAG, "Content hidden: " + viewController.getClass().getName());
- debugLog();
- }
-
- private void refreshHighestZOrderWhenHidingView(OverlayViewController viewController) {
- if (mZOrderVisibleSortedMap.isEmpty()) {
- mHighestZOrder = null;
- return;
- }
- if (!mHighestZOrder.equals(viewController)) {
- return;
- }
-
- mHighestZOrder = mZOrderVisibleSortedMap.get(mZOrderVisibleSortedMap.lastKey());
- }
-
- private void refreshNavigationBarVisibility() {
- if (mZOrderVisibleSortedMap.isEmpty()) {
- mWindowInsetsController.show(navigationBars());
- return;
- }
-
- // Do not hide navigation bar insets if the window is not focusable.
- if (mHighestZOrder.shouldFocusWindow() && !mHighestZOrder.shouldShowNavigationBarInsets()) {
- mWindowInsetsController.hide(navigationBars());
- } else {
- mWindowInsetsController.show(navigationBars());
- }
- }
-
- private void refreshStatusBarVisibility() {
- if (mZOrderVisibleSortedMap.isEmpty()) {
- mWindowInsetsController.show(statusBars());
- return;
- }
-
- // Do not hide status bar insets if the window is not focusable.
- if (mHighestZOrder.shouldFocusWindow() && !mHighestZOrder.shouldShowStatusBarInsets()) {
- mWindowInsetsController.hide(statusBars());
- } else {
- mWindowInsetsController.show(statusBars());
- }
- }
-
- private void refreshWindowFocus() {
- setWindowFocusable(mHighestZOrder == null ? false : mHighestZOrder.shouldFocusWindow());
- }
-
- private void refreshUseStableInsets() {
- mSystemUIOverlayWindowController.setUsingStableInsets(
- mHighestZOrder == null ? false : mHighestZOrder.shouldUseStableInsets());
- }
-
- /**
- * Refreshes the insets to fit (or honor) either by {@link InsetsType} or {@link InsetsSide}.
- *
- * By default, the insets to fit are defined by the {@link InsetsType}. But if an
- * {@link OverlayViewController} overrides {@link OverlayViewController#getInsetSidesToFit()} to
- * return an {@link InsetsSide}, then that takes precedence over {@link InsetsType}.
- */
- private void refreshInsetsToFit() {
- if (mZOrderVisibleSortedMap.isEmpty()) {
- setFitInsetsTypes(statusBars());
- } else {
- if (mHighestZOrder.getInsetSidesToFit() != OverlayViewController.INVALID_INSET_SIDE) {
- // First fit all system bar insets as setFitInsetsSide defines which sides of system
- // bar insets to actually honor.
- setFitInsetsTypes(WindowInsets.Type.systemBars());
- setFitInsetsSides(mHighestZOrder.getInsetSidesToFit());
- } else {
- setFitInsetsTypes(mHighestZOrder.getInsetTypesToFit());
- }
- }
- }
-
- /** Returns {@code true} is the window is visible. */
- public boolean isWindowVisible() {
- return mSystemUIOverlayWindowController.isWindowVisible();
- }
-
- private void setWindowVisible(boolean visible) {
- mSystemUIOverlayWindowController.setWindowVisible(visible);
- }
-
- /** Sets the insets to fit based on the {@link InsetsType} */
- private void setFitInsetsTypes(@InsetsType int types) {
- mSystemUIOverlayWindowController.setFitInsetsTypes(types);
- }
-
- /** Sets the insets to fit based on the {@link InsetsSide} */
- private void setFitInsetsSides(@InsetsSide int sides) {
- mSystemUIOverlayWindowController.setFitInsetsSides(sides);
- }
-
- /**
- * Sets the {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flag of the
- * sysui overlay window.
- */
- public void setWindowNeedsInput(boolean needsInput) {
- mSystemUIOverlayWindowController.setWindowNeedsInput(needsInput);
- }
-
- /** Returns {@code true} if the window is focusable. */
- public boolean isWindowFocusable() {
- return mSystemUIOverlayWindowController.isWindowFocusable();
- }
-
- /** Sets the focusable flag of the sysui overlawy window. */
- public void setWindowFocusable(boolean focusable) {
- mSystemUIOverlayWindowController.setWindowFocusable(focusable);
- }
-
- /** Inflates the view controlled by the given view controller. */
- public void inflateView(OverlayViewController viewController) {
- if (!viewController.isInflated()) {
- viewController.inflate(mSystemUIOverlayWindowController.getBaseLayout());
- }
- }
-
- /**
- * Return {@code true} if OverlayWindow is in a state where HUNs should be displayed above it.
- */
- public boolean shouldShowHUN() {
- return mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowHUN();
- }
-
- /**
- * Set the OverlayViewWindow to be in occluded or unoccluded state. When OverlayViewWindow is
- * occluded, all views mounted to it that are not configured to be shown during occlusion will
- * be hidden.
- */
- public void setOccluded(boolean occluded) {
- if (occluded) {
- // Hide views before setting mIsOccluded to true so the regular hideView logic is used,
- // not the one used during occlusion.
- hideViewsForOcclusion();
- mIsOccluded = true;
- } else {
- mIsOccluded = false;
- // show views after setting mIsOccluded to false so the regular showView logic is used,
- // not the one used during occlusion.
- showViewsHiddenForOcclusion();
- }
- }
-
- private void hideViewsForOcclusion() {
- HashSet<OverlayViewController> viewsCurrentlyShowing = new HashSet<>(
- mZOrderVisibleSortedMap.values());
- viewsCurrentlyShowing.forEach(overlayController -> {
- if (!overlayController.shouldShowWhenOccluded()) {
- hideView(overlayController, overlayController::hideInternal);
- mViewsHiddenForOcclusion.add(overlayController);
- }
- });
- }
-
- private void showViewsHiddenForOcclusion() {
- mViewsHiddenForOcclusion.forEach(overlayViewController -> {
- showView(overlayViewController, overlayViewController::showInternal);
- });
- mViewsHiddenForOcclusion.clear();
- }
-
- private void debugLog() {
- if (!DEBUG) {
- return;
- }
-
- Log.d(TAG, "mHighestZOrder: " + mHighestZOrder);
- Log.d(TAG, "mZOrderVisibleSortedMap.size(): " + mZOrderVisibleSortedMap.size());
- Log.d(TAG, "mZOrderVisibleSortedMap: " + mZOrderVisibleSortedMap);
- Log.d(TAG, "mZOrderMap.size(): " + mZOrderMap.size());
- Log.d(TAG, "mZOrderMap: " + mZOrderMap);
- Log.d(TAG, "mIsOccluded: " + mIsOccluded);
- Log.d(TAG, "mViewsHiddenForOcclusion: " + mViewsHiddenForOcclusion);
- Log.d(TAG, "mViewsHiddenForOcclusion.size(): " + mViewsHiddenForOcclusion.size());
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java
deleted file mode 100644
index fcbb0b807e74..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayWindowModule.java
+++ /dev/null
@@ -1,86 +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.car.window;
-
-import com.android.systemui.car.keyguard.CarKeyguardViewMediator;
-import com.android.systemui.car.notification.BottomNotificationPanelViewMediator;
-import com.android.systemui.car.notification.NotificationPanelViewMediator;
-import com.android.systemui.car.notification.TopNotificationPanelViewMediator;
-import com.android.systemui.car.rvc.RearViewCameraViewMediator;
-import com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator;
-import com.android.systemui.car.userswitcher.UserSwitchTransitionViewMediator;
-
-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 {
-
- /** Injects NotificationPanelViewMediator. */
- @Binds
- @IntoMap
- @ClassKey(NotificationPanelViewMediator.class)
- public abstract OverlayViewMediator bindNotificationPanelViewMediator(
- NotificationPanelViewMediator notificationPanelViewMediator);
-
- /** Injects TopNotificationPanelViewMediator. */
- @Binds
- @IntoMap
- @ClassKey(TopNotificationPanelViewMediator.class)
- public abstract OverlayViewMediator bindTopNotificationPanelViewMediator(
- TopNotificationPanelViewMediator topNotificationPanelViewMediator);
-
- /** Injects BottomNotificationPanelViewMediator. */
- @Binds
- @IntoMap
- @ClassKey(BottomNotificationPanelViewMediator.class)
- public abstract OverlayViewMediator bindBottomNotificationPanelViewMediator(
- BottomNotificationPanelViewMediator bottomNotificationPanelViewMediator);
-
- /** Inject into CarKeyguardViewMediator. */
- @Binds
- @IntoMap
- @ClassKey(CarKeyguardViewMediator.class)
- public abstract OverlayViewMediator bindCarKeyguardViewMediator(
- CarKeyguardViewMediator carKeyguardViewMediator);
-
- /** Injects FullscreenUserSwitcherViewsMediator. */
- @Binds
- @IntoMap
- @ClassKey(FullscreenUserSwitcherViewMediator.class)
- public abstract OverlayViewMediator bindFullscreenUserSwitcherViewsMediator(
- FullscreenUserSwitcherViewMediator overlayViewsMediator);
-
- /** Injects CarUserSwitchingDialogMediator. */
- @Binds
- @IntoMap
- @ClassKey(UserSwitchTransitionViewMediator.class)
- public abstract OverlayViewMediator bindUserSwitchTransitionViewMediator(
- UserSwitchTransitionViewMediator userSwitchTransitionViewMediator);
-
- /** Injects RearViewCameraViewMediator. */
- @Binds
- @IntoMap
- @ClassKey(RearViewCameraViewMediator.class)
- public abstract OverlayViewMediator bindRearViewCameraViewMediator(
- RearViewCameraViewMediator overlayViewsMediator);
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java
deleted file mode 100644
index 0e73f2520a66..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java
+++ /dev/null
@@ -1,183 +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.car.window;
-
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-
-import android.content.Context;
-import android.graphics.PixelFormat;
-import android.os.Binder;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-
-import com.android.systemui.R;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-
-import javax.inject.Inject;
-
-/**
- * Controls the expansion state of the primary window which will contain all of the fullscreen sysui
- * behavior. This window still has a collapsed state in order to watch for swipe events to expand
- * this window for the notification panel.
- */
-@SysUISingleton
-public class SystemUIOverlayWindowController implements
- ConfigurationController.ConfigurationListener {
-
- private final Context mContext;
- private final WindowManager mWindowManager;
-
- private ViewGroup mBaseLayout;
- private WindowManager.LayoutParams mLp;
- private WindowManager.LayoutParams mLpChanged;
- private boolean mIsAttached = false;
- private boolean mVisible = false;
- private boolean mFocusable = false;
- private boolean mUsingStableInsets = false;
-
- @Inject
- public SystemUIOverlayWindowController(
- Context context,
- WindowManager windowManager,
- ConfigurationController configurationController
- ) {
- mContext = context;
- mWindowManager = windowManager;
-
- mLpChanged = new WindowManager.LayoutParams();
- mBaseLayout = (ViewGroup) LayoutInflater.from(context)
- .inflate(R.layout.sysui_overlay_window, /* root= */ null, false);
-
- configurationController.addCallback(this);
- }
-
- /** Returns the base view of the primary window. */
- public ViewGroup getBaseLayout() {
- return mBaseLayout;
- }
-
- /** Returns {@code true} if the window is already attached. */
- public boolean isAttached() {
- return mIsAttached;
- }
-
- /** Attaches the window to the window manager. */
- public void attach() {
- if (mIsAttached) {
- return;
- }
- mIsAttached = true;
- // Now that the status bar window encompasses the sliding panel and its
- // translucent backdrop, the entire thing is made TRANSLUCENT and is
- // hardware-accelerated.
- mLp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
- PixelFormat.TRANSLUCENT);
- mLp.token = new Binder();
- mLp.gravity = Gravity.TOP;
- mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
- mLp.setTitle("SystemUIOverlayWindow");
- mLp.packageName = mContext.getPackageName();
- mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- mLp.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
-
- mWindowManager.addView(mBaseLayout, mLp);
- mLpChanged.copyFrom(mLp);
- setWindowVisible(false);
- }
-
- /** Sets the types of insets to fit. Note: This should be rarely used. */
- public void setFitInsetsTypes(@WindowInsets.Type.InsetsType int types) {
- mLpChanged.setFitInsetsTypes(types);
- mLpChanged.setFitInsetsIgnoringVisibility(mUsingStableInsets);
- updateWindow();
- }
-
- /** Sets the sides of system bar insets to fit. Note: This should be rarely used. */
- public void setFitInsetsSides(@WindowInsets.Side.InsetsSide int sides) {
- mLpChanged.setFitInsetsSides(sides);
- mLpChanged.setFitInsetsIgnoringVisibility(mUsingStableInsets);
- updateWindow();
- }
-
- /** Sets the window to the visible state. */
- public void setWindowVisible(boolean visible) {
- mVisible = visible;
- if (visible) {
- mBaseLayout.setVisibility(View.VISIBLE);
- } else {
- mBaseLayout.setVisibility(View.INVISIBLE);
- }
- updateWindow();
- }
-
- /** Sets the window to be focusable. */
- public void setWindowFocusable(boolean focusable) {
- mFocusable = focusable;
- if (focusable) {
- mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- } else {
- mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- }
- updateWindow();
- }
-
- /** Sets the window to enable IME. */
- public void setWindowNeedsInput(boolean needsInput) {
- if (needsInput) {
- mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- } else {
- mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- }
- updateWindow();
- }
-
- /** Returns {@code true} if the window is visible */
- public boolean isWindowVisible() {
- return mVisible;
- }
-
- public boolean isWindowFocusable() {
- return mFocusable;
- }
-
- protected void setUsingStableInsets(boolean useStableInsets) {
- mUsingStableInsets = useStableInsets;
- }
-
- private void updateWindow() {
- if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {
- if (isAttached()) {
- mLp.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
- mWindowManager.updateViewLayout(mBaseLayout, mLp);
- }
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowManager.java b/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowManager.java
deleted file mode 100644
index 6395ebff5a41..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowManager.java
+++ /dev/null
@@ -1,100 +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.car.window;
-
-import android.content.Context;
-import android.util.Log;
-
-import com.android.systemui.R;
-import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.SysUISingleton;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-/**
- * Registers {@link OverlayViewMediator}(s) and synchronizes their calls to hide/show {@link
- * OverlayViewController}(s) to allow for the correct visibility of system bars.
- */
-@SysUISingleton
-public class SystemUIOverlayWindowManager extends SystemUI {
- private static final String TAG = "SystemUIOverlayWM";
- 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) {
- long ti = System.currentTimeMillis();
- 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);
- }
-
- // Warn if initialization of component takes too long
- ti = System.currentTimeMillis() - ti;
- if (ti > 200) {
- Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
- }
- }
- }
-
- 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/src/com/android/systemui/wm/BarControlPolicy.java b/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
deleted file mode 100644
index 0452b83b125f..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
+++ /dev/null
@@ -1,250 +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.wm;
-
-import android.car.settings.CarSettings;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.ArraySet;
-import android.util.Slog;
-import android.view.WindowInsets;
-
-import androidx.annotation.VisibleForTesting;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-/**
- * Util class to load PolicyControl and allow for querying if a package matches immersive filters.
- * Similar to {@link com.android.server.wm.PolicyControl}, but separate due to CarSystemUI needing
- * to set its own policies for system bar visibilities.
- *
- * This forces immersive mode behavior for one or both system bars (based on a package
- * list).
- *
- * Control by setting {@link Settings.Global#POLICY_CONTROL_AUTO} to one or more name-value pairs.
- * e.g.
- * to force immersive mode everywhere:
- * "immersive.full=*"
- * to force hide status bars for com.package1 but not com.package2:
- * "immersive.status=com.package1,-com.package2"
- *
- * Separate multiple name-value pairs with ':'
- * e.g. "immersive.status=com.package:immersive.navigation=*"
- */
-public class BarControlPolicy {
-
- private static final String TAG = "BarControlPolicy";
- private static final boolean DEBUG = false;
-
- private static final String NAME_IMMERSIVE_FULL = "immersive.full";
- private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
- private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation";
-
- @VisibleForTesting
- static String sSettingValue;
- @VisibleForTesting
- static Filter sImmersiveStatusFilter;
- private static Filter sImmersiveNavigationFilter;
-
- /** Loads values from the POLICY_CONTROL setting to set filters. */
- static boolean reloadFromSetting(Context context) {
- if (DEBUG) Slog.d(TAG, "reloadFromSetting()");
- String value = null;
- try {
- value = Settings.Global.getStringForUser(context.getContentResolver(),
- CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
- UserHandle.USER_CURRENT);
- if (sSettingValue == value || sSettingValue != null && sSettingValue.equals(value)) {
- return false;
- }
- setFilters(value);
- sSettingValue = value;
- } catch (Throwable t) {
- Slog.w(TAG, "Error loading policy control, value=" + value, t);
- return false;
- }
- return true;
- }
-
- /** Used in testing to reset BarControlPolicy. */
- @VisibleForTesting
- static void reset() {
- sSettingValue = null;
- sImmersiveStatusFilter = null;
- sImmersiveNavigationFilter = null;
- }
-
- /**
- * Registers a content observer to listen to updates to the SYSTEM_BAR_VISIBILITY_OVERRIDE flag.
- */
- static void registerContentObserver(Context context, Handler handler, FilterListener listener) {
- context.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE), false,
- new ContentObserver(handler) {
- @Override
- public void onChange(boolean selfChange) {
- if (reloadFromSetting(context)) {
- listener.onFilterUpdated();
- }
- }
- }, UserHandle.USER_ALL);
- }
-
- /**
- * Returns bar visibilities based on POLICY_CONTROL_AUTO filters and window policies.
- * @return int[], where the first value is the inset types that should be shown, and the second
- * is the inset types that should be hidden.
- */
- @WindowInsets.Type.InsetsType
- static int[] getBarVisibilities(String packageName) {
- int hideTypes = 0;
- int showTypes = 0;
- if (matchesStatusFilter(packageName)) {
- hideTypes |= WindowInsets.Type.statusBars();
- } else {
- showTypes |= WindowInsets.Type.statusBars();
- }
- if (matchesNavigationFilter(packageName)) {
- hideTypes |= WindowInsets.Type.navigationBars();
- } else {
- showTypes |= WindowInsets.Type.navigationBars();
- }
-
- return new int[] {showTypes, hideTypes};
- }
-
- private static boolean matchesStatusFilter(String packageName) {
- return sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(packageName);
- }
-
- private static boolean matchesNavigationFilter(String packageName) {
- return sImmersiveNavigationFilter != null
- && sImmersiveNavigationFilter.matches(packageName);
- }
-
- private static void setFilters(String value) {
- if (DEBUG) Slog.d(TAG, "setFilters: " + value);
- sImmersiveStatusFilter = null;
- sImmersiveNavigationFilter = null;
- if (value != null) {
- String[] nvps = value.split(":");
- for (String nvp : nvps) {
- int i = nvp.indexOf('=');
- if (i == -1) continue;
- String n = nvp.substring(0, i);
- String v = nvp.substring(i + 1);
- if (n.equals(NAME_IMMERSIVE_FULL)) {
- Filter f = Filter.parse(v);
- sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
- } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
- Filter f = Filter.parse(v);
- sImmersiveStatusFilter = f;
- } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
- Filter f = Filter.parse(v);
- sImmersiveNavigationFilter = f;
- }
- }
- }
- if (DEBUG) {
- Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter);
- Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter);
- }
- }
-
- private static class Filter {
- private static final String ALL = "*";
-
- private final ArraySet<String> mToInclude;
- private final ArraySet<String> mToExclude;
-
- private Filter(ArraySet<String> toInclude, ArraySet<String> toExclude) {
- mToInclude = toInclude;
- mToExclude = toExclude;
- }
-
- boolean matches(String packageName) {
- if (packageName == null) return false;
- if (toExclude(packageName)) return false;
- return toInclude(packageName);
- }
-
- private boolean toExclude(String packageName) {
- return mToExclude.contains(packageName) || mToExclude.contains(ALL);
- }
-
- private boolean toInclude(String packageName) {
- return mToInclude.contains(ALL) || mToInclude.contains(packageName);
- }
-
- void dump(PrintWriter pw) {
- pw.print("Filter[");
- dump("toInclude", mToInclude, pw); pw.print(',');
- dump("toExclude", mToExclude, pw); pw.print(']');
- }
-
- private void dump(String name, ArraySet<String> set, PrintWriter pw) {
- pw.print(name); pw.print("=(");
- int n = set.size();
- for (int i = 0; i < n; i++) {
- if (i > 0) pw.print(',');
- pw.print(set.valueAt(i));
- }
- pw.print(')');
- }
-
- @Override
- public String toString() {
- StringWriter sw = new StringWriter();
- dump(new PrintWriter(sw, true));
- return sw.toString();
- }
-
- // value = comma-delimited list of tokens, where token = (package name|*)
- // e.g. "com.package1", or "com.android.systemui, com.android.keyguard" or "*"
- static Filter parse(String value) {
- if (value == null) return null;
- ArraySet<String> toInclude = new ArraySet<String>();
- ArraySet<String> toExclude = new ArraySet<String>();
- for (String token : value.split(",")) {
- token = token.trim();
- if (token.startsWith("-") && token.length() > 1) {
- token = token.substring(1);
- toExclude.add(token);
- } else {
- toInclude.add(token);
- }
- }
- return new Filter(toInclude, toExclude);
- }
- }
-
- /**
- * Interface to listen for updates to the filter triggered by the content observer listening to
- * the SYSTEM_BAR_VISIBILITY_OVERRIDE flag.
- */
- interface FilterListener {
-
- /** Callback triggered when the content observer updates the filter. */
- void onFilterUpdated();
- }
-
- private BarControlPolicy() {}
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
deleted file mode 100644
index f2ca4956be07..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
+++ /dev/null
@@ -1,187 +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.wm;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.util.ArraySet;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.view.IDisplayWindowInsetsController;
-import android.view.IWindowManager;
-import android.view.InsetsController;
-import android.view.InsetsSourceControl;
-import android.view.InsetsState;
-import android.view.WindowInsets;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.TransactionPool;
-
-import java.util.Objects;
-
-/**
- * Controller that maps between displays and {@link IDisplayWindowInsetsController} in order to
- * give system bar control to SystemUI.
- * {@link R.bool#config_remoteInsetsControllerControlsSystemBars} determines whether this controller
- * takes control or not.
- */
-public class DisplaySystemBarsController extends DisplayImeController {
-
- private static final String TAG = "DisplaySystemBarsController";
-
- private final Context mContext;
- private final DisplayController mDisplayController;
- private final Handler mHandler;
- private SparseArray<PerDisplay> mPerDisplaySparseArray;
-
- public DisplaySystemBarsController(
- Context context,
- IWindowManager wmService,
- DisplayController displayController,
- @Main Handler mainHandler,
- TransactionPool transactionPool) {
- super(wmService, displayController, (r) -> mainHandler.post(r), transactionPool);
- mContext = context;
- mDisplayController = displayController;
- mHandler = mainHandler;
- }
-
- @Override
- public void onDisplayAdded(int displayId) {
- PerDisplay pd = new PerDisplay(displayId);
- try {
- mWmService.setDisplayWindowInsetsController(displayId, pd);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to set insets controller on display " + displayId);
- }
- // Lazy loading policy control filters instead of during boot.
- if (mPerDisplaySparseArray == null) {
- mPerDisplaySparseArray = new SparseArray<>();
- BarControlPolicy.reloadFromSetting(mContext);
- BarControlPolicy.registerContentObserver(mContext, mHandler, () -> {
- int size = mPerDisplaySparseArray.size();
- for (int i = 0; i < size; i++) {
- mPerDisplaySparseArray.valueAt(i).modifyDisplayWindowInsets();
- }
- });
- }
- mPerDisplaySparseArray.put(displayId, pd);
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- try {
- mWmService.setDisplayWindowInsetsController(displayId, null);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to remove insets controller on display " + displayId);
- }
- mPerDisplaySparseArray.remove(displayId);
- }
-
- @VisibleForTesting
- class PerDisplay extends DisplayImeController.PerDisplay {
-
- int mDisplayId;
- InsetsController mInsetsController;
- InsetsState mInsetsState = new InsetsState();
- String mPackageName;
-
- PerDisplay(int displayId) {
- super(displayId, mDisplayController.getDisplayLayout(displayId).rotation());
- mDisplayId = displayId;
- mInsetsController = new InsetsController(
- new DisplaySystemBarsInsetsControllerHost(mHandler, this));
- }
-
- @Override
- public void insetsChanged(InsetsState insetsState) {
- super.insetsChanged(insetsState);
- if (mInsetsState.equals(insetsState)) {
- return;
- }
- mInsetsState.set(insetsState, true /* copySources */);
- mInsetsController.onStateChanged(insetsState);
- if (mPackageName != null) {
- modifyDisplayWindowInsets();
- }
- }
-
- @Override
- public void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls) {
- super.insetsControlChanged(insetsState, activeControls);
- mInsetsController.onControlsChanged(activeControls);
- }
-
- @Override
- public void hideInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
- if ((types & WindowInsets.Type.ime()) == 0) {
- mInsetsController.hide(types);
- } else {
- super.hideInsets(types, fromIme);
- }
-
- }
-
- @Override
- public void showInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) {
- if ((types & WindowInsets.Type.ime()) == 0) {
- mInsetsController.show(types);
- } else {
- super.showInsets(types, fromIme);
- }
-
- }
-
- @Override
- public void topFocusedWindowChanged(String packageName) {
- if (Objects.equals(mPackageName, packageName)) {
- return;
- }
- mPackageName = packageName;
- modifyDisplayWindowInsets();
- }
-
- private void modifyDisplayWindowInsets() {
- if (mPackageName == null) {
- return;
- }
- int[] barVisibilities = BarControlPolicy.getBarVisibilities(mPackageName);
- updateInsetsState(barVisibilities[0], /* visible= */ true);
- updateInsetsState(barVisibilities[1], /* visible= */ false);
- showInsets(barVisibilities[0], /* fromIme= */ false);
- hideInsets(barVisibilities[1], /* fromIme= */ false);
- try {
- mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to update window manager service.");
- }
- }
-
- private void updateInsetsState(@WindowInsets.Type.InsetsType int types, boolean visible) {
- ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
- for (int i = internalTypes.size() - 1; i >= 0; i--) {
- mInsetsState.getSource(internalTypes.valueAt(i)).setVisible(visible);
- }
- }
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsInsetsControllerHost.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsInsetsControllerHost.java
deleted file mode 100644
index 2f8da44ba851..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsInsetsControllerHost.java
+++ /dev/null
@@ -1,173 +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.wm;
-
-import android.annotation.NonNull;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.IDisplayWindowInsetsController;
-import android.view.InsetsController;
-import android.view.InsetsState;
-import android.view.SurfaceControl;
-import android.view.SyncRtSurfaceTransactionApplier;
-import android.view.WindowInsets;
-import android.view.WindowInsetsAnimation;
-import android.view.WindowInsetsController;
-import android.view.inputmethod.InputMethodManager;
-
-import java.util.List;
-
-/**
- * Implements {@link InsetsController.Host} for usage by
- * {@link DisplaySystemBarsController.PerDisplay} instances in {@link DisplaySystemBarsController}.
- * @hide
- */
-public class DisplaySystemBarsInsetsControllerHost implements InsetsController.Host {
-
- private static final String TAG = DisplaySystemBarsInsetsControllerHost.class.getSimpleName();
-
- private final Handler mHandler;
- private final IDisplayWindowInsetsController mController;
- private final float[] mTmpFloat9 = new float[9];
-
- public DisplaySystemBarsInsetsControllerHost(
- Handler handler, IDisplayWindowInsetsController controller) {
- mHandler = handler;
- mController = controller;
- }
-
- @Override
- public Handler getHandler() {
- return mHandler;
- }
-
- @Override
- public void notifyInsetsChanged() {
- // no-op
- }
-
- @Override
- public void dispatchWindowInsetsAnimationPrepare(@NonNull WindowInsetsAnimation animation) {
- // no-op
- }
-
- @Override
- public WindowInsetsAnimation.Bounds dispatchWindowInsetsAnimationStart(
- @NonNull WindowInsetsAnimation animation,
- @NonNull WindowInsetsAnimation.Bounds bounds) {
- return null;
- }
-
- @Override
- public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets,
- @NonNull List<WindowInsetsAnimation> runningAnimations) {
- return null;
- }
-
- @Override
- public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) {
- // no-op
- }
-
- @Override
- public void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
- for (int i = params.length - 1; i >= 0; i--) {
- SyncRtSurfaceTransactionApplier.applyParams(
- new SurfaceControl.Transaction(), params[i], mTmpFloat9);
- }
-
- }
-
- @Override
- public void updateCompatSysUiVisibility(
- @InsetsState.InternalInsetsType int type, boolean visible, boolean hasControl) {
- // no-op
- }
-
- @Override
- public void onInsetsModified(InsetsState insetsState) {
- try {
- mController.insetsChanged(insetsState);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send insets to controller");
- }
- }
-
- @Override
- public boolean hasAnimationCallbacks() {
- return false;
- }
-
- @Override
- public void setSystemBarsAppearance(
- @WindowInsetsController.Appearance int appearance,
- @WindowInsetsController.Appearance int mask) {
- // no-op
- }
-
- @Override
- public @WindowInsetsController.Appearance int getSystemBarsAppearance() {
- return 0;
- }
-
- @Override
- public void setSystemBarsBehavior(@WindowInsetsController.Behavior int behavior) {
- // no-op
- }
-
- @Override
- public @WindowInsetsController.Behavior int getSystemBarsBehavior() {
- return 0;
- }
-
- @Override
- public void releaseSurfaceControlFromRt(SurfaceControl surfaceControl) {
- surfaceControl.release();
- }
-
- @Override
- public void addOnPreDrawRunnable(Runnable r) {
- mHandler.post(r);
- }
-
- @Override
- public void postInsetsAnimationCallback(Runnable r) {
- mHandler.post(r);
- }
-
- @Override
- public InputMethodManager getInputMethodManager() {
- return null;
- }
-
- @Override
- public String getRootViewTitle() {
- return null;
- }
-
- @Override
- public int dipToPx(int dips) {
- return 0;
- }
-
- @Override
- public IBinder getWindowToken() {
- return null;
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java b/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
deleted file mode 100644
index 27aabffd5090..000000000000
--- a/packages/CarSystemUI/src/com/android/systemui/wmshell/CarWMShellModule.java
+++ /dev/null
@@ -1,49 +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.wmshell;
-
-import android.content.Context;
-import android.os.Handler;
-import android.view.IWindowManager;
-
-import com.android.systemui.dagger.WMSingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.wm.DisplaySystemBarsController;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.pip.Pip;
-
-import dagger.BindsOptionalOf;
-import dagger.Module;
-import dagger.Provides;
-
-/** Provides dependencies from {@link com.android.wm.shell} for CarSystemUI. */
-@Module(includes = WMShellBaseModule.class)
-public abstract class CarWMShellModule {
- @WMSingleton
- @Provides
- static DisplayImeController provideDisplayImeController(Context context,
- IWindowManager wmService, DisplayController displayController,
- @Main Handler mainHandler, TransactionPool transactionPool) {
- return new DisplaySystemBarsController(context, wmService, displayController,
- mainHandler, transactionPool);
- }
-
- @BindsOptionalOf
- abstract Pip optionalPip();
-}
diff --git a/packages/CarSystemUI/tests/Android.mk b/packages/CarSystemUI/tests/Android.mk
deleted file mode 100644
index 1366568c3a66..000000000000
--- a/packages/CarSystemUI/tests/Android.mk
+++ /dev/null
@@ -1,88 +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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_DX_FLAGS := --multi-dex
-
-LOCAL_PACKAGE_NAME := CarSystemUITests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- CarSystemUI-tests
-
-LOCAL_MULTILIB := both
-
-LOCAL_JNI_SHARED_LIBRARIES := \
- libdexmakerjvmtiagent \
- libmultiplejvmtiagentsinterferenceagent
-
-LOCAL_JAVA_LIBRARIES := \
- android.test.runner \
- telephony-common \
- android.test.base \
-
-LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui
-
-# sign this with platform cert, so this test is allowed to inject key events into
-# UI it doesn't own. This is necessary to allow screenshots to be taken
-LOCAL_CERTIFICATE := platform
-
-# Provide jack a list of classes to exclude from code coverage.
-# This is needed because the CarSystemUITests compile CarSystemUI source directly, rather than using
-# LOCAL_INSTRUMENTATION_FOR := CarSystemUI.
-#
-# We want to exclude the test classes from code coverage measurements, but they share the same
-# package as the rest of SystemUI so they can't be easily filtered by package name.
-#
-# Generate a comma separated list of patterns based on the test source files under src/
-# SystemUI classes are in ../src/ so they won't be excluded.
-# Example:
-# Input files: src/com/android/systemui/Test.java src/com/android/systemui/AnotherTest.java
-# Generated exclude list: com.android.systemui.Test*,com.android.systemui.AnotherTest*
-
-# Filter all src files under src/ to just java files
-local_java_files := $(filter %.java,$(call all-java-files-under, src))
-
-# Transform java file names into full class names.
-# This only works if the class name matches the file name and the directory structure
-# matches the package.
-local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files)))
-local_comma := ,
-local_empty :=
-local_space := $(local_empty) $(local_empty)
-
-# Convert class name list to jacoco exclude list
-# This appends a * to all classes and replace the space separators with commas.
-jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
-
-LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*,com.android.keyguard.*
-LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
-
-ifeq ($(EXCLUDE_SYSTEMUI_TESTS),)
- include $(BUILD_PACKAGE)
-endif
-
-# Reset variables
-local_java_files :=
-local_classes :=
-local_comma :=
-local_space :=
-jacoco_exclude :=
diff --git a/packages/CarSystemUI/tests/AndroidManifest.xml b/packages/CarSystemUI/tests/AndroidManifest.xml
deleted file mode 100644
index a74bb56d8d75..000000000000
--- a/packages/CarSystemUI/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:sharedUserId="android.uid.system"
- package="com.android.systemui.tests">
-
- <application android:debuggable="true" android:largeHeap="true">
- <uses-library android:name="android.test.runner" />
-
- <provider
- android:name="androidx.lifecycle.ProcessLifecycleOwnerInitializer"
- tools:replace="android:authorities"
- android:authorities="${applicationId}.lifecycle-tests"
- android:exported="false"
- android:enabled="false"
- android:multiprocess="true" />
- </application>
-
- <instrumentation android:name="android.testing.TestableInstrumentation"
- android:targetPackage="com.android.systemui.tests"
- android:label="Tests for CarSystemUI">
- </instrumentation>
-</manifest>
diff --git a/packages/CarSystemUI/tests/AndroidTest.xml b/packages/CarSystemUI/tests/AndroidTest.xml
deleted file mode 100644
index 8685632f2b63..000000000000
--- a/packages/CarSystemUI/tests/AndroidTest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<configuration description="Runs Tests for CarSystemUI.">
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
- <option name="test-file-name" value="CarSystemUITests.apk" />
- </target_preparer>
-
- <option name="test-suite-tag" value="apct" />
- <option name="test-suite-tag" value="framework-base-presubmit" />
- <option name="test-tag" value="CarSystemUITests" />
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.systemui.tests" />
- <option name="runner" value="android.testing.TestableInstrumentation" />
- <option name="hidden-api-checks" value="false"/>
- </test>
-</configuration>
diff --git a/packages/CarSystemUI/tests/res/layout/button_role_holder_controller_test.xml b/packages/CarSystemUI/tests/res/layout/button_role_holder_controller_test.xml
deleted file mode 100644
index 25ec2c179c8c..000000000000
--- a/packages/CarSystemUI/tests/res/layout/button_role_holder_controller_test.xml
+++ /dev/null
@@ -1,41 +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.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:id="@id/nav_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:gravity="center">
-
- <com.android.systemui.car.navigationbar.AssitantButton
- android:id="@+id/assistant_role_button"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/car_ic_overview"
- systemui:useDefaultAppIconForRole="true"
- />
-
- <com.android.systemui.car.navigationbar.AssitantButton
- android:id="@+id/assistant_role_disabled_button"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/car_ic_overview"
- />
-
-</LinearLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml b/packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml
deleted file mode 100644
index a8e83d6d7717..000000000000
--- a/packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml
+++ /dev/null
@@ -1,55 +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.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:id="@id/nav_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:gravity="center">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/detectable_by_component_name"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/detectable_by_category"
- style="@style/NavigationBarButton"
- systemui:categories="android.intent.category.APP_MAPS"
- systemui:icon="@drawable/car_ic_navigation"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;launchFlags=0x14000000;end"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/detectable_by_package"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/car_ic_phone"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
- systemui:packages="com.android.car.dialer"
- systemui:highlightWhenSelected="true"
- />
-
-</LinearLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/tests/res/layout/car_navigation_bar_view_test.xml b/packages/CarSystemUI/tests/res/layout/car_navigation_bar_view_test.xml
deleted file mode 100644
index 94edc4b5e245..000000000000
--- a/packages/CarSystemUI/tests/res/layout/car_navigation_bar_view_test.xml
+++ /dev/null
@@ -1,58 +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.
- -->
-
-<com.android.systemui.car.navigationbar.CarNavigationBarView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/system_bar_background"
- android:orientation="vertical">
- <!--The 20dp padding is the difference between the background selected icon size and the ripple
- that was chosen, thus it's a hack to make it look pretty and not an official margin value-->
- <LinearLayout
- android:id="@id/nav_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:gravity="center">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_overview_selected"
- systemui:highlightWhenSelected="true"
- />
-
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/lock_screen_nav_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingStart="@dimen/car_keyline_1"
- android:paddingEnd="@dimen/car_keyline_1"
- android:gravity="center"
- android:visibility="gone"
- />
-
-</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml b/packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml
deleted file mode 100644
index 44f834040391..000000000000
--- a/packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml
+++ /dev/null
@@ -1,124 +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.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res-auto"
- android:id="@id/nav_buttons"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:gravity="center">
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/default_no_selection_state"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_overview_selected"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/app_grid_activity"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
- systemui:icon="@drawable/car_ic_apps"
- systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
- systemui:selectedIcon="@drawable/car_ic_apps_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/long_click_app_grid_activity"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
- systemui:icon="@drawable/car_ic_apps"
- systemui:longIntent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
- systemui:selectedIcon="@drawable/car_ic_apps_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/broadcast"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"
- systemui:broadcast="true"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/selected_icon_undefined"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/highlightable_no_more_button"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_overview_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/not_highlightable_more_button"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_overview_selected"
- systemui:showMoreWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/highlightable_more_button"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_overview_selected"
- systemui:highlightWhenSelected="true"
- systemui:showMoreWhenSelected="true"
- />
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/broadcast"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_overview_selected"
- systemui:broadcast="true"
- />
-
- <com.android.systemui.car.navigationbar.AssitantButton
- android:id="@+id/role_based_button"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/car_ic_overview"
- systemui:selectedIcon="@drawable/car_ic_overview_selected"
- systemui:useDefaultAppIconForRole="true"
- systemui:highlightWhenSelected="true"
- />
-
-</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
deleted file mode 100644
index 165193e86c96..000000000000
--- a/packages/CarSystemUI/tests/res/layout/overlay_view_controller_test.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?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/res/layout/overlay_view_global_state_controller_test.xml b/packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml
deleted file mode 100644
index 03fe0e4fcf2e..000000000000
--- a/packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?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_1"
- android:inflatedId="@+id/overlay_view_controller_1"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout="@layout/overlay_view_controller_stub"/>
-
- <ViewStub android:id="@+id/overlay_view_controller_stub_2"
- android:inflatedId="@+id/overlay_view_controller_2"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout="@layout/overlay_view_controller_stub"/>
-
- <ViewStub android:id="@+id/overlay_view_controller_stub_3"
- android:inflatedId="@+id/overlay_view_controller_3"
- 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/res/values/config.xml b/packages/CarSystemUI/tests/res/values/config.xml
deleted file mode 100644
index 0d08ac26d962..000000000000
--- a/packages/CarSystemUI/tests/res/values/config.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<resources>
- <!-- Configure which system ui bars should be displayed.
- These can be overwritten within the tests. -->
- <bool name="config_enableLeftNavigationBar">false</bool>
- <bool name="config_enableRightNavigationBar">false</bool>
- <bool name="config_enableBottomNavigationBar">false</bool>
-</resources>
diff --git a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
deleted file mode 100644
index 86b86d482eee..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
+++ /dev/null
@@ -1,216 +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;
-
-import static org.hamcrest.Matchers.empty;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-
-import android.testing.AndroidTestingRunner;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.test.filters.LargeTest;
-import androidx.test.filters.MediumTest;
-import androidx.test.filters.SmallTest;
-import androidx.test.internal.runner.ClassPathScanner;
-import androidx.test.internal.runner.ClassPathScanner.ChainedClassNameFilter;
-import androidx.test.internal.runner.ClassPathScanner.ExternalClassNameFilter;
-
-import com.android.systemui.SysuiBaseFragmentTest;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarSystemUiTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * This is named AAAPlusPlusVerifySysuiRequiredTestPropertiesTest for two reasons.
- * a) Its so awesome it deserves an AAA++
- * b) It should run first to draw attention to itself.
- *
- * For trues though: this test verifies that all the sysui tests extend the right classes.
- * This matters because including tests with different context implementations in the same
- * test suite causes errors, such as the incorrect settings provider being cached.
- * For an example, see {@link com.android.systemui.DependencyTest}.
- */
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@SmallTest
-public class AAAPlusPlusVerifySysuiRequiredTestPropertiesTest extends SysuiTestCase {
-
- private static final String TAG = "AAA++VerifyTest";
-
- private static final Class[] BASE_CLS_TO_INCLUDE = {
- SysuiTestCase.class,
- SysuiBaseFragmentTest.class,
- };
-
- private static final Class[] SUPPORTED_SIZES = {
- SmallTest.class,
- MediumTest.class,
- LargeTest.class,
- android.test.suitebuilder.annotation.SmallTest.class,
- android.test.suitebuilder.annotation.MediumTest.class,
- android.test.suitebuilder.annotation.LargeTest.class,
- };
-
- @Test
- public void testAllClassInheritance() throws Throwable {
- ArrayList<String> fails = new ArrayList<>();
- for (String className : getClassNamesFromClassPath()) {
- Class<?> cls = Class.forName(className, false, this.getClass().getClassLoader());
- if (!isTestClass(cls)) continue;
-
- boolean hasParent = false;
- for (Class<?> parent : BASE_CLS_TO_INCLUDE) {
- if (parent.isAssignableFrom(cls)) {
- hasParent = true;
- break;
- }
- }
- boolean hasSize = hasSize(cls);
- if (!hasSize) {
- fails.add(cls.getName() + " does not have size annotation, such as @SmallTest");
- }
- if (!hasParent) {
- fails.add(cls.getName() + " does not extend any of " + getClsStr());
- }
- }
-
- assertThat("All sysui test classes must have size and extend one of " + getClsStr(),
- fails, is(empty()));
- }
-
- private boolean hasSize(Class<?> cls) {
- for (int i = 0; i < SUPPORTED_SIZES.length; i++) {
- if (cls.getDeclaredAnnotation(SUPPORTED_SIZES[i]) != null) return true;
- }
- return false;
- }
-
- private Collection<String> getClassNamesFromClassPath() {
- ClassPathScanner scanner = new ClassPathScanner(mContext.getPackageCodePath());
-
- ChainedClassNameFilter filter = new ChainedClassNameFilter();
-
- filter.add(new ExternalClassNameFilter());
- filter.add(s -> s.startsWith("com.android.systemui")
- || s.startsWith("com.android.keyguard"));
-
- try {
- return scanner.getClassPathEntries(filter);
- } catch (IOException e) {
- Log.e(TAG, "Failed to scan classes", e);
- }
- return Collections.emptyList();
- }
-
- private String getClsStr() {
- return TextUtils.join(",", Arrays.asList(BASE_CLS_TO_INCLUDE)
- .stream().map(cls -> cls.getSimpleName()).toArray());
- }
-
- /**
- * Determines if given class is a valid test class.
- *
- * @return <code>true</code> if loadedClass is a test
- */
- private boolean isTestClass(Class<?> loadedClass) {
- try {
- if (Modifier.isAbstract(loadedClass.getModifiers())) {
- logDebug(String.format("Skipping abstract class %s: not a test",
- loadedClass.getName()));
- return false;
- }
- // TODO: try to find upstream junit calls to replace these checks
- if (junit.framework.Test.class.isAssignableFrom(loadedClass)) {
- // ensure that if a TestCase, it has at least one test method otherwise
- // TestSuite will throw error
- if (junit.framework.TestCase.class.isAssignableFrom(loadedClass)) {
- return hasJUnit3TestMethod(loadedClass);
- }
- return true;
- }
- // TODO: look for a 'suite' method?
- if (loadedClass.isAnnotationPresent(RunWith.class)) {
- return true;
- }
- for (Method testMethod : loadedClass.getMethods()) {
- if (testMethod.isAnnotationPresent(Test.class)) {
- return true;
- }
- }
- logDebug(String.format("Skipping class %s: not a test", loadedClass.getName()));
- return false;
- } catch (Exception e) {
- // Defensively catch exceptions - Will throw runtime exception if it cannot load
- // methods.
- // For earlier versions of Android (Pre-ICS), Dalvik might try to initialize a class
- // during getMethods(), fail to do so, hide the error and throw a NoSuchMethodException.
- // Since the java.lang.Class.getMethods does not declare such an exception, resort to a
- // generic catch all.
- // For ICS+, Dalvik will throw a NoClassDefFoundException.
- Log.w(TAG, String.format("%s in isTestClass for %s", e.toString(),
- loadedClass.getName()));
- return false;
- } catch (Error e) {
- // defensively catch Errors too
- Log.w(TAG, String.format("%s in isTestClass for %s", e.toString(),
- loadedClass.getName()));
- return false;
- }
- }
-
- private boolean hasJUnit3TestMethod(Class<?> loadedClass) {
- for (Method testMethod : loadedClass.getMethods()) {
- if (isPublicTestMethod(testMethod)) {
- return true;
- }
- }
- return false;
- }
-
- // copied from junit.framework.TestSuite
- private boolean isPublicTestMethod(Method m) {
- return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
- }
-
- // copied from junit.framework.TestSuite
- private boolean isTestMethod(Method m) {
- return m.getParameterTypes().length == 0 && m.getName().startsWith("test")
- && m.getReturnType().equals(Void.TYPE);
- }
-
- /**
- * Utility method for logging debug messages. Only actually logs a message if TAG is marked
- * as loggable to limit log spam during normal use.
- */
- private void logDebug(String msg) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, msg);
- }
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java
deleted file mode 100644
index fe071d54fb10..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java
+++ /dev/null
@@ -1,234 +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.car.hvac;
-
-import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
-import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
-import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
-
-import static com.android.systemui.car.hvac.HvacController.convertToCelsius;
-import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.car.Car;
-import android.car.VehicleUnit;
-import android.car.hardware.property.CarPropertyManager;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.widget.TextView;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.CarSystemUiTest;
-
-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 java.util.concurrent.Executor;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class AdjustableTemperatureViewTest extends SysuiTestCase {
-
- private static final float TEMP_CELSIUS = 22.0f;
- private final String mFormat = getContext().getString(R.string.hvac_temperature_format);
- private AdjustableTemperatureView mAdjustableTemperatureView;
- private HvacController mHvacController;
-
- @Mock
- private Car mCar;
- @Mock
- private CarPropertyManager mCarPropertyManager;
- @Mock
- private Executor mExecutor;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mCar.isConnected()).thenReturn(true);
- when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
-
- CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
- mHvacController = new HvacController(carServiceProvider, mExecutor);
- mHvacController.connectToCarService();
- mAdjustableTemperatureView = new AdjustableTemperatureView(getContext(), /* attrs= */ null);
- mAdjustableTemperatureView.onFinishInflate();
- mAdjustableTemperatureView.setHvacController(mHvacController);
- }
-
- @Test
- public void addTemperatureViewToController_setsTemperatureView() {
- when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
- anyInt())).thenReturn(true);
- when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
- TEMP_CELSIUS);
-
- mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
-
- TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
- assertEquals(tempText.getText(), String.format(mFormat, TEMP_CELSIUS));
- }
-
- @Test
- public void setTemp_tempNaN_setsTextToNaNText() {
- when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
- anyInt())).thenReturn(true);
- when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
- Float.NaN);
-
- mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
-
- TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
- assertEquals(tempText.getText(),
- getContext().getResources().getString(R.string.hvac_null_temp_text));
- }
-
- @Test
- public void setTemp_tempBelowMin_setsTextToMinTempText() {
- when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
- anyInt())).thenReturn(true);
- when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
- getContext().getResources().getFloat(R.dimen.hvac_min_value_celsius));
-
- mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
-
- TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
- assertEquals(tempText.getText(),
- getContext().getResources().getString(R.string.hvac_min_text));
- }
-
- @Test
- public void setTemp_tempAboveMax_setsTextToMaxTempText() {
- when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
- anyInt())).thenReturn(true);
- when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
- getContext().getResources().getFloat(R.dimen.hvac_max_value_celsius));
-
- mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
-
- TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
- assertEquals(tempText.getText(),
- getContext().getResources().getString(R.string.hvac_max_text));
- }
-
- @Test
- public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
- when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
- anyInt())).thenReturn(true);
- when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
- TEMP_CELSIUS);
- when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
- when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
-
- mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
-
- TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
- assertEquals(tempText.getText(), String.format(mFormat, convertToFahrenheit(TEMP_CELSIUS)));
- }
-
- @Test
- public void adjustableViewIncreaseButton_setsTempWithCarPropertyManager() {
- when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
- anyInt())).thenReturn(true);
- when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
- TEMP_CELSIUS);
- mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
-
- mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick();
-
- ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mExecutor).execute(setTempRunnableCaptor.capture());
- setTempRunnableCaptor.getValue().run();
- verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
- eq(TEMP_CELSIUS + 1));
- }
-
- @Test
- public void adjustableViewDecreaseButton_setsTempWithCarPropertyManager() {
- when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
- anyInt())).thenReturn(true);
- when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
- TEMP_CELSIUS);
- mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
-
- mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick();
-
- ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mExecutor).execute(setTempRunnableCaptor.capture());
- setTempRunnableCaptor.getValue().run();
- verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
- eq(TEMP_CELSIUS - 1));
- }
-
- @Test
- public void adjustableViewIncreaseButton_inFahrenheit_setsTempWithCarPropertyManager() {
- when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
- anyInt())).thenReturn(true);
- when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
- TEMP_CELSIUS);
- when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
- when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
- mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
-
- mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick();
-
- ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mExecutor).execute(setTempRunnableCaptor.capture());
- setTempRunnableCaptor.getValue().run();
- verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
- eq(convertToCelsius(convertToFahrenheit(TEMP_CELSIUS) + 1)));
- }
-
- @Test
- public void adjustableViewDecreaseButton_inFahrenheit_setsTempWithCarPropertyManager() {
- when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
- anyInt())).thenReturn(true);
- when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
- TEMP_CELSIUS);
- when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
- when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
- mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
-
- mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick();
-
- ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mExecutor).execute(setTempRunnableCaptor.capture());
- setTempRunnableCaptor.getValue().run();
- verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
- eq(convertToCelsius(convertToFahrenheit(TEMP_CELSIUS) - 1)));
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
deleted file mode 100644
index 52f07dfd6b81..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
+++ /dev/null
@@ -1,146 +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.car.hvac;
-
-import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
-import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
-import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.car.Car;
-import android.car.VehicleUnit;
-import android.car.hardware.property.CarPropertyManager;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class HvacControllerTest extends SysuiTestCase {
-
- private static final int AREA_ID = 1;
- private static final float TEMP = 72.0f;
-
- private HvacController mHvacController;
-
- @Mock
- private Car mCar;
- @Mock
- private CarPropertyManager mCarPropertyManager;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mCar.isConnected()).thenReturn(true);
- when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
-
- CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
- mHvacController = new HvacController(carServiceProvider,
- new FakeExecutor(new FakeSystemClock()));
- mHvacController.connectToCarService();
- }
-
- @Test
- public void connectToCarService_registersCallback() {
- verify(mCarPropertyManager).registerCallback(any(), eq(HVAC_TEMPERATURE_SET), anyFloat());
- verify(mCarPropertyManager).registerCallback(any(), eq(HVAC_TEMPERATURE_DISPLAY_UNITS),
- anyFloat());
- }
-
- @Test
- public void addTemperatureViewToController_usingTemperatureView_registersView() {
- TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
- mHvacController.addTemperatureViewToController(v);
-
- verify(v).setTemp(TEMP);
- }
-
- @Test
- public void addTemperatureViewToController_usingSameTemperatureView_registersFirstView() {
- TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
- mHvacController.addTemperatureViewToController(v);
- verify(v).setTemp(TEMP);
- resetTemperatureView(v, AREA_ID);
-
- mHvacController.addTemperatureViewToController(v);
- verify(v, never()).setTemp(TEMP);
- }
-
- @Test
- public void addTemperatureViewToController_usingDifferentTemperatureView_registersBothViews() {
- TemperatureTextView v1 = setupMockTemperatureTextView(AREA_ID, TEMP);
- mHvacController.addTemperatureViewToController(v1);
- verify(v1).setTemp(TEMP);
-
- TemperatureTextView v2 = setupMockTemperatureTextView(
- AREA_ID + 1,
- TEMP + 1);
- mHvacController.addTemperatureViewToController(v2);
- verify(v2).setTemp(TEMP + 1);
- }
-
- @Test
- public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
- when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
- when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
- TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
-
- mHvacController.addTemperatureViewToController(v);
-
- verify(v).setDisplayInFahrenheit(true);
- verify(v).setTemp(TEMP);
- }
-
- private TemperatureTextView setupMockTemperatureTextView(int areaId, float value) {
- TemperatureTextView v = mock(TemperatureTextView.class);
- resetTemperatureView(v, areaId);
- when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, areaId)).thenReturn(
- true);
- when(mCarPropertyManager.getFloatProperty(HVAC_TEMPERATURE_SET, areaId)).thenReturn(value);
- return v;
- }
-
- private void resetTemperatureView(TemperatureTextView view, int areaId) {
- reset(view);
- when(view.getAreaId()).thenReturn(areaId);
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java
deleted file mode 100644
index 3ed811105a54..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java
+++ /dev/null
@@ -1,110 +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.car.hvac;
-
-import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
-import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
-import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
-
-import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-import android.car.Car;
-import android.car.VehicleUnit;
-import android.car.hardware.property.CarPropertyManager;
-import android.content.Context;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class TemperatureTextViewTest extends SysuiTestCase {
- private static final float TEMP = 72.0f;
- private final String mFormat = getContext().getString(R.string.hvac_temperature_format);
- private HvacController mHvacController;
- private TemperatureTextView mTextView;
-
- @Mock
- private Context mContext;
-
- @Mock
- private Car mCar;
- @Mock
- private CarPropertyManager mCarPropertyManager;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mCar.isConnected()).thenReturn(true);
- when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
-
- CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
- mHvacController = new HvacController(carServiceProvider,
- new FakeExecutor(new FakeSystemClock()));
- mHvacController.connectToCarService();
- mTextView = new TemperatureTextView(getContext(), /* attrs= */ null);
- }
-
- @Test
- public void addTemperatureViewToController_usingTemperatureView_registersView() {
- when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
- anyInt())).thenReturn(true);
- when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
- TEMP);
-
- mHvacController.addTemperatureViewToController(mTextView);
-
- assertEquals(mTextView.getText(), String.format(mFormat, TEMP));
- }
-
- @Test
- public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
- when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
- anyInt())).thenReturn(true);
- when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
- TEMP);
- when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
- when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
-
- mHvacController.addTemperatureViewToController(mTextView);
-
- assertEquals(mTextView.getText(), String.format(mFormat, convertToFahrenheit(TEMP)));
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
deleted file mode 100644
index 062ab4115263..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
+++ /dev/null
@@ -1,199 +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.car.keyguard;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.os.Handler;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.car.navigationbar.CarNavigationBarController;
-import com.android.systemui.car.window.OverlayViewGlobalStateController;
-import com.android.systemui.statusbar.phone.BiometricUnlockController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class CarKeyguardViewControllerTest extends SysuiTestCase {
-
- private CarKeyguardViewController mCarKeyguardViewController;
-
- @Mock
- private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
- @Mock
- private CarKeyguardViewController.OnKeyguardCancelClickedListener mCancelClickedListener;
- @Mock
- private KeyguardBouncer.Factory mKeyguardBouncerFactory;
- @Mock
- private KeyguardBouncer mBouncer;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- when(mKeyguardBouncerFactory.create(
- any(ViewGroup.class),
- any(KeyguardBouncer.BouncerExpansionCallback.class)))
- .thenReturn(mBouncer);
-
- mCarKeyguardViewController = new CarKeyguardViewController(
- Handler.getMain(),
- mock(CarServiceProvider.class),
- mOverlayViewGlobalStateController,
- mock(KeyguardStateController.class),
- mock(KeyguardUpdateMonitor.class),
- () -> mock(BiometricUnlockController.class),
- mock(ViewMediatorCallback.class),
- mock(CarNavigationBarController.class),
- mKeyguardBouncerFactory
- );
- mCarKeyguardViewController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate(
- R.layout.sysui_overlay_window, /* root= */ null));
- }
-
- @Test
- public void onShow_bouncerIsSecure_showsBouncerWithSecuritySelectionReset() {
- when(mBouncer.isSecure()).thenReturn(true);
- mCarKeyguardViewController.show(/* options= */ null);
-
- verify(mBouncer).show(/* resetSecuritySelection= */ true);
- }
-
- @Test
- public void onShow_bouncerIsSecure_keyguardIsVisible() {
- when(mBouncer.isSecure()).thenReturn(true);
- mCarKeyguardViewController.show(/* options= */ null);
-
- verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController), any());
- }
-
- @Test
- public void onShow_bouncerNotSecure_hidesBouncerAndDestroysTheView() {
- when(mBouncer.isSecure()).thenReturn(false);
- mCarKeyguardViewController.show(/* options= */ null);
-
- verify(mBouncer).hide(/* destroyView= */ true);
- }
-
- @Test
- public void onShow_bouncerNotSecure_keyguardIsNotVisible() {
- when(mBouncer.isSecure()).thenReturn(false);
- mCarKeyguardViewController.show(/* options= */ null);
-
- // Here we check for both showView and hideView since the current implementation of show
- // with bouncer being not secure has the following method execution orders:
- // 1) show -> start -> showView
- // 2) show -> reset -> dismissAndCollapse -> hide -> stop -> hideView
- // Hence, we want to make sure that showView is called before hideView and not in any
- // other combination.
- InOrder inOrder = inOrder(mOverlayViewGlobalStateController);
- inOrder.verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController),
- any());
- inOrder.verify(mOverlayViewGlobalStateController).hideView(eq(mCarKeyguardViewController),
- any());
- }
-
- @Test
- public void onHide_keyguardShowing_hidesBouncerAndDestroysTheView() {
- when(mBouncer.isSecure()).thenReturn(true);
- mCarKeyguardViewController.show(/* options= */ null);
- mCarKeyguardViewController.hide(/* startTime= */ 0, /* fadeoutDelay= */ 0);
-
- verify(mBouncer).hide(/* destroyView= */ true);
- }
-
- @Test
- public void onHide_keyguardNotShown_doesNotHideOrDestroyBouncer() {
- mCarKeyguardViewController.hide(/* startTime= */ 0, /* fadeoutDelay= */ 0);
-
- verify(mBouncer, never()).hide(anyBoolean());
- }
-
- @Test
- public void onHide_KeyguardNotVisible() {
- when(mBouncer.isSecure()).thenReturn(true);
- mCarKeyguardViewController.show(/* options= */ null);
- mCarKeyguardViewController.hide(/* startTime= */ 0, /* fadeoutDelay= */ 0);
-
- InOrder inOrder = inOrder(mOverlayViewGlobalStateController);
- inOrder.verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController),
- any());
- inOrder.verify(mOverlayViewGlobalStateController).hideView(eq(mCarKeyguardViewController),
- any());
- }
-
- @Test
- public void setOccludedFalse_currentlyOccluded_bouncerReset() {
- when(mBouncer.isSecure()).thenReturn(true);
- mCarKeyguardViewController.show(/* options= */ null);
- mCarKeyguardViewController.setOccluded(/* occluded= */ true, /* animate= */ false);
- reset(mBouncer);
-
- mCarKeyguardViewController.setOccluded(/* occluded= */ false, /* animate= */ false);
-
- verify(mBouncer).show(/* resetSecuritySelection= */ true);
- }
-
- @Test
- public void onCancelClicked_callsCancelClickedListener() {
- when(mBouncer.isSecure()).thenReturn(true);
- mCarKeyguardViewController.show(/* options= */ null);
- mCarKeyguardViewController.registerOnKeyguardCancelClickedListener(mCancelClickedListener);
- mCarKeyguardViewController.onCancelClicked();
-
- verify(mCancelClickedListener).onCancelClicked();
- }
-
- @Test
- public void onCancelClicked_hidesBouncerAndDestroysTheView() {
- when(mBouncer.isSecure()).thenReturn(true);
- mCarKeyguardViewController.show(/* options= */ null);
- mCarKeyguardViewController.registerOnKeyguardCancelClickedListener(mCancelClickedListener);
- mCarKeyguardViewController.onCancelClicked();
-
- verify(mBouncer).hide(/* destroyView= */ true);
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java
deleted file mode 100644
index 4b8268052324..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java
+++ /dev/null
@@ -1,189 +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.car.navigationbar;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.when;
-
-import android.app.role.RoleManager;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.LayoutInflater;
-import android.widget.LinearLayout;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.tests.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class ButtonRoleHolderControllerTest extends SysuiTestCase {
- private static final String TEST_VALID_PACKAGE_NAME = "foo";
- private static final String TEST_INVALID_PACKAGE_NAME = "bar";
- private static final UserHandle TEST_CURRENT_USER = UserHandle.of(100);
- private static final UserHandle TEST_NON_CURRENT_USER = UserHandle.of(101);
-
- private LinearLayout mTestView;
- private CarNavigationButton mNavButtonDefaultAppIconForRoleWithEnabled;
- private CarNavigationButton mNavButtonDefaultAppIconForRoleWithDisabled;
- private ButtonRoleHolderController mControllerUnderTest;
- private Drawable mAppIcon;
-
- @Mock
- private RoleManager mRoleManager;
- @Mock
- private CarDeviceProvisionedController mDeviceProvisionedController;
- @Mock
- private PackageManager mPackageManager;
- @Mock
- private ApplicationInfo mApplicationInfo;
-
- @Before
- public void setUp() throws PackageManager.NameNotFoundException {
- MockitoAnnotations.initMocks(this);
-
- mTestView = (LinearLayout) LayoutInflater.from(mContext).inflate(
- R.layout.button_role_holder_controller_test, /* root= */ null);
- mNavButtonDefaultAppIconForRoleWithEnabled = mTestView
- .findViewById(R.id.assistant_role_button);
- mNavButtonDefaultAppIconForRoleWithDisabled = mTestView
- .findViewById(R.id.assistant_role_disabled_button);
- mAppIcon = mContext.getDrawable(R.drawable.car_ic_apps);
- when(mApplicationInfo.loadIcon(any())).thenReturn(mAppIcon);
- doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager)
- .getApplicationInfo(any(), anyInt());
- doReturn(mApplicationInfo).when(mPackageManager)
- .getApplicationInfo(eq(TEST_VALID_PACKAGE_NAME), anyInt());
- when(mDeviceProvisionedController
- .getCurrentUser())
- .thenReturn(TEST_CURRENT_USER.getIdentifier());
- mControllerUnderTest = new ButtonRoleHolderController(mContext,
- mPackageManager, mRoleManager, mDeviceProvisionedController);
- }
-
- @Test
- public void addAllButtonsWithRoleName_roleAssigned_appIconEnabled_useAssignedAppIcon() {
- when(mRoleManager.getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any()))
- .thenReturn(List.of(TEST_VALID_PACKAGE_NAME));
-
- mControllerUnderTest.addAllButtonsWithRoleName(mTestView);
-
- assertThat(mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon()).isEqualTo(mAppIcon);
- }
-
- @Test
- public void addAllButtonsWithRoleName_roleUnassigned_appIconEnabled_useDefaultIcon() {
- when(mRoleManager.getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any()))
- .thenReturn(null);
-
- mControllerUnderTest.addAllButtonsWithRoleName(mTestView);
-
- assertThat(mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon()).isNull();
- }
-
- @Test
- public void onRoleChanged_currentUser_appIconEnabled_useAssignedAppIcon() {
- when(mRoleManager.getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any()))
- .thenReturn(null);
- mControllerUnderTest.addAllButtonsWithRoleName(mTestView);
- when(mRoleManager
- .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any()))
- .thenReturn(List.of(TEST_VALID_PACKAGE_NAME));
-
- mControllerUnderTest.onRoleChanged(RoleManager.ROLE_ASSISTANT, TEST_CURRENT_USER);
-
- assertThat(mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon()).isEqualTo(mAppIcon);
- }
-
- @Test
- public void onRoleChanged_nonCurrentUser_appIconEnabled_iconIsNotUpdated() {
- when(mRoleManager
- .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any()))
- .thenReturn(null);
- mControllerUnderTest.addAllButtonsWithRoleName(mTestView);
- Drawable beforeIcon = mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon();
- when(mRoleManager
- .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any()))
- .thenReturn(List.of(TEST_VALID_PACKAGE_NAME));
-
- mControllerUnderTest.onRoleChanged(RoleManager.ROLE_ASSISTANT, TEST_NON_CURRENT_USER);
-
- Drawable afterIcon = mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon();
- assertThat(afterIcon).isEqualTo(beforeIcon);
- }
-
- @Test
- public void onRoleChanged_invalidPackage_useDefaultIcon() {
- when(mRoleManager
- .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any()))
- .thenReturn(List.of(TEST_INVALID_PACKAGE_NAME));
-
- mControllerUnderTest.addAllButtonsWithRoleName(mTestView);
-
- assertThat(mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon()).isNull();
- }
-
- @Test
- public void addAllButtonsWithRoleName_appIconDisabled_useDefaultIcon() {
- when(mRoleManager
- .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any()))
- .thenReturn(List.of(TEST_VALID_PACKAGE_NAME));
-
- mControllerUnderTest.addAllButtonsWithRoleName(mTestView);
-
- assertThat(mNavButtonDefaultAppIconForRoleWithDisabled.getAppIcon()).isNull();
- }
-
- @Test
- public void onRoleChanged_roleAssigned_appIconDisabled_useDefaultIcon() {
- when(mRoleManager
- .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any()))
- .thenReturn(null);
- mControllerUnderTest.addAllButtonsWithRoleName(mTestView);
- assertThat(mNavButtonDefaultAppIconForRoleWithDisabled.getAppIcon()).isNull();
- when(mRoleManager
- .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any()))
- .thenReturn(List.of(TEST_VALID_PACKAGE_NAME));
-
- mControllerUnderTest.onRoleChanged(RoleManager.ROLE_ASSISTANT, TEST_CURRENT_USER);
-
- assertThat(mNavButtonDefaultAppIconForRoleWithDisabled.getAppIcon()).isNull();
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java
deleted file mode 100644
index bd017cd2835b..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java
+++ /dev/null
@@ -1,138 +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.car.navigationbar;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.ActivityTaskManager.RootTaskInfo;
-import android.content.ComponentName;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.LayoutInflater;
-import android.widget.LinearLayout;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.tests.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class ButtonSelectionStateControllerTest extends SysuiTestCase {
-
- private static final String TEST_COMPONENT_NAME_PACKAGE = "com.android.car.carlauncher";
- private static final String TEST_COMPONENT_NAME_CLASS = ".CarLauncher";
- private static final String TEST_CATEGORY = "com.google.android.apps.maps";
- private static final String TEST_CATEGORY_CLASS = ".APP_MAPS";
- private static final String TEST_PACKAGE = "com.android.car.dialer";
- private static final String TEST_PACKAGE_CLASS = ".Dialer";
-
- // LinearLayout with CarNavigationButtons with different configurations.
- private LinearLayout mTestView;
- private ButtonSelectionStateController mButtonSelectionStateController;
- private ComponentName mComponentName;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mTestView = (LinearLayout) LayoutInflater.from(mContext).inflate(
- R.layout.car_button_selection_state_controller_test, /* root= */ null);
- mButtonSelectionStateController = new ButtonSelectionStateController(mContext);
- mButtonSelectionStateController.addAllButtonsWithSelectionState(mTestView);
- }
-
- @Test
- public void onTaskChanged_buttonDetectableByComponentName_selectsAssociatedButton() {
- CarNavigationButton testButton = mTestView.findViewById(R.id.detectable_by_component_name);
- mComponentName = new ComponentName(TEST_COMPONENT_NAME_PACKAGE, TEST_COMPONENT_NAME_CLASS);
- List<RootTaskInfo> testStack = createTestStack(mComponentName);
- testButton.setSelected(false);
- mButtonSelectionStateController.taskChanged(testStack, /* validDisplay= */ -1);
-
- assertbuttonSelected(testButton);
- }
-
- @Test
- public void onTaskChanged_buttonDetectableByCategory_selectsAssociatedButton() {
- CarNavigationButton testButton = mTestView.findViewById(R.id.detectable_by_category);
- mComponentName = new ComponentName(TEST_CATEGORY, TEST_CATEGORY_CLASS);
- List<RootTaskInfo> testStack = createTestStack(mComponentName);
- testButton.setSelected(false);
- mButtonSelectionStateController.taskChanged(testStack, /* validDisplay= */ -1);
-
- assertbuttonSelected(testButton);
- }
-
- @Test
- public void onTaskChanged_buttonDetectableByPackage_selectsAssociatedButton() {
- CarNavigationButton testButton = mTestView.findViewById(R.id.detectable_by_package);
- mComponentName = new ComponentName(TEST_PACKAGE, TEST_PACKAGE_CLASS);
- List<RootTaskInfo> testStack = createTestStack(mComponentName);
- testButton.setSelected(false);
- mButtonSelectionStateController.taskChanged(testStack, /* validDisplay= */ -1);
-
- assertbuttonSelected(testButton);
- }
-
- @Test
- public void onTaskChanged_deselectsPreviouslySelectedButton() {
- CarNavigationButton oldButton = mTestView.findViewById(R.id.detectable_by_component_name);
- mComponentName = new ComponentName(TEST_COMPONENT_NAME_PACKAGE, TEST_COMPONENT_NAME_CLASS);
- List<RootTaskInfo> oldStack = createTestStack(mComponentName);
- oldButton.setSelected(false);
- mButtonSelectionStateController.taskChanged(oldStack, /* validDisplay= */ -1);
-
- mComponentName = new ComponentName(TEST_PACKAGE, TEST_PACKAGE_CLASS);
- List<RootTaskInfo> newStack = createTestStack(mComponentName);
- mButtonSelectionStateController.taskChanged(newStack, /* validDisplay= */ -1);
-
- assertButtonUnselected(oldButton);
- }
-
- // Comparing alpha is a valid way to verify button selection state because all test buttons use
- // highlightWhenSelected = true.
- private void assertbuttonSelected(CarNavigationButton button) {
- assertThat(button.getAlpha()).isEqualTo(CarNavigationButton.DEFAULT_SELECTED_ALPHA);
- }
-
- private void assertButtonUnselected(CarNavigationButton button) {
- assertThat(button.getAlpha()).isEqualTo(CarNavigationButton.DEFAULT_UNSELECTED_ALPHA);
- }
-
- private List<RootTaskInfo> createTestStack(ComponentName componentName) {
- RootTaskInfo validStackInfo = new RootTaskInfo();
- validStackInfo.displayId = -1; // No display is assigned to this test view
- validStackInfo.topActivity = componentName;
-
- List<RootTaskInfo> testStack = new ArrayList<>();
- testStack.add(validStackInfo);
-
- return testStack;
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
deleted file mode 100644
index 5b0bb35ad491..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
+++ /dev/null
@@ -1,479 +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.car.navigationbar;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableResources;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.car.hvac.HvacController;
-import com.android.systemui.car.statusbar.UserNameViewController;
-import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class CarNavigationBarControllerTest extends SysuiTestCase {
-
- private static final String TOP_NOTIFICATION_PANEL =
- "com.android.systemui.car.notification.TopNotificationPanelViewMediator";
- private static final String BOTTOM_NOTIFICATION_PANEL =
- "com.android.systemui.car.notification.BottomNotificationPanelViewMediator";
- private CarNavigationBarController mCarNavigationBar;
- private NavigationBarViewFactory mNavigationBarViewFactory;
- private TestableResources mTestableResources;
-
- @Mock
- private ButtonSelectionStateController mButtonSelectionStateController;
- @Mock
- private ButtonRoleHolderController mButtonRoleHolderController;
- @Mock
- private HvacController mHvacController;
- @Mock
- private UserNameViewController mUserNameViewController;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mNavigationBarViewFactory = new NavigationBarViewFactory(mContext);
- mTestableResources = mContext.getOrCreateTestableResources();
-
- // Needed to inflate top navigation bar.
- mDependency.injectMockDependency(DarkIconDispatcher.class);
- mDependency.injectMockDependency(StatusBarIconController.class);
- }
-
- private CarNavigationBarController createNavigationBarController() {
- return new CarNavigationBarController(mContext, mNavigationBarViewFactory,
- mButtonSelectionStateController, () -> mHvacController,
- () -> mUserNameViewController, mButtonRoleHolderController,
- new SystemBarConfigs(mTestableResources.getResources()));
- }
-
- @Test
- public void testConnectToHvac_callsConnect() {
- mCarNavigationBar = createNavigationBarController();
-
- mCarNavigationBar.connectToHvac();
-
- verify(mHvacController).connectToCarService();
- }
-
- @Test
- public void testRemoveAll_callsHvacControllerRemoveAllComponents() {
- mCarNavigationBar = createNavigationBarController();
-
- mCarNavigationBar.removeAll();
-
- verify(mHvacController).removeAllComponents();
- }
-
-
- @Test
- public void testRemoveAll_callsButtonRoleHolderControllerRemoveAll() {
- mCarNavigationBar = createNavigationBarController();
-
- mCarNavigationBar.removeAll();
-
- verify(mButtonRoleHolderController).removeAll();
- }
-
- @Test
- public void testRemoveAll_callsButtonSelectionStateControllerRemoveAll() {
- mCarNavigationBar = createNavigationBarController();
-
- mCarNavigationBar.removeAll();
-
- verify(mButtonSelectionStateController).removeAll();
- }
-
- @Test
- public void testGetTopWindow_topDisabled_returnsNull() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, false);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- // If Top Notification Panel is used but top navigation bar is not enabled, SystemUI is
- // expected to crash.
- mTestableResources.addOverride(R.string.config_notificationPanelViewMediator,
- BOTTOM_NOTIFICATION_PANEL);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getTopWindow();
-
- assertThat(window).isNull();
- }
-
- @Test
- public void testGetTopWindow_topEnabled_returnsWindow() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getTopWindow();
-
- assertThat(window).isNotNull();
- }
-
- @Test
- public void testGetTopWindow_topEnabled_calledTwice_returnsSameWindow() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window1 = mCarNavigationBar.getTopWindow();
- ViewGroup window2 = mCarNavigationBar.getTopWindow();
-
- assertThat(window1).isEqualTo(window2);
- }
-
- @Test
- public void testGetBottomWindow_bottomDisabled_returnsNull() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, false);
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- // If Bottom Notification Panel is used but bottom navigation bar is not enabled,
- // SystemUI is expected to crash.
- mTestableResources.addOverride(R.string.config_notificationPanelViewMediator,
- TOP_NOTIFICATION_PANEL);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getBottomWindow();
-
- assertThat(window).isNull();
- }
-
- @Test
- public void testGetBottomWindow_bottomEnabled_returnsWindow() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getBottomWindow();
-
- assertThat(window).isNotNull();
- }
-
- @Test
- public void testGetBottomWindow_bottomEnabled_calledTwice_returnsSameWindow() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window1 = mCarNavigationBar.getBottomWindow();
- ViewGroup window2 = mCarNavigationBar.getBottomWindow();
-
- assertThat(window1).isEqualTo(window2);
- }
-
- @Test
- public void testGetLeftWindow_leftDisabled_returnsNull() {
- mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, false);
- mCarNavigationBar = createNavigationBarController();
- ViewGroup window = mCarNavigationBar.getLeftWindow();
- assertThat(window).isNull();
- }
-
- @Test
- public void testGetLeftWindow_leftEnabled_returnsWindow() {
- mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getLeftWindow();
-
- assertThat(window).isNotNull();
- }
-
- @Test
- public void testGetLeftWindow_leftEnabled_calledTwice_returnsSameWindow() {
- mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window1 = mCarNavigationBar.getLeftWindow();
- ViewGroup window2 = mCarNavigationBar.getLeftWindow();
-
- assertThat(window1).isEqualTo(window2);
- }
-
- @Test
- public void testGetRightWindow_rightDisabled_returnsNull() {
- mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, false);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getRightWindow();
-
- assertThat(window).isNull();
- }
-
- @Test
- public void testGetRightWindow_rightEnabled_returnsWindow() {
- mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getRightWindow();
-
- assertThat(window).isNotNull();
- }
-
- @Test
- public void testGetRightWindow_rightEnabled_calledTwice_returnsSameWindow() {
- mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window1 = mCarNavigationBar.getRightWindow();
- ViewGroup window2 = mCarNavigationBar.getRightWindow();
-
- assertThat(window1).isEqualTo(window2);
- }
-
- @Test
- public void testSetTopWindowVisibility_setTrue_isVisible() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getTopWindow();
- mCarNavigationBar.setTopWindowVisibility(View.VISIBLE);
-
- assertThat(window.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void testSetTopWindowVisibility_setFalse_isGone() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getTopWindow();
- mCarNavigationBar.setTopWindowVisibility(View.GONE);
-
- assertThat(window.getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
- public void testSetBottomWindowVisibility_setTrue_isVisible() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getBottomWindow();
- mCarNavigationBar.setBottomWindowVisibility(View.VISIBLE);
-
- assertThat(window.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void testSetBottomWindowVisibility_setFalse_isGone() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getBottomWindow();
- mCarNavigationBar.setBottomWindowVisibility(View.GONE);
-
- assertThat(window.getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
- public void testSetLeftWindowVisibility_setTrue_isVisible() {
- mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getLeftWindow();
- mCarNavigationBar.setLeftWindowVisibility(View.VISIBLE);
-
- assertThat(window.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void testSetLeftWindowVisibility_setFalse_isGone() {
- mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getLeftWindow();
- mCarNavigationBar.setLeftWindowVisibility(View.GONE);
-
- assertThat(window.getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
- public void testSetRightWindowVisibility_setTrue_isVisible() {
- mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getRightWindow();
- mCarNavigationBar.setRightWindowVisibility(View.VISIBLE);
-
- assertThat(window.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void testSetRightWindowVisibility_setFalse_isGone() {
- mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- ViewGroup window = mCarNavigationBar.getRightWindow();
- mCarNavigationBar.setRightWindowVisibility(View.GONE);
-
- assertThat(window.getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
- public void testRegisterBottomBarTouchListener_createViewFirst_registrationSuccessful() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
- View.OnTouchListener controller = bottomBar.getStatusBarWindowTouchListener();
- assertThat(controller).isNull();
- mCarNavigationBar.registerBottomBarTouchListener(mock(View.OnTouchListener.class));
- controller = bottomBar.getStatusBarWindowTouchListener();
-
- assertThat(controller).isNotNull();
- }
-
- @Test
- public void testRegisterBottomBarTouchListener_registerFirst_registrationSuccessful() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- mCarNavigationBar.registerBottomBarTouchListener(mock(View.OnTouchListener.class));
- CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
- View.OnTouchListener controller = bottomBar.getStatusBarWindowTouchListener();
-
- assertThat(controller).isNotNull();
- }
-
- @Test
- public void testRegisterNotificationController_createViewFirst_registrationSuccessful() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
- CarNavigationBarController.NotificationsShadeController controller =
- bottomBar.getNotificationsPanelController();
- assertThat(controller).isNull();
- mCarNavigationBar.registerNotificationController(
- mock(CarNavigationBarController.NotificationsShadeController.class));
- controller = bottomBar.getNotificationsPanelController();
-
- assertThat(controller).isNotNull();
- }
-
- @Test
- public void testRegisterNotificationController_registerFirst_registrationSuccessful() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
-
- mCarNavigationBar.registerNotificationController(
- mock(CarNavigationBarController.NotificationsShadeController.class));
- CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
- CarNavigationBarController.NotificationsShadeController controller =
- bottomBar.getNotificationsPanelController();
-
- assertThat(controller).isNotNull();
- }
-
- @Test
- public void testShowAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsVisible() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
- CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
- View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons);
-
- mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true);
-
- assertThat(bottomKeyguardButtons.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void testShowAllKeyguardButtons_bottomEnabled_bottomNavButtonsGone() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
- CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
- View bottomButtons = bottomBar.findViewById(R.id.nav_buttons);
-
- mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true);
-
- assertThat(bottomButtons.getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
- public void testHideAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsGone() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
- CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
- View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons);
-
- mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true);
- assertThat(bottomKeyguardButtons.getVisibility()).isEqualTo(View.VISIBLE);
- mCarNavigationBar.hideAllKeyguardButtons(/* isSetUp= */ true);
-
- assertThat(bottomKeyguardButtons.getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
- public void testHideAllKeyguardButtons_bottomEnabled_bottomNavButtonsVisible() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
- CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
- View bottomButtons = bottomBar.findViewById(R.id.nav_buttons);
-
- mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true);
- assertThat(bottomButtons.getVisibility()).isEqualTo(View.GONE);
- mCarNavigationBar.hideAllKeyguardButtons(/* isSetUp= */ true);
-
- assertThat(bottomButtons.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_hasUnseen_setCorrectly() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
- CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
- CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications);
-
- boolean hasUnseen = true;
- mCarNavigationBar.toggleAllNotificationsUnseenIndicator(/* isSetUp= */ true,
- hasUnseen);
-
- assertThat(notifications.getUnseen()).isTrue();
- }
-
- @Test
- public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_noUnseen_setCorrectly() {
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- mCarNavigationBar = createNavigationBarController();
- CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true);
- CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications);
-
- boolean hasUnseen = false;
- mCarNavigationBar.toggleAllNotificationsUnseenIndicator(/* isSetUp= */ true,
- hasUnseen);
-
- assertThat(notifications.getUnseen()).isFalse();
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
deleted file mode 100644
index 2b5af71dccaa..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
+++ /dev/null
@@ -1,373 +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.car.navigationbar;
-
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableResources;
-import android.util.ArrayMap;
-import android.view.Display;
-import android.view.WindowManager;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.RegisterStatusBarResult;
-import com.android.internal.view.AppearanceRegion;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.AutoHideController;
-import com.android.systemui.statusbar.phone.LightBarController;
-import com.android.systemui.statusbar.phone.LightBarTransitionsController;
-import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-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;
-
-@CarSystemUiTest
-@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 LightBarController mLightBarController;
- @Mock
- private SysuiDarkIconDispatcher mStatusBarIconController;
- @Mock
- private LightBarTransitionsController mLightBarTransitionsController;
- @Mock
- private WindowManager mWindowManager;
- @Mock
- private CarDeviceProvisionedController mDeviceProvisionedController;
- @Mock
- private AutoHideController mAutoHideController;
- @Mock
- private ButtonSelectionStateListener mButtonSelectionStateListener;
- @Mock
- private ButtonRoleHolderController mButtonRoleHolderController;
- @Mock
- private IStatusBarService mBarService;
- @Mock
- private KeyguardStateController mKeyguardStateController;
- @Mock
- private ButtonSelectionStateController mButtonSelectionStateController;
- @Mock
- private PhoneStatusBarPolicy mIconPolicy;
- @Mock
- private StatusBarIconController mIconController;
-
- private RegisterStatusBarResult mBarResult;
- private AppearanceRegion[] mAppearanceRegions;
- private FakeExecutor mUiBgExecutor;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mTestableResources = mContext.getOrCreateTestableResources();
- mHandler = Handler.getMain();
- mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
- when(mStatusBarIconController.getTransitionsController()).thenReturn(
- mLightBarTransitionsController);
- mAppearanceRegions = new AppearanceRegion[] {
- new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect())
- };
- mBarResult = new RegisterStatusBarResult(
- /* icons= */ new ArrayMap<>(),
- /* disabledFlags1= */ 0,
- /* appearance= */ 0,
- mAppearanceRegions,
- /* imeWindowVis= */ 0,
- /* imeBackDisposition= */ 0,
- /* showImeSwitcher= */ false,
- /* disabledFlags2= */ 0,
- /* imeToken= */ null,
- /* navbarColorMangedByIme= */ false,
- /* appFullscreen= */ false,
- /* appImmersive= */ false,
- /* transientBarTypes= */ new int[]{});
- try {
- when(mBarService.registerStatusBar(any())).thenReturn(mBarResult);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- mCarNavigationBar = new CarNavigationBar(mContext, mTestableResources.getResources(),
- mCarNavigationBarController, mLightBarController, mStatusBarIconController,
- mWindowManager, mDeviceProvisionedController, new CommandQueue(mContext),
- mAutoHideController, mButtonSelectionStateListener, mHandler, mUiBgExecutor,
- mBarService, () -> mKeyguardStateController, () -> mIconPolicy,
- () -> mIconController, new SystemBarConfigs(mTestableResources.getResources()));
- }
-
- @Test
- public void restartNavbars_refreshesTaskChanged() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- 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();
- }
-
- @Test
- public void restartNavBars_newUserNotSetupWithKeyguardShowing_showsKeyguardButtons() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- ArgumentCaptor<CarDeviceProvisionedController.DeviceProvisionedListener>
- deviceProvisionedCallbackCaptor = ArgumentCaptor.forClass(
- CarDeviceProvisionedController.DeviceProvisionedListener.class);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- mCarNavigationBar.start();
- when(mKeyguardStateController.isShowing()).thenReturn(true);
- // 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(mCarNavigationBarController).showAllKeyguardButtons(false);
- }
-
- @Test
- public void restartNavbars_newUserIsSetupWithKeyguardHidden_hidesKeyguardButtons() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- ArgumentCaptor<CarDeviceProvisionedController.DeviceProvisionedListener>
- deviceProvisionedCallbackCaptor = ArgumentCaptor.forClass(
- CarDeviceProvisionedController.DeviceProvisionedListener.class);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- mCarNavigationBar.start();
- when(mKeyguardStateController.isShowing()).thenReturn(true);
- // switching the currentUserSetup value to force restart the navbars.
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false);
- verify(mDeviceProvisionedController).addCallback(deviceProvisionedCallbackCaptor.capture());
- deviceProvisionedCallbackCaptor.getValue().onUserSwitched();
- waitForIdleSync(mHandler);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- when(mKeyguardStateController.isShowing()).thenReturn(false);
-
- deviceProvisionedCallbackCaptor.getValue().onUserSetupChanged();
- waitForIdleSync(mHandler);
-
- verify(mCarNavigationBarController).hideAllKeyguardButtons(true);
- }
-
- @Test
- public void restartNavBars_lightAppearance_darkensAllIcons() {
- mAppearanceRegions[0] = new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect());
-
- mCarNavigationBar.start();
-
- verify(mLightBarTransitionsController).setIconsDark(
- /* dark= */ true, /* animate= */ false);
- }
-
- @Test
- public void restartNavBars_opaqueAppearance_lightensAllIcons() {
- mAppearanceRegions[0] = new AppearanceRegion(APPEARANCE_OPAQUE_STATUS_BARS, new Rect());
-
- mCarNavigationBar.start();
-
- verify(mLightBarTransitionsController).setIconsDark(
- /* dark= */ false, /* animate= */ false);
- }
-
- @Test
- public void showTransient_wrongDisplayId_transientModeNotUpdated() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- mCarNavigationBar.start();
-
- int randomDisplay = Display.DEFAULT_DISPLAY + 10;
- int[] insetTypes = new int[]{};
- mCarNavigationBar.showTransient(randomDisplay, insetTypes);
-
- assertThat(mCarNavigationBar.isStatusBarTransientShown()).isFalse();
- }
-
- @Test
- public void showTransient_correctDisplayId_noStatusBarInset_transientModeNotUpdated() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- mCarNavigationBar.start();
-
- int[] insetTypes = new int[]{};
- mCarNavigationBar.showTransient(Display.DEFAULT_DISPLAY, insetTypes);
-
- assertThat(mCarNavigationBar.isStatusBarTransientShown()).isFalse();
- }
-
- @Test
- public void showTransient_correctDisplayId_statusBarInset_transientModeUpdated() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- mCarNavigationBar.start();
-
- int[] insetTypes = new int[]{ITYPE_STATUS_BAR};
- mCarNavigationBar.showTransient(Display.DEFAULT_DISPLAY, insetTypes);
-
- assertThat(mCarNavigationBar.isStatusBarTransientShown()).isTrue();
- }
-
- @Test
- public void showTransient_correctDisplayId_noNavBarInset_transientModeNotUpdated() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- mCarNavigationBar.start();
-
- int[] insetTypes = new int[]{};
- mCarNavigationBar.showTransient(Display.DEFAULT_DISPLAY, insetTypes);
-
- assertThat(mCarNavigationBar.isNavBarTransientShown()).isFalse();
- }
-
- @Test
- public void showTransient_correctDisplayId_navBarInset_transientModeUpdated() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- mCarNavigationBar.start();
-
- int[] insetTypes = new int[]{ITYPE_NAVIGATION_BAR};
- mCarNavigationBar.showTransient(Display.DEFAULT_DISPLAY, insetTypes);
-
- assertThat(mCarNavigationBar.isNavBarTransientShown()).isTrue();
- }
-
- @Test
- public void abortTransient_wrongDisplayId_transientModeNotCleared() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- mCarNavigationBar.start();
- mCarNavigationBar.showTransient(Display.DEFAULT_DISPLAY,
- new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
- assertThat(mCarNavigationBar.isStatusBarTransientShown()).isTrue();
- assertThat(mCarNavigationBar.isNavBarTransientShown()).isTrue();
-
- int[] insetTypes = new int[]{};
- int randomDisplay = Display.DEFAULT_DISPLAY + 10;
- mCarNavigationBar.abortTransient(randomDisplay, insetTypes);
-
- // The transient booleans were not cleared.
- assertThat(mCarNavigationBar.isStatusBarTransientShown()).isTrue();
- assertThat(mCarNavigationBar.isNavBarTransientShown()).isTrue();
- }
-
- @Test
- public void abortTransient_correctDisplayId_noInsets_transientModeNotCleared() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- mCarNavigationBar.start();
- mCarNavigationBar.showTransient(Display.DEFAULT_DISPLAY,
- new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
- assertThat(mCarNavigationBar.isStatusBarTransientShown()).isTrue();
- assertThat(mCarNavigationBar.isNavBarTransientShown()).isTrue();
-
- int[] insetTypes = new int[]{};
- mCarNavigationBar.abortTransient(Display.DEFAULT_DISPLAY, insetTypes);
-
- // The transient booleans were not cleared.
- assertThat(mCarNavigationBar.isStatusBarTransientShown()).isTrue();
- assertThat(mCarNavigationBar.isNavBarTransientShown()).isTrue();
- }
-
- @Test
- public void abortTransient_correctDisplayId_statusBarInset_transientModeCleared() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- mCarNavigationBar.start();
- mCarNavigationBar.showTransient(Display.DEFAULT_DISPLAY,
- new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
- assertThat(mCarNavigationBar.isStatusBarTransientShown()).isTrue();
- assertThat(mCarNavigationBar.isNavBarTransientShown()).isTrue();
-
- int[] insetTypes = new int[]{ITYPE_STATUS_BAR};
- mCarNavigationBar.abortTransient(Display.DEFAULT_DISPLAY, insetTypes);
-
- // The transient booleans were cleared.
- assertThat(mCarNavigationBar.isStatusBarTransientShown()).isFalse();
- assertThat(mCarNavigationBar.isNavBarTransientShown()).isFalse();
- }
-
- @Test
- public void abortTransient_correctDisplayId_navBarInset_transientModeCleared() {
- mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
- mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
- when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
- mCarNavigationBar.start();
- mCarNavigationBar.showTransient(Display.DEFAULT_DISPLAY,
- new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR});
- assertThat(mCarNavigationBar.isStatusBarTransientShown()).isTrue();
- assertThat(mCarNavigationBar.isNavBarTransientShown()).isTrue();
-
- int[] insetTypes = new int[]{ITYPE_NAVIGATION_BAR};
- mCarNavigationBar.abortTransient(Display.DEFAULT_DISPLAY, insetTypes);
-
- // The transient booleans were cleared.
- assertThat(mCarNavigationBar.isStatusBarTransientShown()).isFalse();
- assertThat(mCarNavigationBar.isNavBarTransientShown()).isFalse();
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java
deleted file mode 100644
index 47fd8201d197..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java
+++ /dev/null
@@ -1,102 +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.car.navigationbar;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarSystemUiTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class CarNavigationBarViewTest extends SysuiTestCase {
-
- private CarNavigationBarView mNavBarView;
-
- @Mock
- private CarNavigationBarController.NotificationsShadeController mNotificationsShadeController;
-
- @Mock
- private View.OnTouchListener mNavBarTouchListener;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- @After
- public void tearDown() {
- getContext().getOrCreateTestableResources().addOverride(
- R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen, false);
- }
-
- @Test
- public void dispatchTouch_shadeOpen_flagOff_doesNotConsumeTouch() {
- getContext().getOrCreateTestableResources().addOverride(
- R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen, false);
- when(mNotificationsShadeController.isNotificationPanelOpen()).thenReturn(true);
- mNavBarView = (CarNavigationBarView) LayoutInflater.from(getContext()).inflate(
- R.layout.car_navigation_bar_view_test, /* root= */ null);
- mNavBarView.setNotificationsPanelController(mNotificationsShadeController);
- mNavBarView.setStatusBarWindowTouchListener(mNavBarTouchListener);
-
- boolean consume = mNavBarView.onInterceptTouchEvent(
- MotionEvent.obtain(/* downTime= */ 200, /* eventTime= */ 300,
- MotionEvent.ACTION_MOVE, mNavBarView.getX(),
- mNavBarView.getY(), /* metaState= */ 0));
-
- assertThat(consume).isFalse();
- }
-
- @Test
- public void dispatchTouch_shadeOpen_flagOn_consumesTouch() {
- getContext().getOrCreateTestableResources().addOverride(
- R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen, true);
- when(mNotificationsShadeController.isNotificationPanelOpen()).thenReturn(true);
- mNavBarView = (CarNavigationBarView) LayoutInflater.from(getContext()).inflate(
- R.layout.car_navigation_bar_view_test, /* root= */ null);
- mNavBarView.setNotificationsPanelController(mNotificationsShadeController);
- mNavBarView.setStatusBarWindowTouchListener(mNavBarTouchListener);
-
- boolean consume = mNavBarView.onInterceptTouchEvent(
- MotionEvent.obtain(/* downTime= */ 200, /* eventTime= */ 300,
- MotionEvent.ACTION_MOVE, mNavBarView.getX(),
- mNavBarView.getY(), /* metaState= */ 0));
-
- assertThat(consume).isTrue();
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
deleted file mode 100644
index 173f5487c728..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
+++ /dev/null
@@ -1,291 +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.car.navigationbar;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.statusbar.AlphaOptimizedImageView;
-import com.android.systemui.tests.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class CarNavigationButtonTest extends SysuiTestCase {
-
- private static final String DEFAULT_BUTTON_ACTIVITY_NAME =
- "com.android.car.carlauncher/.CarLauncher";
- private static final String APP_GRID_BUTTON_ACTIVITY_NAME =
- "com.android.car.carlauncher/.AppGridActivity";
- private static final String BROADCAST_ACTION_NAME =
- "android.car.intent.action.TOGGLE_HVAC_CONTROLS";
-
- private ActivityManager mActivityManager;
- // LinearLayout with CarNavigationButtons with different configurations.
- private LinearLayout mTestView;
- // Does not have any selection state which is the default configuration.
- private CarNavigationButton mDefaultButton;
-
- @Before
- public void setUp() {
- mContext = spy(mContext);
- mTestView = (LinearLayout) LayoutInflater.from(mContext).inflate(
- R.layout.car_navigation_button_test, /* root= */ null);
- mDefaultButton = mTestView.findViewById(R.id.default_no_selection_state);
- mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- }
-
- @Test
- public void onCreate_iconIsVisible() {
- AlphaOptimizedImageView icon = mDefaultButton.findViewById(
- R.id.car_nav_button_icon_image);
-
- assertThat(icon.getDrawable()).isNotNull();
- }
-
- @Test
- public void onSelected_selectedIconDefined_togglesIcon() {
- mDefaultButton.setSelected(true);
- Drawable selectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
- R.id.car_nav_button_icon_image)).getDrawable();
-
-
- mDefaultButton.setSelected(false);
- Drawable unselectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
- R.id.car_nav_button_icon_image)).getDrawable();
-
- assertThat(selectedIconDrawable).isNotEqualTo(unselectedIconDrawable);
- }
-
- @Test
- public void onSelected_selectedIconUndefined_displaysSameIcon() {
- CarNavigationButton selectedIconUndefinedButton = mTestView.findViewById(
- R.id.selected_icon_undefined);
-
- selectedIconUndefinedButton.setSelected(true);
- Drawable selectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
- R.id.car_nav_button_icon_image)).getDrawable();
-
-
- selectedIconUndefinedButton.setSelected(false);
- Drawable unselectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
- R.id.car_nav_button_icon_image)).getDrawable();
-
- assertThat(selectedIconDrawable).isEqualTo(unselectedIconDrawable);
- }
-
- @Test
- public void onUnselected_doesNotHighlightWhenSelected_applySelectedAlpha() {
- mDefaultButton.setSelected(false);
-
- assertThat(mDefaultButton.getAlpha()).isEqualTo(
- CarNavigationButton.DEFAULT_SELECTED_ALPHA);
- }
-
- @Test
- public void onSelected_doesNotHighlightWhenSelected_applySelectedAlpha() {
- mDefaultButton.setSelected(true);
-
- assertThat(mDefaultButton.getAlpha()).isEqualTo(
- CarNavigationButton.DEFAULT_SELECTED_ALPHA);
- }
-
- @Test
- public void onUnselected_highlightWhenSelected_applyDefaultUnselectedAlpha() {
- CarNavigationButton highlightWhenSelectedButton = mTestView.findViewById(
- R.id.highlightable_no_more_button);
- highlightWhenSelectedButton.setSelected(false);
-
- assertThat(highlightWhenSelectedButton.getAlpha()).isEqualTo(
- CarNavigationButton.DEFAULT_UNSELECTED_ALPHA);
- }
-
- @Test
- public void onSelected_highlightWhenSelected_applyDefaultSelectedAlpha() {
- CarNavigationButton highlightWhenSelectedButton = mTestView.findViewById(
- R.id.highlightable_no_more_button);
- highlightWhenSelectedButton.setSelected(true);
-
- assertThat(highlightWhenSelectedButton.getAlpha()).isEqualTo(
- CarNavigationButton.DEFAULT_SELECTED_ALPHA);
- }
-
- @Test
- public void onSelected_doesNotShowMoreWhenSelected_doesNotShowMoreIcon() {
- mDefaultButton.setSelected(true);
- AlphaOptimizedImageView moreIcon = mDefaultButton.findViewById(
- R.id.car_nav_button_more_icon);
-
- assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
- public void onSelected_showMoreWhenSelected_showsMoreIcon() {
- CarNavigationButton showMoreWhenSelected = mTestView.findViewById(
- R.id.not_highlightable_more_button);
- showMoreWhenSelected.setSelected(true);
- AlphaOptimizedImageView moreIcon = showMoreWhenSelected.findViewById(
- R.id.car_nav_button_more_icon);
-
- assertThat(moreIcon.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void onUnselected_showMoreWhenSelected_doesNotShowMoreIcon() {
- CarNavigationButton showMoreWhenSelected = mTestView.findViewById(
- R.id.highlightable_no_more_button);
- showMoreWhenSelected.setSelected(true);
- showMoreWhenSelected.setSelected(false);
- AlphaOptimizedImageView moreIcon = showMoreWhenSelected.findViewById(
- R.id.car_nav_button_more_icon);
-
- assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
- public void onUnselected_withAppIcon_showsAppIcon() {
- CarNavigationButton roleBasedButton = mTestView.findViewById(R.id.role_based_button);
- Drawable appIcon = getContext().getDrawable(R.drawable.ic_android);
-
- roleBasedButton.setSelected(false);
- roleBasedButton.setAppIcon(appIcon);
-
- Drawable currentDrawable = ((AlphaOptimizedImageView) roleBasedButton.findViewById(
- R.id.car_nav_button_icon_image)).getDrawable();
-
- assertThat(currentDrawable).isEqualTo(appIcon);
- }
-
- @Test
- public void onUnselected_withAppIcon_applyUnselectedAlpha() {
- CarNavigationButton roleBasedButton = mTestView.findViewById(R.id.role_based_button);
-
- roleBasedButton.setSelected(false);
- roleBasedButton.setAppIcon(getContext().getDrawable(R.drawable.ic_android));
-
- assertThat(roleBasedButton.getAlpha()).isEqualTo(
- CarNavigationButton.DEFAULT_UNSELECTED_ALPHA);
- }
-
- @Test
- public void onSelected_withAppIcon_showsAppIconWithSelectedAlpha() {
- CarNavigationButton roleBasedButton = mTestView.findViewById(R.id.role_based_button);
- Drawable appIcon = getContext().getDrawable(R.drawable.ic_android);
-
- roleBasedButton.setSelected(true);
- roleBasedButton.setAppIcon(appIcon);
-
- Drawable currentDrawable = ((AlphaOptimizedImageView) roleBasedButton.findViewById(
- R.id.car_nav_button_icon_image)).getDrawable();
-
- assertThat(currentDrawable).isEqualTo(appIcon);
- }
-
- @Test
- public void onSelected_withAppIcon_applySelectedAlpha() {
- CarNavigationButton roleBasedButton = mTestView.findViewById(R.id.role_based_button);
-
- roleBasedButton.setSelected(true);
- roleBasedButton.setAppIcon(getContext().getDrawable(R.drawable.ic_android));
-
- assertThat(roleBasedButton.getAlpha()).isEqualTo(
- CarNavigationButton.DEFAULT_SELECTED_ALPHA);
- }
-
- @Test
- public void onClick_launchesIntentActivity() {
- mDefaultButton.performClick();
-
- assertThat(getCurrentActivityName()).isEqualTo(DEFAULT_BUTTON_ACTIVITY_NAME);
-
- CarNavigationButton appGridButton = mTestView.findViewById(R.id.app_grid_activity);
- appGridButton.performClick();
-
- assertThat(getCurrentActivityName()).isEqualTo(APP_GRID_BUTTON_ACTIVITY_NAME);
- }
-
- @Test
- public void onLongClick_longIntentDefined_launchesLongIntentActivity() {
- mDefaultButton.performClick();
-
- assertThat(getCurrentActivityName()).isEqualTo(DEFAULT_BUTTON_ACTIVITY_NAME);
-
- CarNavigationButton appGridButton = mTestView.findViewById(
- R.id.long_click_app_grid_activity);
- appGridButton.performLongClick();
-
- assertThat(getCurrentActivityName()).isEqualTo(APP_GRID_BUTTON_ACTIVITY_NAME);
- }
-
- @Test
- public void onClick_useBroadcast_broadcastsIntent() {
- CarNavigationButton appGridButton = mTestView.findViewById(R.id.broadcast);
- appGridButton.performClick();
-
- verify(mContext).sendBroadcastAsUser(argThat(new ArgumentMatcher<Intent>() {
- @Override
- public boolean matches(Intent argument) {
- return argument.getAction().equals(BROADCAST_ACTION_NAME);
- }
- }), any());
- }
-
- @Test
- public void onSetUnseen_hasUnseen_showsUnseenIndicator() {
- mDefaultButton.setUnseen(true);
- ImageView hasUnseenIndicator = mDefaultButton.findViewById(R.id.car_nav_button_unseen_icon);
-
- assertThat(hasUnseenIndicator.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void onSetUnseen_doesNotHaveUnseen_hidesUnseenIndicator() {
- mDefaultButton.setUnseen(false);
- ImageView hasUnseenIndicator = mDefaultButton.findViewById(R.id.car_nav_button_unseen_icon);
-
- assertThat(hasUnseenIndicator.getVisibility()).isEqualTo(View.GONE);
- }
-
- private String getCurrentActivityName() {
- return mActivityManager.getRunningTasks(1).get(0).topActivity.flattenToShortString();
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
deleted file mode 100644
index 0c62f8b4a22b..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
+++ /dev/null
@@ -1,290 +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.car.navigationbar;
-
-import static org.junit.Assert.assertEquals;
-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.when;
-
-import android.content.res.Resources;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.util.ArrayMap;
-import android.view.WindowManager;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.car.notification.NotificationPanelViewController;
-import com.android.systemui.car.notification.NotificationPanelViewMediator;
-import com.android.systemui.car.notification.PowerManagerHelper;
-import com.android.systemui.car.notification.TopNotificationPanelViewMediator;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class SystemBarConfigsTest extends SysuiTestCase {
- private static final int SYSTEM_BAR_GIRTH = 100;
-
- private SystemBarConfigs mSystemBarConfigs;
- @Mock
- private Resources mResources;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- setDefaultValidConfig();
- }
-
- @Test
- public void onInit_allSystemBarsEnabled_eachHasUniqueBarTypes_doesNotThrowException() {
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- }
-
- @Test(expected = RuntimeException.class)
- public void onInit_allSystemBarsEnabled_twoBarsHaveDuplicateType_throwsRuntimeException() {
- when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0);
- when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(0);
-
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- }
-
- @Test
- public void onInit_allSystemBarsEnabled_systemBarSidesSortedByZOrder() {
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- List<Integer> actualOrder = mSystemBarConfigs.getSystemBarSidesByZOrder();
- List<Integer> expectedOrder = new ArrayList<>();
- expectedOrder.add(SystemBarConfigs.LEFT);
- expectedOrder.add(SystemBarConfigs.RIGHT);
- expectedOrder.add(SystemBarConfigs.TOP);
- expectedOrder.add(SystemBarConfigs.BOTTOM);
-
- assertTrue(actualOrder.equals(expectedOrder));
- }
-
- @Test(expected = RuntimeException.class)
- public void onInit_intersectingBarsHaveSameZOrder_throwsRuntimeException() {
- when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(33);
- when(mResources.getInteger(R.integer.config_leftSystemBarZOrder)).thenReturn(33);
-
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- }
-
- @Test(expected = RuntimeException.class)
- public void onInit_hideBottomSystemBarForKeyboardValueDoNotSync_throwsRuntimeException() {
- when(mResources.getBoolean(R.bool.config_hideBottomSystemBarForKeyboard)).thenReturn(false);
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard)).thenReturn(
- true);
-
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- }
-
- @Test
- public void onInit_topNotifPanelViewMediatorUsed_topBarEnabled_doesNotThrowException() {
- when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(true);
- when(mResources.getString(R.string.config_notificationPanelViewMediator)).thenReturn(
- TestTopNotificationPanelViewMediator.class.getName());
-
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- }
-
- @Test(expected = RuntimeException.class)
- public void onInit_topNotifPanelViewMediatorUsed_topBarNotEnabled_throwsRuntimeException() {
- when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(false);
- when(mResources.getString(R.string.config_notificationPanelViewMediator)).thenReturn(
- TestTopNotificationPanelViewMediator.class.getName());
-
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- }
-
- @Test
- public void onInit_notificationPanelViewMediatorUsed_topBarNotEnabled_doesNotThrowException() {
- when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(false);
- when(mResources.getString(R.string.config_notificationPanelViewMediator)).thenReturn(
- NotificationPanelViewMediator.class.getName());
-
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- }
-
- @Test
- public void getTopSystemBarLayoutParams_topBarEnabled_returnsTopSystemBarLayoutParams() {
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
- SystemBarConfigs.TOP);
-
- assertNotNull(lp);
- }
-
- @Test
- public void getTopSystemBarLayoutParams_topBarNotEnabled_returnsNull() {
- when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(false);
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
- SystemBarConfigs.TOP);
-
- assertNull(lp);
- }
-
- @Test
- public void getTopSystemBarHideForKeyboard_hideBarForKeyboard_returnsTrue() {
- when(mResources.getBoolean(R.bool.config_hideTopSystemBarForKeyboard)).thenReturn(true);
- mSystemBarConfigs = new SystemBarConfigs(mResources);
-
- boolean hideKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(SystemBarConfigs.TOP);
-
- assertTrue(hideKeyboard);
- }
-
- @Test
- public void getTopSystemBarHideForKeyboard_topBarNotEnabled_returnsFalse() {
- when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(false);
- mSystemBarConfigs = new SystemBarConfigs(mResources);
-
- boolean hideKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(SystemBarConfigs.TOP);
-
- assertFalse(hideKeyboard);
- }
-
- @Test
- public void topSystemBarHasHigherZOrderThanHuns_topSystemBarIsNavigationBarPanelType() {
- when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(
- SystemBarConfigs.getHunZOrder() + 1);
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
- SystemBarConfigs.TOP);
-
- assertEquals(lp.type, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL);
- }
-
- @Test
- public void topSystemBarHasLowerZOrderThanHuns_topSystemBarIsStatusBarAdditionalType() {
- when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(
- SystemBarConfigs.getHunZOrder() - 1);
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
- SystemBarConfigs.TOP);
-
- assertEquals(lp.type, WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL);
- }
-
- @Test
- public void updateInsetPaddings_overlappingBarWithHigherZOrderDisappeared_removesInset() {
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- CarNavigationBarView leftBar = new CarNavigationBarView(mContext, /* attrs= */ null);
- Map<Integer, Boolean> visibilities = new ArrayMap<>();
- visibilities.put(SystemBarConfigs.TOP, false);
- visibilities.put(SystemBarConfigs.BOTTOM, true);
- visibilities.put(SystemBarConfigs.LEFT, true);
- visibilities.put(SystemBarConfigs.RIGHT, true);
-
- mSystemBarConfigs.updateInsetPaddings(SystemBarConfigs.LEFT, visibilities);
- mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, leftBar);
-
- assertEquals(0, leftBar.getPaddingTop());
- }
-
- @Test
- public void updateInsetPaddings_overlappingBarWithHigherZOrderReappeared_addsInset() {
- mSystemBarConfigs = new SystemBarConfigs(mResources);
- CarNavigationBarView leftBar = new CarNavigationBarView(mContext, /* attrs= */ null);
- Map<Integer, Boolean> visibilities = new ArrayMap<>();
- visibilities.put(SystemBarConfigs.TOP, false);
- visibilities.put(SystemBarConfigs.BOTTOM, true);
- visibilities.put(SystemBarConfigs.LEFT, true);
- visibilities.put(SystemBarConfigs.RIGHT, true);
-
- mSystemBarConfigs.updateInsetPaddings(SystemBarConfigs.LEFT, visibilities);
- mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, leftBar);
- visibilities.put(SystemBarConfigs.TOP, true);
- mSystemBarConfigs.updateInsetPaddings(SystemBarConfigs.LEFT, visibilities);
- mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, leftBar);
-
- assertEquals(SYSTEM_BAR_GIRTH, leftBar.getPaddingTop());
- }
-
- // Set valid config where all system bars are enabled.
- private void setDefaultValidConfig() {
- when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(true);
- when(mResources.getBoolean(R.bool.config_enableBottomNavigationBar)).thenReturn(true);
- when(mResources.getBoolean(R.bool.config_enableLeftNavigationBar)).thenReturn(true);
- when(mResources.getBoolean(R.bool.config_enableRightNavigationBar)).thenReturn(true);
-
- when(mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height)).thenReturn(SYSTEM_BAR_GIRTH);
- when(mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_height)).thenReturn(SYSTEM_BAR_GIRTH);
- when(mResources.getDimensionPixelSize(R.dimen.car_left_navigation_bar_width)).thenReturn(
- SYSTEM_BAR_GIRTH);
- when(mResources.getDimensionPixelSize(R.dimen.car_right_navigation_bar_width)).thenReturn(
- SYSTEM_BAR_GIRTH);
-
- when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0);
- when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(1);
- when(mResources.getInteger(R.integer.config_leftSystemBarType)).thenReturn(2);
- when(mResources.getInteger(R.integer.config_rightSystemBarType)).thenReturn(3);
-
- when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(5);
- when(mResources.getInteger(R.integer.config_bottomSystemBarZOrder)).thenReturn(10);
- when(mResources.getInteger(R.integer.config_leftSystemBarZOrder)).thenReturn(2);
- when(mResources.getInteger(R.integer.config_rightSystemBarZOrder)).thenReturn(3);
-
- when(mResources.getBoolean(R.bool.config_hideTopSystemBarForKeyboard)).thenReturn(false);
- when(mResources.getBoolean(
- com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard)).thenReturn(
- false);
- when(mResources.getBoolean(R.bool.config_hideLeftSystemBarForKeyboard)).thenReturn(
- false);
- when(mResources.getBoolean(R.bool.config_hideRightSystemBarForKeyboard)).thenReturn(
- false);
- }
-
- // Intentionally using a subclass of TopNotificationPanelViewMediator for testing purposes to
- // ensure that OEM's will be able to implement and use their own NotificationPanelViewMediator.
- private class TestTopNotificationPanelViewMediator extends
- TopNotificationPanelViewMediator {
- TestTopNotificationPanelViewMediator(
- CarNavigationBarController carNavigationBarController,
- NotificationPanelViewController notificationPanelViewController,
- PowerManagerHelper powerManagerHelper,
- BroadcastDispatcher broadcastDispatcher,
- CarDeviceProvisionedController carDeviceProvisionedController,
- ConfigurationController configurationController) {
- super(carNavigationBarController, notificationPanelViewController, powerManagerHelper,
- broadcastDispatcher, carDeviceProvisionedController, configurationController);
- }
- }
-}
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
deleted file mode 100644
index 384888ab42c3..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
+++ /dev/null
@@ -1,121 +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.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.SysuiTestCase;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.car.window.OverlayViewGlobalStateController;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class CarHeadsUpNotificationSystemContainerTest extends SysuiTestCase {
- private CarHeadsUpNotificationSystemContainer mCarHeadsUpNotificationSystemContainer;
- @Mock
- private CarDeviceProvisionedController mCarDeviceProvisionedController;
- @Mock
- private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
- @Mock
- private WindowManager mWindowManager;
-
- @Mock
- private View mNotificationView;
- @Mock
- private View mNotificationView2;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(/* testClass= */this);
-
- when(mOverlayViewGlobalStateController.shouldShowHUN()).thenReturn(true);
- when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true);
-
- TestableResources testableResources = mContext.getOrCreateTestableResources();
-
- mCarHeadsUpNotificationSystemContainer = new CarHeadsUpNotificationSystemContainer(mContext,
- testableResources.getResources(), mCarDeviceProvisionedController, mWindowManager,
- mOverlayViewGlobalStateController);
- }
-
- @Test
- public void testDisplayNotification_firstNotification_isVisible() {
- mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
- assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
- }
-
- @Test
- public void testRemoveNotification_lastNotification_isInvisible() {
- mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
- mCarHeadsUpNotificationSystemContainer.removeNotification(mNotificationView);
- assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse();
- }
-
- @Test
- public void testRemoveNotification_nonLastNotification_isVisible() {
- mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
- mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView2);
- mCarHeadsUpNotificationSystemContainer.removeNotification(mNotificationView);
- assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
- }
-
- @Test
- public void testDisplayNotification_userFullySetupTrue_isInvisible() {
- mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
- assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
-
- }
-
- @Test
- public void testDisplayNotification_userFullySetupFalse_isInvisible() {
- when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(false);
- mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
- assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse();
- }
-
- @Test
- public void testDisplayNotification_overlayWindowStateShouldShowHUNFalse_isInvisible() {
- when(mOverlayViewGlobalStateController.shouldShowHUN()).thenReturn(false);
- mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
- assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse();
- }
-
- @Test
- public void testDisplayNotification_overlayWindowStateShouldShowHUNTrue_isVisible() {
- mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView);
- assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue();
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java
deleted file mode 100644
index d51aeb18135d..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java
+++ /dev/null
@@ -1,141 +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.car.notification;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Notification;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.car.notification.AlertEntry;
-import com.android.car.notification.NotificationDataManager;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-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 java.util.Collections;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class NotificationVisibilityLoggerTest extends SysuiTestCase {
-
- private static final String PKG = "package_1";
- private static final String OP_PKG = "OpPackage";
- private static final int ID = 1;
- private static final String TAG = "Tag";
- private static final int UID = 2;
- private static final int INITIAL_PID = 3;
- private static final String CHANNEL_ID = "CHANNEL_ID";
- private static final String CONTENT_TITLE = "CONTENT_TITLE";
- private static final String OVERRIDE_GROUP_KEY = "OVERRIDE_GROUP_KEY";
- private static final long POST_TIME = 12345L;
- private static final UserHandle USER_HANDLE = new UserHandle(12);
-
- @Mock
- private IStatusBarService mBarService;
- @Mock
- private NotificationDataManager mNotificationDataManager;
-
- private NotificationVisibilityLogger mNotificationVisibilityLogger;
- private FakeExecutor mUiBgExecutor;
- private AlertEntry mMessageNotification;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(/* testClass= */this);
-
- mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
- Notification.Builder mNotificationBuilder1 = new Notification.Builder(mContext, CHANNEL_ID)
- .setContentTitle(CONTENT_TITLE);
- mMessageNotification = new AlertEntry(new StatusBarNotification(PKG, OP_PKG,
- ID, TAG, UID, INITIAL_PID, mNotificationBuilder1.build(), USER_HANDLE,
- OVERRIDE_GROUP_KEY, POST_TIME));
-
- when(mNotificationDataManager.getVisibleNotifications()).thenReturn(
- Collections.singletonList(mMessageNotification));
-
- mNotificationVisibilityLogger = new NotificationVisibilityLogger(
- mUiBgExecutor, mBarService, mNotificationDataManager);
- }
-
- @Test
- public void log_notifiesStatusBarService() throws RemoteException {
- mNotificationVisibilityLogger.log(/* isVisible= */ true);
- mUiBgExecutor.runNextReady();
-
- verify(mBarService).onNotificationVisibilityChanged(
- any(NotificationVisibility[].class), any(NotificationVisibility[].class));
- }
-
- @Test
- public void log_isVisibleIsTrue_notifiesOfNewlyVisibleItems() throws RemoteException {
- ArgumentCaptor<NotificationVisibility[]> newlyVisibleCaptor =
- ArgumentCaptor.forClass(NotificationVisibility[].class);
- ArgumentCaptor<NotificationVisibility[]> previouslyVisibleCaptor =
- ArgumentCaptor.forClass(NotificationVisibility[].class);
-
- mNotificationVisibilityLogger.log(/* isVisible= */ true);
- mUiBgExecutor.runNextReady();
-
- verify(mBarService).onNotificationVisibilityChanged(
- newlyVisibleCaptor.capture(), previouslyVisibleCaptor.capture());
- assertThat(newlyVisibleCaptor.getValue().length).isEqualTo(1);
- assertThat(previouslyVisibleCaptor.getValue().length).isEqualTo(0);
- }
-
- @Test
- public void log_isVisibleIsFalse_notifiesOfPreviouslyVisibleItems() throws RemoteException {
- ArgumentCaptor<NotificationVisibility[]> newlyVisibleCaptor =
- ArgumentCaptor.forClass(NotificationVisibility[].class);
- ArgumentCaptor<NotificationVisibility[]> previouslyVisibleCaptor =
- ArgumentCaptor.forClass(NotificationVisibility[].class);
- mNotificationVisibilityLogger.log(/* isVisible= */ true);
- mUiBgExecutor.runNextReady();
- reset(mBarService);
-
- mNotificationVisibilityLogger.log(/* isVisible= */ false);
- mUiBgExecutor.runNextReady();
-
- verify(mBarService).onNotificationVisibilityChanged(
- newlyVisibleCaptor.capture(), previouslyVisibleCaptor.capture());
- assertThat(previouslyVisibleCaptor.getValue().length).isEqualTo(1);
- assertThat(newlyVisibleCaptor.getValue().length).isEqualTo(0);
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/rvc/RearViewCameraViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/rvc/RearViewCameraViewControllerTest.java
deleted file mode 100644
index a6160ecf1c62..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/rvc/RearViewCameraViewControllerTest.java
+++ /dev/null
@@ -1,117 +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.car.rvc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.verify;
-
-import android.app.ActivityView;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.testing.TestableLooper;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.car.window.OverlayViewGlobalStateController;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-@CarSystemUiTest
-@RunWith(MockitoJUnitRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class RearViewCameraViewControllerTest extends SysuiTestCase {
- private static final String TEST_ACTIVITY_NAME = "testPackage/testActivity";
- private RearViewCameraViewController mRearViewCameraViewController;
-
- @Mock
- private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
- @Mock
- private ActivityView mMockActivityView;
- @Captor
- private ArgumentCaptor<Intent> mIntentCaptor;
-
- private void setUpRearViewCameraViewController(String testActivityName) {
- mContext.getOrCreateTestableResources().addOverride(
- R.string.config_rearViewCameraActivity, testActivityName);
- mRearViewCameraViewController = new RearViewCameraViewController(
- mContext.getOrCreateTestableResources().getResources(),
- mOverlayViewGlobalStateController);
- mRearViewCameraViewController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate(
- R.layout.sysui_overlay_window, /* root= */ null));
- }
-
- @Test
- public void testEmptyResourceDisablesController() {
- setUpRearViewCameraViewController("");
-
- assertThat(mRearViewCameraViewController.isEnabled()).isFalse();
- }
-
- @Test
- public void testNonEmptyResourceEnablesController() {
- setUpRearViewCameraViewController(TEST_ACTIVITY_NAME);
-
- assertThat(mRearViewCameraViewController.isEnabled()).isTrue();
- }
-
- @Test
- public void testShowInternal() {
- setUpRearViewCameraViewController(TEST_ACTIVITY_NAME);
- assertThat(mRearViewCameraViewController.isShown()).isFalse();
- assertThat(mRearViewCameraViewController.mActivityView).isNull();
-
- mRearViewCameraViewController.showInternal();
-
- assertThat(mRearViewCameraViewController.isShown()).isTrue();
- assertThat(mRearViewCameraViewController.mActivityView).isNotNull();
- }
-
- @Test
- public void testHideInternal() {
- setUpRearViewCameraViewController(TEST_ACTIVITY_NAME);
- assertThat(mRearViewCameraViewController.isShown()).isFalse();
- mRearViewCameraViewController.showInternal();
- assertThat(mRearViewCameraViewController.isShown()).isTrue();
-
- mRearViewCameraViewController.hideInternal();
-
- assertThat(mRearViewCameraViewController.isShown()).isFalse();
- assertThat(mRearViewCameraViewController.mActivityView).isNull();
- }
-
- @Test
- public void testOnActivityViewReady_fireIntent() {
- setUpRearViewCameraViewController(TEST_ACTIVITY_NAME);
- mRearViewCameraViewController.mActivityViewCallback.onActivityViewReady(mMockActivityView);
-
- verify(mMockActivityView).startActivity(mIntentCaptor.capture());
- ComponentName expectedComponent = ComponentName.unflattenFromString(TEST_ACTIVITY_NAME);
- assertThat(mIntentCaptor.getValue().getComponent()).isEqualTo(expectedComponent);
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/rvc/RearViewCameraViewMediatorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/rvc/RearViewCameraViewMediatorTest.java
deleted file mode 100644
index 5be8f91ff430..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/rvc/RearViewCameraViewMediatorTest.java
+++ /dev/null
@@ -1,169 +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.car.rvc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.car.Car;
-import android.car.VehicleAreaType;
-import android.car.VehicleGear;
-import android.car.VehiclePropertyIds;
-import android.car.hardware.CarPropertyValue;
-import android.car.hardware.property.CarPropertyManager;
-import android.car.hardware.property.CarPropertyManager.CarPropertyEventCallback;
-import android.content.BroadcastReceiver;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.testing.TestableLooper;
-import android.util.Log;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.CarServiceProvider.CarServiceOnConnectedListener;
-import com.android.systemui.car.CarSystemUiTest;
-
-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.junit.MockitoJUnitRunner;
-
-@CarSystemUiTest
-@RunWith(MockitoJUnitRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class RearViewCameraViewMediatorTest extends SysuiTestCase {
- private static final String TAG = RearViewCameraViewMediatorTest.class.getSimpleName();
-
- private RearViewCameraViewMediator mRearViewCameraViewMediator;
-
- @Mock
- private CarServiceProvider mCarServiceProvider;
- @Mock
- private Car mCar;
- @Mock
- private CarPropertyManager mCarPropertyManager;
- @Captor
- private ArgumentCaptor<CarPropertyEventCallback> mCarPropertyEventCallbackCaptor;
-
- @Mock
- private BroadcastDispatcher mBroadcastDispatcher;
- @Captor
- private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
- @Captor
- private ArgumentCaptor<IntentFilter> mIntentFilterCaptor;
-
- @Mock
- private RearViewCameraViewController mRearViewCameraViewController;
-
- @Before
- public void setUp() throws Exception {
- mRearViewCameraViewMediator = new RearViewCameraViewMediator(
- mRearViewCameraViewController, mCarServiceProvider, mBroadcastDispatcher);
- }
-
- public void setUpListener() {
- doAnswer(invocation -> {
- CarServiceOnConnectedListener listener = invocation.getArgument(0);
- listener.onConnected(mCar);
- return null;
- }).when(mCarServiceProvider).addListener(any(CarServiceOnConnectedListener.class));
- when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
- when(mRearViewCameraViewController.isEnabled()).thenReturn(true);
-
- mRearViewCameraViewMediator.registerListeners();
-
- verify(mCarPropertyManager).registerCallback(mCarPropertyEventCallbackCaptor.capture(),
- eq(VehiclePropertyIds.GEAR_SELECTION), anyFloat());
- verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(),
- mIntentFilterCaptor.capture(), any(), any());
- assertThat(mIntentFilterCaptor.getValue().getAction(0)).isEqualTo(
- Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- }
-
- @Test
- public void testDoesnNotRegisterListenersWhenRearViewCameraViewControllerIsDisabled() {
- when(mRearViewCameraViewController.isEnabled()).thenReturn(false);
-
- mRearViewCameraViewMediator.registerListeners();
-
- verify(mCarPropertyManager, never()).registerCallback(any(), anyInt(), anyFloat());
- verify(mBroadcastDispatcher, never()).registerReceiver(any(), any(), any());
- }
-
- @Test
- public void testGearReverseStartsRearViewCamera() {
- setUpListener();
-
- CarPropertyValue<Integer> gearReverse = new CarPropertyValue(
- VehiclePropertyIds.GEAR_SELECTION, VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- VehicleGear.GEAR_REVERSE);
- mCarPropertyEventCallbackCaptor.getValue().onChangeEvent(gearReverse);
-
- verify(mRearViewCameraViewController, times(1)).start();
- }
-
- @Test
- public void testGearNonReverseStopsRearViewCamera() {
- setUpListener();
-
- int[] nonReverseVehicleGears = new int[]{
- VehicleGear.GEAR_NEUTRAL, VehicleGear.GEAR_PARK, VehicleGear.GEAR_DRIVE,
- VehicleGear.GEAR_FIRST
- };
- for (int i = 0; i < nonReverseVehicleGears.length; ++i) {
- Log.i(TAG, "testGearNonReverseStopsRearViewCamera: gear=" + nonReverseVehicleGears[i]);
- CarPropertyValue<Integer> propertyGear = new CarPropertyValue(
- VehiclePropertyIds.GEAR_SELECTION, VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL,
- nonReverseVehicleGears[i]);
- mCarPropertyEventCallbackCaptor.getValue().onChangeEvent(propertyGear);
-
- verify(mRearViewCameraViewController, times(i + 1)).stop();
- }
- }
-
- @Test
- public void testBroadcastIntentStopsRearViewCamera() {
- setUpListener();
- when(mRearViewCameraViewController.isShown()).thenReturn(true);
-
- Intent randomIntent = new Intent(Intent.ACTION_MAIN);
- mBroadcastReceiverCaptor.getValue().onReceive(mContext, randomIntent);
-
- verify(mRearViewCameraViewController, never()).stop();
-
- Intent actionCloseSystemDialogs = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- mBroadcastReceiverCaptor.getValue().onReceive(mContext, actionCloseSystemDialogs);
-
- verify(mRearViewCameraViewController, times(1)).stop();
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java
deleted file mode 100644
index bf9ac3017436..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java
+++ /dev/null
@@ -1,166 +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.car.sideloaded;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityTaskManager.RootTaskInfo;
-import android.content.ComponentName;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.InstallSourceInfo;
-import android.content.pm.PackageManager;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableResources;
-
-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.car.CarSystemUiTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class SideLoadedAppDetectorTest extends SysuiTestCase {
-
- private static final String SAFE_VENDOR = "com.safe.vendor";
- private static final String UNSAFE_VENDOR = "com.unsafe.vendor";
- private static final String APP_PACKAGE_NAME = "com.test";
- private static final String APP_CLASS_NAME = ".TestClass";
-
- private SideLoadedAppDetector mSideLoadedAppDetector;
-
- @Mock
- private PackageManager mPackageManager;
- @Mock
- private CarDeviceProvisionedController mCarDeviceProvisionedController;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- TestableResources testableResources = mContext.getOrCreateTestableResources();
- String[] allowedAppInstallSources = new String[] {SAFE_VENDOR};
- testableResources.addOverride(R.array.config_allowedAppInstallSources,
- allowedAppInstallSources);
-
- mSideLoadedAppDetector = new SideLoadedAppDetector(testableResources.getResources(),
- mPackageManager,
- mCarDeviceProvisionedController);
- }
-
- @Test
- public void isSafe_systemApp_returnsTrue() throws Exception {
- RootTaskInfo taskInfo = new RootTaskInfo();
- taskInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
-
- ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.packageName = APP_PACKAGE_NAME;
- applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
-
- when(mPackageManager.getApplicationInfoAsUser(eq(APP_PACKAGE_NAME), anyInt(), any()))
- .thenReturn(applicationInfo);
-
- assertThat(mSideLoadedAppDetector.isSafe(taskInfo)).isTrue();
- }
-
- @Test
- public void isSafe_updatedSystemApp_returnsTrue() throws Exception {
- RootTaskInfo taskInfo = new RootTaskInfo();
- taskInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
-
- ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.packageName = APP_PACKAGE_NAME;
- applicationInfo.flags = ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
-
- when(mPackageManager.getApplicationInfoAsUser(eq(APP_PACKAGE_NAME), anyInt(), any()))
- .thenReturn(applicationInfo);
-
- assertThat(mSideLoadedAppDetector.isSafe(taskInfo)).isTrue();
- }
-
- @Test
- public void isSafe_nonSystemApp_withSafeSource_returnsTrue() throws Exception {
- InstallSourceInfo sourceInfo = new InstallSourceInfo(SAFE_VENDOR,
- /* initiatingPackageSigningInfo= */null,
- /* originatingPackageName= */ null,
- /* installingPackageName= */ null);
- RootTaskInfo taskInfo = new RootTaskInfo();
- taskInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
-
- ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.packageName = APP_PACKAGE_NAME;
-
- when(mPackageManager.getApplicationInfoAsUser(eq(APP_PACKAGE_NAME), anyInt(), any()))
- .thenReturn(applicationInfo);
- when(mPackageManager.getInstallSourceInfo(APP_PACKAGE_NAME)).thenReturn(sourceInfo);
-
- assertThat(mSideLoadedAppDetector.isSafe(taskInfo)).isTrue();
- }
-
- @Test
- public void isSafe_nonSystemApp_withUnsafeSource_returnsFalse() throws Exception {
- InstallSourceInfo sourceInfo = new InstallSourceInfo(UNSAFE_VENDOR,
- /* initiatingPackageSigningInfo= */null,
- /* originatingPackageName= */ null,
- /* installingPackageName= */ null);
- RootTaskInfo taskInfo = new RootTaskInfo();
- taskInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
-
- ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.packageName = APP_PACKAGE_NAME;
-
- when(mPackageManager.getApplicationInfoAsUser(eq(APP_PACKAGE_NAME), anyInt(), any()))
- .thenReturn(applicationInfo);
- when(mPackageManager.getInstallSourceInfo(APP_PACKAGE_NAME)).thenReturn(sourceInfo);
-
- assertThat(mSideLoadedAppDetector.isSafe(taskInfo)).isFalse();
- }
-
- @Test
- public void isSafe_nonSystemApp_withoutSource_returnsFalse() throws Exception {
- InstallSourceInfo sourceInfo = new InstallSourceInfo(null,
- /* initiatingPackageSigningInfo= */null,
- /* originatingPackageName= */ null,
- /* installingPackageName= */ null);
- RootTaskInfo taskInfo = new RootTaskInfo();
- taskInfo.topActivity = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
-
- ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.packageName = APP_PACKAGE_NAME;
-
- when(mPackageManager.getApplicationInfoAsUser(eq(APP_PACKAGE_NAME), anyInt(), any()))
- .thenReturn(applicationInfo);
- when(mPackageManager.getInstallSourceInfo(APP_PACKAGE_NAME)).thenReturn(sourceInfo);
-
- assertThat(mSideLoadedAppDetector.isSafe(taskInfo)).isFalse();
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
deleted file mode 100644
index 0b5f68f76ebc..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
+++ /dev/null
@@ -1,243 +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.car.sideloaded;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityTaskManager.RootTaskInfo;
-import android.app.IActivityTaskManager;
-import android.content.ComponentName;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerGlobal;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.Display;
-import android.view.DisplayAdjustments;
-import android.view.DisplayInfo;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarSystemUiTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class SideLoadedAppListenerTest extends SysuiTestCase {
-
- private static final String APP_PACKAGE_NAME = "com.test";
- private static final String APP_CLASS_NAME = ".TestClass";
-
- private SideLoadedAppListener mSideLoadedAppListener;
-
- @Mock
- private SideLoadedAppDetector mSideLoadedAppDetector;
- @Mock
- private DisplayManager mDisplayManager;
- @Mock
- private IActivityTaskManager mActivityTaskManager;
- @Mock
- private SideLoadedAppStateController mSideLoadedAppStateController;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mSideLoadedAppListener = new SideLoadedAppListener(mSideLoadedAppDetector,
- mActivityTaskManager, mDisplayManager, mSideLoadedAppStateController);
- }
-
- @Test
- public void onTaskCreated_safeTask_callsNoMethods() throws Exception {
- int taskId = 999;
- int displayId = 123;
- ComponentName componentName = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
-
- RootTaskInfo taskInfo1 = createTask(1, /* isVisible= */ true);
- taskInfo1.childTaskIds = new int[] { 11, 22, 33 };
-
- RootTaskInfo taskInfo2 = createTask(2, /* isVisible= */ true);
- taskInfo2.childTaskIds = new int[] { 111, 222, 333, taskId };
- taskInfo2.displayId = displayId;
-
- List<RootTaskInfo> taskInfoList = Arrays.asList(taskInfo1, taskInfo2);
-
- when(mActivityTaskManager.getAllRootTaskInfos()).thenReturn(taskInfoList);
- when(mSideLoadedAppDetector.isSafe(taskInfo2)).thenReturn(true);
-
- mSideLoadedAppListener.onTaskCreated(taskId, componentName);
-
- verify(mSideLoadedAppDetector, never()).isSafe(taskInfo1);
- verify(mSideLoadedAppDetector).isSafe(taskInfo2);
-
- verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
- verify(mSideLoadedAppStateController, never()).onSafeTaskDisplayedOnDisplay(any());
- verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(any());
- }
-
- @Test
- public void onTaskCreated_unsafeTask_callsUnsafeTaskCreated() throws Exception {
- int taskId = 999;
- int displayId = 123;
- ComponentName componentName = new ComponentName(APP_PACKAGE_NAME, APP_CLASS_NAME);
-
- RootTaskInfo taskInfo1 = createTask(1, /* isVisible= */ true);
- taskInfo1.childTaskIds = new int[] { 11, 22, 33 };
- RootTaskInfo taskInfo2 = createTask(2, /* isVisible= */ true);
- taskInfo2.childTaskIds = new int[] { 111, 222, 333, taskId };
- taskInfo2.displayId = displayId;
- List<RootTaskInfo> taskInfoList = Arrays.asList(taskInfo1, taskInfo2);
-
- Display display = createDisplay(displayId);
-
- when(mActivityTaskManager.getAllRootTaskInfos()).thenReturn(taskInfoList);
- when(mSideLoadedAppDetector.isSafe(taskInfo2)).thenReturn(false);
- when(mDisplayManager.getDisplay(displayId)).thenReturn(display);
-
- mSideLoadedAppListener.onTaskCreated(taskId, componentName);
-
- verify(mSideLoadedAppDetector, never()).isSafe(taskInfo1);
- verify(mSideLoadedAppDetector).isSafe(taskInfo2);
-
- verify(mSideLoadedAppStateController).onUnsafeTaskCreatedOnDisplay(display);
- verify(mSideLoadedAppStateController, never()).onSafeTaskDisplayedOnDisplay(any());
- verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(any());
- }
-
- @Test
- public void onTaskStackChanged_safeTask_callsSafeTaskDisplayed() throws Exception {
- Display display = createDisplay(123);
- RootTaskInfo taskInfo1 = createTask(1, /* isVisible= */ false);
- RootTaskInfo taskInfo2 = createTask(2, /* isVisible= */ true);
- RootTaskInfo taskInfo3 = createTask(3, /* isVisible= */ true);
- List<RootTaskInfo> taskInfoList = Arrays.asList(taskInfo1, taskInfo2, taskInfo3);
-
- when(mActivityTaskManager.getAllRootTaskInfosOnDisplay(display.getDisplayId()))
- .thenReturn(taskInfoList);
- when(mSideLoadedAppDetector.isSafe(taskInfo2)).thenReturn(true);
- when(mDisplayManager.getDisplays()).thenReturn(new Display[] { display });
-
- mSideLoadedAppListener.onTaskStackChanged();
-
- verify(mSideLoadedAppDetector, never()).isSafe(taskInfo1);
- verify(mSideLoadedAppDetector).isSafe(taskInfo2);
- verify(mSideLoadedAppDetector, never()).isSafe(taskInfo3);
-
- verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
- verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display);
- verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(any());
- }
-
- @Test
- public void onTaskStackChanged_unsafeTask_callsUnsafeTaskDisplayed() throws Exception {
- Display display = createDisplay(123);
- RootTaskInfo taskInfo1 = createTask(1, /* isVisible= */ false);
- RootTaskInfo taskInfo2 = createTask(2, /* isVisible= */ true);
- RootTaskInfo taskInfo3 = createTask(3, /* isVisible= */ true);
- List<RootTaskInfo> taskInfoList = Arrays.asList(taskInfo1, taskInfo2, taskInfo3);
-
- when(mActivityTaskManager.getAllRootTaskInfosOnDisplay(display.getDisplayId()))
- .thenReturn(taskInfoList);
- when(mSideLoadedAppDetector.isSafe(taskInfo2)).thenReturn(false);
- when(mDisplayManager.getDisplays()).thenReturn(new Display[] { display });
-
- mSideLoadedAppListener.onTaskStackChanged();
-
- verify(mSideLoadedAppDetector, never()).isSafe(taskInfo1);
- verify(mSideLoadedAppDetector).isSafe(taskInfo2);
- verify(mSideLoadedAppDetector, never()).isSafe(taskInfo3);
-
- verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
- verify(mSideLoadedAppStateController, never()).onSafeTaskDisplayedOnDisplay(any());
- verify(mSideLoadedAppStateController).onUnsafeTaskDisplayedOnDisplay(display);
- }
-
- @Test
- public void onTaskStackChanged_multiDisplay_callsTasksDisplayed() throws Exception {
- Display display1 = createDisplay(1);
- RootTaskInfo taskInfo1 = createTask(1, /* isVisible= */ false);
- RootTaskInfo taskInfo2 = createTask(2, /* isVisible= */ true);
- RootTaskInfo taskInfo3 = createTask(3, /* isVisible= */ true);
- List<RootTaskInfo> display1Tasks = Arrays.asList(taskInfo1, taskInfo2, taskInfo3);
-
- Display display2 = createDisplay(2);
- RootTaskInfo taskInfo4 = createTask(4, /* isVisible= */ true);
- List<RootTaskInfo> display2Tasks = Collections.singletonList(taskInfo4);
-
- Display display3 = createDisplay(3);
- RootTaskInfo taskInfo5 = createTask(5, /* isVisible= */ true);
- List<RootTaskInfo> display3Tasks = Collections.singletonList(taskInfo5);
-
- when(mActivityTaskManager.getAllRootTaskInfosOnDisplay(display1.getDisplayId()))
- .thenReturn(display1Tasks);
- when(mActivityTaskManager.getAllRootTaskInfosOnDisplay(display2.getDisplayId()))
- .thenReturn(display2Tasks);
- when(mActivityTaskManager.getAllRootTaskInfosOnDisplay(display3.getDisplayId()))
- .thenReturn(display3Tasks);
-
- when(mSideLoadedAppDetector.isSafe(taskInfo2)).thenReturn(true);
- when(mSideLoadedAppDetector.isSafe(taskInfo4)).thenReturn(false);
- when(mSideLoadedAppDetector.isSafe(taskInfo5)).thenReturn(true);
-
- when(mDisplayManager.getDisplays())
- .thenReturn(new Display[] { display1, display2, display3});
-
- mSideLoadedAppListener.onTaskStackChanged();
-
- verify(mSideLoadedAppDetector, never()).isSafe(taskInfo1);
- verify(mSideLoadedAppDetector).isSafe(taskInfo2);
- verify(mSideLoadedAppDetector, never()).isSafe(taskInfo3);
- verify(mSideLoadedAppDetector).isSafe(taskInfo4);
- verify(mSideLoadedAppDetector).isSafe(taskInfo5);
-
- verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any());
- verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display1);
- verify(mSideLoadedAppStateController).onUnsafeTaskDisplayedOnDisplay(display2);
- verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display3);
- verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(display1);
- verify(mSideLoadedAppStateController).onUnsafeTaskDisplayedOnDisplay(display2);
- verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(display3);
- }
-
- private Display createDisplay(int id) {
- return new Display(DisplayManagerGlobal.getInstance(),
- id,
- new DisplayInfo(),
- DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
- }
-
- private RootTaskInfo createTask(int id, boolean isVisible) {
- RootTaskInfo taskInfo = new RootTaskInfo();
- taskInfo.taskId = id;
- taskInfo.visible = isVisible;
- return taskInfo;
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java
deleted file mode 100644
index ac7edd32c14c..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java
+++ /dev/null
@@ -1,162 +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.car.statusbar;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.car.Car;
-import android.car.user.CarUserManager;
-import android.content.BroadcastReceiver;
-import android.content.Intent;
-import android.content.pm.UserInfo;
-import android.os.UserManager;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.View;
-import android.widget.TextView;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.CarSystemUiTest;
-
-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;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class UserNameViewControllerTest extends SysuiTestCase {
-
- private final UserInfo mUserInfo1 = new UserInfo(/* id= */ 0, "Test User Name", /* flags= */ 0);
- private final UserInfo mUserInfo2 = new UserInfo(/* id= */ 1, "Another User", /* flags= */ 0);
- private TextView mTextView;
- private UserNameViewController mUserNameViewController;
-
- @Mock
- private Car mCar;
- @Mock
- private CarUserManager mCarUserManager;
- @Mock
- private UserManager mUserManager;
- @Mock
- private CarDeviceProvisionedController mCarDeviceProvisionedController;
- @Mock
- private BroadcastDispatcher mBroadcastDispatcher;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mUserManager.getUserInfo(mUserInfo1.id)).thenReturn(mUserInfo1);
- when(mUserManager.getUserInfo(mUserInfo2.id)).thenReturn(mUserInfo2);
- when(mCar.isConnected()).thenReturn(true);
- when(mCar.getCarManager(Car.CAR_USER_SERVICE)).thenReturn(mCarUserManager);
-
- CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
- mUserNameViewController = new UserNameViewController(getContext(), carServiceProvider,
- mUserManager, mBroadcastDispatcher, mCarDeviceProvisionedController);
-
- mTextView = new TextView(getContext());
- mTextView.setId(R.id.user_name_text);
- }
-
- @Test
- public void addUserNameViewToController_updatesUserNameView() {
- when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo1.id);
-
- mUserNameViewController.addUserNameView(mTextView);
-
- assertEquals(mTextView.getText(), mUserInfo1.name);
- }
-
- @Test
- public void addUserNameViewToController_withNoTextView_doesNotUpdate() {
- View nullView = new View(getContext());
- mUserNameViewController.addUserNameView(nullView);
-
- assertEquals(mTextView.getText(), "");
- verifyZeroInteractions(mCarDeviceProvisionedController);
- verifyZeroInteractions(mCarUserManager);
- verifyZeroInteractions(mUserManager);
- }
-
- @Test
- public void removeAll_withNoRegisteredListener_doesNotUnregister() {
- mUserNameViewController.removeAll();
-
- verifyZeroInteractions(mCarUserManager);
- }
-
- @Test
- public void userLifecycleListener_onUserSwitchLifecycleEvent_updatesUserNameView() {
- ArgumentCaptor<CarUserManager.UserLifecycleListener> userLifecycleListenerArgumentCaptor =
- ArgumentCaptor.forClass(CarUserManager.UserLifecycleListener.class);
- when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo1.id);
- // Add the initial TextView, which registers the UserLifecycleListener
- mUserNameViewController.addUserNameView(mTextView);
- assertEquals(mTextView.getText(), mUserInfo1.name);
- verify(mCarUserManager).addListener(any(), userLifecycleListenerArgumentCaptor.capture());
-
- CarUserManager.UserLifecycleEvent event = new CarUserManager.UserLifecycleEvent(
- CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, /* from= */ mUserInfo1.id,
- /* to= */ mUserInfo2.id);
- userLifecycleListenerArgumentCaptor.getValue().onEvent(event);
-
- assertEquals(mTextView.getText(), mUserInfo2.name);
- }
-
- @Test
- public void userInfoChangedBroadcast_withoutInitializingUserNameView_doesNothing() {
- getContext().sendBroadcast(new Intent(Intent.ACTION_USER_INFO_CHANGED));
-
- assertEquals(mTextView.getText(), "");
- verifyZeroInteractions(mCarDeviceProvisionedController);
- }
-
- @Test
- public void userInfoChangedBroadcast_withUserNameViewInitialized_updatesUserNameView() {
- ArgumentCaptor<BroadcastReceiver> broadcastReceiverArgumentCaptor = ArgumentCaptor.forClass(
- BroadcastReceiver.class);
- when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo1.id);
- mUserNameViewController.addUserNameView(mTextView);
- assertEquals(mTextView.getText(), mUserInfo1.name);
- verify(mBroadcastDispatcher).registerReceiver(broadcastReceiverArgumentCaptor.capture(),
- any(), any(), any());
-
- reset(mCarDeviceProvisionedController);
- when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo2.id);
- broadcastReceiverArgumentCaptor.getValue().onReceive(getContext(),
- new Intent(Intent.ACTION_USER_INFO_CHANGED));
-
- assertEquals(mTextView.getText(), mUserInfo2.name);
- verify(mCarDeviceProvisionedController).getCurrentUser();
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
deleted file mode 100644
index 2e9d43b595a1..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
+++ /dev/null
@@ -1,178 +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.car.userswitcher;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.Handler;
-import android.os.UserManager;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableResources;
-import android.view.IWindowManager;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.car.window.OverlayViewGlobalStateController;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class UserSwitchTransitionViewControllerTest extends SysuiTestCase {
- private static final int TEST_USER_1 = 100;
- private static final int TEST_USER_2 = 110;
-
- private TestableUserSwitchTransitionViewController mCarUserSwitchingDialogController;
- private TestableResources mTestableResources;
- @Mock
- private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
- @Mock
- private IWindowManager mWindowManagerService;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mTestableResources = mContext.getOrCreateTestableResources();
- mCarUserSwitchingDialogController = new TestableUserSwitchTransitionViewController(
- mContext,
- Handler.getMain(),
- mTestableResources.getResources(),
- (UserManager) mContext.getSystemService(Context.USER_SERVICE),
- mWindowManagerService,
- mOverlayViewGlobalStateController
- );
-
- mCarUserSwitchingDialogController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate(
- R.layout.sysui_overlay_window, /* root= */ null));
- }
-
- @Test
- public void onHandleShow_newUserSelected_showsDialog() {
- mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
-
- verify(mOverlayViewGlobalStateController).showView(eq(mCarUserSwitchingDialogController),
- any());
- }
-
- @Test
- public void onHandleShow_alreadyShowing_ignoresRequest() {
- mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
- mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_2);
-
- // Verify that the request was processed only once.
- verify(mOverlayViewGlobalStateController).showView(eq(mCarUserSwitchingDialogController),
- any());
- }
-
- @Test
- public void onHandleShow_sameUserSelected_ignoresRequest() {
- mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
- mCarUserSwitchingDialogController.handleHide();
- mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
-
- // Verify that the request was processed only once.
- verify(mOverlayViewGlobalStateController).showView(eq(mCarUserSwitchingDialogController),
- any());
- }
-
- @Test
- public void onHide_currentlyShowing_hidesDialog() {
- mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
- mCarUserSwitchingDialogController.handleHide();
-
- verify(mOverlayViewGlobalStateController).hideView(eq(mCarUserSwitchingDialogController),
- any());
- }
-
- @Test
- public void onHide_notShowing_ignoresRequest() {
- mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
- mCarUserSwitchingDialogController.handleHide();
- mCarUserSwitchingDialogController.handleHide();
-
- // Verify that the request was processed only once.
- verify(mOverlayViewGlobalStateController).hideView(eq(mCarUserSwitchingDialogController),
- any());
- }
-
- @Test
- public void onWindowShownTimeoutPassed_viewNotHidden_hidesUserSwitchTransitionView() {
- mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
- reset(mOverlayViewGlobalStateController);
-
- getContext().getMainThreadHandler().postDelayed(() -> {
- verify(mOverlayViewGlobalStateController).hideView(
- eq(mCarUserSwitchingDialogController), any());
- }, mCarUserSwitchingDialogController.getWindowShownTimeoutMs() + 10);
- }
-
- @Test
- public void onWindowShownTimeoutPassed_viewHidden_doesNotHideUserSwitchTransitionViewAgain() {
- mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
- mCarUserSwitchingDialogController.handleHide();
- reset(mOverlayViewGlobalStateController);
-
- getContext().getMainThreadHandler().postDelayed(() -> {
- verify(mOverlayViewGlobalStateController, never()).hideView(
- eq(mCarUserSwitchingDialogController), any());
- }, mCarUserSwitchingDialogController.getWindowShownTimeoutMs() + 10);
- }
-
- private final class TestableUserSwitchTransitionViewController extends
- UserSwitchTransitionViewController {
-
- private final Handler mHandler;
-
- TestableUserSwitchTransitionViewController(Context context, Handler handler,
- Resources resources, UserManager userManager,
- IWindowManager windowManagerService,
- OverlayViewGlobalStateController overlayViewGlobalStateController) {
- super(context, handler, resources, userManager, windowManagerService,
- overlayViewGlobalStateController);
- mHandler = handler;
- }
-
- @Override
- public void handleShow(int currentUserId) {
- super.handleShow(currentUserId);
- waitForIdleSync(mHandler);
- }
-
- @Override
- public void handleHide() {
- super.handleHide();
- waitForIdleSync(mHandler);
- }
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
deleted file mode 100644
index 7aeffce7042d..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
+++ /dev/null
@@ -1,97 +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.car.userswitcher;
-
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.car.user.CarUserManager;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarServiceProvider;
-import com.android.systemui.car.CarSystemUiTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class UserSwitchTransitionViewMediatorTest extends SysuiTestCase {
- private static final int TEST_USER = 100;
-
- private UserSwitchTransitionViewMediator mUserSwitchTransitionViewMediator;
- @Mock
- private CarServiceProvider mCarServiceProvider;
- @Mock
- private CarDeviceProvisionedController mCarDeviceProvisionedController;
- @Mock
- private UserSwitchTransitionViewController mUserSwitchTransitionViewController;
- @Mock
- private CarUserManager.UserLifecycleEvent mUserLifecycleEvent;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mUserSwitchTransitionViewMediator = new UserSwitchTransitionViewMediator(
- mCarServiceProvider, mCarDeviceProvisionedController,
- mUserSwitchTransitionViewController);
- when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(TEST_USER);
- }
-
- @Test
- public void onUserLifecycleEvent_userStarting_isCurrentUser_callsHandleShow() {
- when(mUserLifecycleEvent.getEventType()).thenReturn(
- CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING);
- when(mUserLifecycleEvent.getUserId()).thenReturn(TEST_USER);
-
- mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent);
-
- verify(mUserSwitchTransitionViewController).handleShow(TEST_USER);
- }
-
- @Test
- public void onUserLifecycleEvent_userStarting_isNotCurrentUser_doesNotCallHandleShow() {
- when(mUserLifecycleEvent.getEventType()).thenReturn(
- CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING);
- when(mUserLifecycleEvent.getUserId()).thenReturn(TEST_USER);
- when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(TEST_USER + 1);
-
- mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent);
-
- verify(mUserSwitchTransitionViewController, never()).handleShow(TEST_USER);
- }
-
- @Test
- public void onUserLifecycleEvent_userSwitching_callsHandleHide() {
- when(mUserLifecycleEvent.getEventType()).thenReturn(
- CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING);
- mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent);
-
- verify(mUserSwitchTransitionViewController).handleHide();
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
deleted file mode 100644
index f77294e37b98..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
+++ /dev/null
@@ -1,135 +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.car.voicerecognition;
-
-import static com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier.INVALID_VALUE;
-import static com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier.VOICE_RECOGNITION_STARTED;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadsetClient;
-import android.content.Intent;
-import android.os.Handler;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarSystemUiTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-// TODO(b/162866441): Refactor to use the Executor pattern instead.
-public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
-
- private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
- private static final String BLUETOOTH_REMOTE_ADDRESS = "00:11:22:33:44:55";
-
- private ConnectedDeviceVoiceRecognitionNotifier mVoiceRecognitionNotifier;
- private TestableLooper mTestableLooper;
- private Handler mHandler;
- private Handler mTestHandler;
- private BluetoothDevice mBluetoothDevice;
-
- @Before
- public void setUp() throws Exception {
- mTestableLooper = TestableLooper.get(this);
- mHandler = new Handler(mTestableLooper.getLooper());
- mTestHandler = spy(mHandler);
- mBluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
- BLUETOOTH_REMOTE_ADDRESS);
- mVoiceRecognitionNotifier = new ConnectedDeviceVoiceRecognitionNotifier(
- mContext, mTestHandler);
- mVoiceRecognitionNotifier.onBootCompleted();
- }
-
- @Test
- public void testReceiveIntent_started_showToast() {
- Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
- intent.putExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, VOICE_RECOGNITION_STARTED);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
-
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- mTestableLooper.processAllMessages();
- waitForIdleSync();
-
- mHandler.post(() -> {
- ArgumentCaptor<Runnable> argumentCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mTestHandler).post(argumentCaptor.capture());
- assertThat(argumentCaptor.getValue()).isNotNull();
- assertThat(argumentCaptor.getValue()).isNotEqualTo(this);
- });
- }
-
- @Test
- public void testReceiveIntent_invalidExtra_noToast() {
- Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
- intent.putExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, INVALID_VALUE);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
-
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- mTestableLooper.processAllMessages();
- waitForIdleSync();
-
- mHandler.post(() -> {
- verify(mTestHandler, never()).post(any());
- });
- }
-
- @Test
- public void testReceiveIntent_noExtra_noToast() {
- Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
-
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- mTestableLooper.processAllMessages();
- waitForIdleSync();
-
- mHandler.post(() -> {
- verify(mTestHandler, never()).post(any());
- });
- }
-
- @Test
- public void testReceiveIntent_invalidIntent_noToast() {
- Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice);
-
- mContext.sendBroadcast(intent, BLUETOOTH_PERM);
- mTestableLooper.processAllMessages();
- waitForIdleSync();
-
- mHandler.post(() -> {
- verify(mTestHandler, never()).post(any());
- });
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
deleted file mode 100644
index f5f3ea3030da..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
+++ /dev/null
@@ -1,499 +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.car.window;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.animation.Animator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarDeviceProvisionedController;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.tests.R;
-import com.android.wm.shell.animation.FlingAnimationUtils;
-
-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 java.util.ArrayList;
-import java.util.List;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class OverlayPanelViewControllerTest extends SysuiTestCase {
- private TestOverlayPanelViewController mOverlayPanelViewController;
- private ViewGroup mBaseLayout;
-
- @Mock
- private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
- @Mock
- private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
- @Mock
- private FlingAnimationUtils mFlingAnimationUtils;
- @Mock
- private CarDeviceProvisionedController mCarDeviceProvisionedController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate(
- R.layout.overlay_view_controller_test, /* root= */ null);
-
- when(mFlingAnimationUtilsBuilder.setMaxLengthSeconds(anyFloat())).thenReturn(
- mFlingAnimationUtilsBuilder);
- when(mFlingAnimationUtilsBuilder.setSpeedUpFactor(anyFloat())).thenReturn(
- mFlingAnimationUtilsBuilder);
- when(mFlingAnimationUtilsBuilder.build()).thenReturn(mFlingAnimationUtils);
- mOverlayPanelViewController = new TestOverlayPanelViewController(
- getContext(),
- getContext().getOrCreateTestableResources().getResources(),
- R.id.overlay_view_controller_stub,
- mOverlayViewGlobalStateController,
- mFlingAnimationUtilsBuilder,
- mCarDeviceProvisionedController);
- }
-
- @Test
- public void toggle_notInflated_inflates() {
- assertThat(mOverlayPanelViewController.isInflated()).isFalse();
-
- mOverlayPanelViewController.toggle();
-
- verify(mOverlayViewGlobalStateController).inflateView(mOverlayPanelViewController);
- }
-
- @Test
- public void toggle_inflated_doesNotInflate() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- assertThat(mOverlayPanelViewController.isInflated()).isTrue();
-
- mOverlayPanelViewController.toggle();
-
- verify(mOverlayViewGlobalStateController, never()).inflateView(mOverlayPanelViewController);
- }
-
- @Test
- public void toggle_notExpanded_panelExpands() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.setPanelExpanded(false);
-
- mOverlayPanelViewController.toggle();
-
- assertThat(mOverlayPanelViewController.mAnimateExpandPanelCalled).isTrue();
- }
-
- @Test
- public void toggle_expanded_panelCollapses() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.setPanelExpanded(true);
-
- mOverlayPanelViewController.toggle();
-
- assertThat(mOverlayPanelViewController.mAnimateCollapsePanelCalled).isTrue();
- }
-
- @Test
- public void animateCollapsePanel_shouldNotAnimateCollapsePanel_doesNotCollapse() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.setShouldAnimateCollapsePanel(false);
-
- mOverlayPanelViewController.animateCollapsePanel();
-
- assertThat(mOverlayPanelViewController.mAnimateCollapsePanelCalled).isTrue();
- assertThat(mOverlayPanelViewController.mOnAnimateCollapsePanelCalled).isFalse();
- }
-
- @Test
- public void animateCollapsePanel_isNotExpanded_doesNotCollapse() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.setShouldAnimateCollapsePanel(true);
- mOverlayPanelViewController.setPanelExpanded(false);
-
- mOverlayPanelViewController.animateCollapsePanel();
-
- assertThat(mOverlayPanelViewController.mAnimateCollapsePanelCalled).isTrue();
- assertThat(mOverlayPanelViewController.mOnAnimateCollapsePanelCalled).isFalse();
- }
-
- @Test
- public void animateCollapsePanel_isNotVisible_doesNotCollapse() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.setShouldAnimateCollapsePanel(true);
- mOverlayPanelViewController.setPanelExpanded(true);
- mOverlayPanelViewController.setPanelVisible(false);
-
- mOverlayPanelViewController.animateCollapsePanel();
-
- assertThat(mOverlayPanelViewController.mAnimateCollapsePanelCalled).isTrue();
- assertThat(mOverlayPanelViewController.mOnAnimateCollapsePanelCalled).isFalse();
- }
-
- @Test
- public void animateCollapsePanel_collapses() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.setShouldAnimateCollapsePanel(true);
- mOverlayPanelViewController.setPanelExpanded(true);
- mOverlayPanelViewController.setPanelVisible(true);
-
- mOverlayPanelViewController.animateCollapsePanel();
-
- assertThat(mOverlayPanelViewController.mOnAnimateCollapsePanelCalled).isTrue();
- }
-
- @Test
- public void animateCollapsePanel_withOverlayFromTopBar_collapsesTowardsTopBar() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- // Mock a panel that has layout size 50 and where the panel is opened.
- int size = 50;
- mockPanelWithSize(size);
- mOverlayPanelViewController.getLayout().setClipBounds(
- new Rect(0, 0, size, size));
- mOverlayPanelViewController.setShouldAnimateCollapsePanel(true);
- mOverlayPanelViewController.setPanelExpanded(true);
- mOverlayPanelViewController.setPanelVisible(true);
- mOverlayPanelViewController.setOverlayDirection(
- OverlayPanelViewController.OVERLAY_FROM_TOP_BAR);
-
- mOverlayPanelViewController.animateCollapsePanel();
-
- ArgumentCaptor<Float> endValueCaptor = ArgumentCaptor.forClass(Float.class);
- verify(mFlingAnimationUtils).apply(
- any(Animator.class), anyFloat(), endValueCaptor.capture(), anyFloat());
- assertThat(endValueCaptor.getValue().intValue()).isEqualTo(0);
- }
-
- @Test
- public void animateCollapsePanel_withOverlayFromBottomBar_collapsesTowardsBottomBar() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- // Mock a panel that has layout size 50 and where the panel is opened.
- int size = 50;
- mockPanelWithSize(size);
- mOverlayPanelViewController.getLayout().setClipBounds(
- new Rect(0, 0, size, size));
- mOverlayPanelViewController.setShouldAnimateCollapsePanel(true);
- mOverlayPanelViewController.setPanelExpanded(true);
- mOverlayPanelViewController.setPanelVisible(true);
- mOverlayPanelViewController.setOverlayDirection(
- OverlayPanelViewController.OVERLAY_FROM_BOTTOM_BAR);
-
- mOverlayPanelViewController.animateCollapsePanel();
-
- ArgumentCaptor<Float> endValueCaptor = ArgumentCaptor.forClass(Float.class);
- verify(mFlingAnimationUtils).apply(
- any(Animator.class), anyFloat(), endValueCaptor.capture(), anyFloat());
- assertThat(endValueCaptor.getValue().intValue()).isEqualTo(
- mOverlayPanelViewController.getLayout().getHeight());
- }
-
- @Test
- public void animateExpandPanel_shouldNotAnimateExpandPanel_doesNotExpand() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.setShouldAnimateExpandPanel(false);
-
- mOverlayPanelViewController.animateExpandPanel();
-
- assertThat(mOverlayPanelViewController.mAnimateExpandPanelCalled).isTrue();
- assertThat(mOverlayPanelViewController.mOnAnimateExpandPanelCalled).isFalse();
- }
-
- @Test
- public void animateExpandPanel_userNotSetup_doesNotExpand() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.setShouldAnimateExpandPanel(true);
- when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(false);
-
- mOverlayPanelViewController.animateExpandPanel();
-
- assertThat(mOverlayPanelViewController.mAnimateExpandPanelCalled).isTrue();
- assertThat(mOverlayPanelViewController.mOnAnimateExpandPanelCalled).isFalse();
- }
-
- @Test
- public void animateExpandPanel_expands() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.setShouldAnimateExpandPanel(true);
- when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true);
-
- mOverlayPanelViewController.animateExpandPanel();
-
- assertThat(mOverlayPanelViewController.mOnAnimateExpandPanelCalled).isTrue();
- }
-
- @Test
- public void animateExpandPanel_withOverlayFromTopBar_expandsToBottom() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- // Mock a panel that has layout size 50 and where the panel is not opened.
- int size = 50;
- mockPanelWithSize(size);
- mOverlayPanelViewController.getLayout().setClipBounds(
- new Rect(0, 0, size, 0));
- mOverlayPanelViewController.setShouldAnimateExpandPanel(true);
- when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true);
- mOverlayPanelViewController.setOverlayDirection(
- OverlayPanelViewController.OVERLAY_FROM_TOP_BAR);
-
- mOverlayPanelViewController.animateExpandPanel();
-
- ArgumentCaptor<Float> endValueCaptor = ArgumentCaptor.forClass(Float.class);
- verify(mFlingAnimationUtils).apply(
- any(Animator.class), anyFloat(), endValueCaptor.capture(), anyFloat());
- assertThat(endValueCaptor.getValue().intValue()).isEqualTo(
- mOverlayPanelViewController.getLayout().getHeight());
- }
-
- @Test
- public void animateExpandPanel_withOverlayFromBottomBar_expandsToTop() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- // Mock a panel that has layout size 50 and where the panel is not opened.
- int size = 50;
- mockPanelWithSize(size);
- mOverlayPanelViewController.getLayout().setClipBounds(
- new Rect(0, size, size, size));
- mOverlayPanelViewController.setShouldAnimateExpandPanel(true);
- when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true);
- mOverlayPanelViewController.setOverlayDirection(
- OverlayPanelViewController.OVERLAY_FROM_BOTTOM_BAR);
-
- mOverlayPanelViewController.animateExpandPanel();
-
- ArgumentCaptor<Float> endValueCaptor = ArgumentCaptor.forClass(Float.class);
- verify(mFlingAnimationUtils).apply(
- any(Animator.class), anyFloat(), endValueCaptor.capture(), anyFloat());
- assertThat(endValueCaptor.getValue().intValue()).isEqualTo(0);
- }
-
- @Test
- public void animateExpandPanel_setsPanelVisible() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.setShouldAnimateExpandPanel(true);
- when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true);
-
- mOverlayPanelViewController.animateExpandPanel();
-
- assertThat(mOverlayPanelViewController.isPanelVisible()).isTrue();
- }
-
- @Test
- public void animateExpandPanel_setsPanelExpanded() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.setShouldAnimateExpandPanel(true);
- when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true);
-
- mOverlayPanelViewController.animateExpandPanel();
-
- assertThat(mOverlayPanelViewController.isPanelExpanded()).isTrue();
- }
-
- @Test
- public void setPanelVisible_setTrue_windowNotVisible_setsWindowVisible() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- when(mOverlayViewGlobalStateController.isWindowVisible()).thenReturn(false);
-
- mOverlayPanelViewController.setPanelVisible(true);
-
- verify(mOverlayViewGlobalStateController).showView(mOverlayPanelViewController);
- }
-
- @Test
- public void setPanelVisible_setTrue_windowVisible_doesNotSetWindowVisible() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- when(mOverlayViewGlobalStateController.isWindowVisible()).thenReturn(true);
-
- mOverlayPanelViewController.setPanelVisible(true);
-
- verify(mOverlayViewGlobalStateController, never()).showView(mOverlayPanelViewController);
- }
-
- @Test
- public void setPanelVisible_setTrue_setLayoutVisible() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.getLayout().setVisibility(View.INVISIBLE);
-
- mOverlayPanelViewController.setPanelVisible(true);
-
- assertThat(mOverlayPanelViewController.getLayout().getVisibility()).isEqualTo(View.VISIBLE);
- }
-
- @Test
- public void setPanelVisible_setFalse_windowVisible_setsWindowNotVisible() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- when(mOverlayViewGlobalStateController.isWindowVisible()).thenReturn(true);
-
- mOverlayPanelViewController.setPanelVisible(false);
-
- verify(mOverlayViewGlobalStateController).hideView(mOverlayPanelViewController);
- }
-
- @Test
- public void setPanelVisible_setFalse_windowNotVisible_doesNotSetWindowNotVisible() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- when(mOverlayViewGlobalStateController.isWindowVisible()).thenReturn(false);
-
- mOverlayPanelViewController.setPanelVisible(false);
-
- verify(mOverlayViewGlobalStateController, never()).hideView(mOverlayPanelViewController);
- }
-
- @Test
- public void setPanelVisible_setFalse_setLayoutInvisible() {
- mOverlayPanelViewController.inflate(mBaseLayout);
- mOverlayPanelViewController.getLayout().setVisibility(View.VISIBLE);
-
- mOverlayPanelViewController.setPanelVisible(false);
-
- assertThat(mOverlayPanelViewController.getLayout().getVisibility()).isEqualTo(
- View.INVISIBLE);
- }
-
- @Test
- public void dragOpenTouchListener_isNotInflated_inflatesView() {
- when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true);
- assertThat(mOverlayPanelViewController.isInflated()).isFalse();
-
- mOverlayPanelViewController.getDragOpenTouchListener().onTouch(/* v= */ null,
- MotionEvent.obtain(/* downTime= */ 200, /* eventTime= */ 300,
- MotionEvent.ACTION_MOVE, /* x= */ 0, /* y= */ 0, /* metaState= */ 0));
-
- verify(mOverlayViewGlobalStateController).inflateView(mOverlayPanelViewController);
- }
-
- private void mockPanelWithSize(int size) {
- mOverlayPanelViewController.getLayout().setLeftTopRightBottom(0, 0, size, size);
- }
-
- private static class TestOverlayPanelViewController extends OverlayPanelViewController {
-
- boolean mOnAnimateCollapsePanelCalled;
- boolean mAnimateCollapsePanelCalled;
- boolean mOnAnimateExpandPanelCalled;
- boolean mAnimateExpandPanelCalled;
- boolean mOnCollapseAnimationEndCalled;
- boolean mOnExpandAnimationEndCalled;
- boolean mOnOpenScrollStartEnd;
- List<Integer> mOnScrollHeights;
- private boolean mShouldAnimateCollapsePanel;
- private boolean mShouldAnimateExpandPanel;
- private boolean mShouldAllowClosingScroll;
-
- TestOverlayPanelViewController(
- Context context,
- Resources resources,
- int stubId,
- OverlayViewGlobalStateController overlayViewGlobalStateController,
- FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
- CarDeviceProvisionedController carDeviceProvisionedController) {
- super(context, resources, stubId, overlayViewGlobalStateController,
- flingAnimationUtilsBuilder,
- carDeviceProvisionedController);
-
- mOnScrollHeights = new ArrayList<>();
- }
-
- public void setShouldAnimateCollapsePanel(boolean shouldAnimate) {
- mShouldAnimateCollapsePanel = shouldAnimate;
- }
-
- @Override
- protected boolean shouldAnimateCollapsePanel() {
- return mShouldAnimateCollapsePanel;
- }
-
- @Override
- protected void animateCollapsePanel() {
- super.animateCollapsePanel();
- mAnimateCollapsePanelCalled = true;
- }
-
- @Override
- protected void onAnimateCollapsePanel() {
- mOnAnimateCollapsePanelCalled = true;
- }
-
- public void setShouldAnimateExpandPanel(boolean shouldAnimate) {
- mShouldAnimateExpandPanel = shouldAnimate;
- }
-
- @Override
- protected boolean shouldAnimateExpandPanel() {
- return mShouldAnimateExpandPanel;
- }
-
- @Override
- protected void animateExpandPanel() {
- super.animateExpandPanel();
- mAnimateExpandPanelCalled = true;
- }
-
- @Override
- protected void onAnimateExpandPanel() {
- mOnAnimateExpandPanelCalled = true;
- }
-
- @Override
- protected void onCollapseAnimationEnd() {
- mOnCollapseAnimationEndCalled = true;
- }
-
- @Override
- protected void onExpandAnimationEnd() {
- mOnExpandAnimationEndCalled = true;
- }
-
- @Override
- protected void onScroll(int height) {
- mOnScrollHeights.add(height);
- }
-
- @Override
- protected void onOpenScrollStart() {
- mOnOpenScrollStartEnd = true;
- }
-
- public void setShouldAllowClosingScroll(boolean shouldAllow) {
- mShouldAllowClosingScroll = shouldAllow;
- }
-
- @Override
- protected boolean shouldAllowClosingScroll() {
- return mShouldAllowClosingScroll;
- }
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java
deleted file mode 100644
index e784761f6d5d..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java
+++ /dev/null
@@ -1,160 +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.car.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.car.CarSystemUiTest;
-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;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class OverlayViewControllerTest extends SysuiTestCase {
- private TestOverlayViewController mOverlayViewController;
- private ViewGroup mBaseLayout;
-
- @Mock
- private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
-
- @Captor
- private ArgumentCaptor<Runnable> mRunnableArgumentCaptor;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(/* testClass= */ this);
-
- mOverlayViewController = new TestOverlayViewController(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 TestOverlayViewController extends OverlayViewController {
- boolean mOnFinishInflateCalled = false;
- boolean mShowInternalCalled = false;
- boolean mHideInternalCalled = false;
-
- TestOverlayViewController(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/car/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
deleted file mode 100644
index 9c2931a8ad22..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
+++ /dev/null
@@ -1,985 +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.car.window;
-
-import static android.view.WindowInsets.Type.navigationBars;
-import static android.view.WindowInsets.Type.statusBars;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewStub;
-import android.view.WindowInsets;
-import android.view.WindowInsetsController;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.tests.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Arrays;
-
-@CarSystemUiTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
- private static final int OVERLAY_VIEW_CONTROLLER_1_Z_ORDER = 0;
- private static final int OVERLAY_VIEW_CONTROLLER_2_Z_ORDER = 1;
- private static final int OVERLAY_PANEL_VIEW_CONTROLLER_Z_ORDER = 2;
-
- private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
- private ViewGroup mBaseLayout;
-
- @Mock
- private SystemUIOverlayWindowController mSystemUIOverlayWindowController;
- @Mock
- private OverlayViewMediator mOverlayViewMediator;
- @Mock
- private OverlayViewController mOverlayViewController1;
- @Mock
- private OverlayViewController mOverlayViewController2;
- @Mock
- private OverlayPanelViewController mOverlayPanelViewController;
- @Mock
- private Runnable mRunnable;
- @Mock
- private WindowInsetsController mWindowInsetsController;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(/* testClass= */ this);
-
- mBaseLayout = spy((ViewGroup) LayoutInflater.from(mContext).inflate(
- R.layout.overlay_view_global_state_controller_test, /* root= */ null));
-
- when(mBaseLayout.getWindowInsetsController()).thenReturn(mWindowInsetsController);
-
- when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
-
- mOverlayViewGlobalStateController = new OverlayViewGlobalStateController(
- mSystemUIOverlayWindowController);
-
- verify(mSystemUIOverlayWindowController).attach();
- }
-
- @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_nothingVisible_windowNotFocusable_shouldShowNavBar_navBarsVisible() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(false);
- when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).show(navigationBars());
- }
-
- @Test
- public void showView_nothingVisible_windowNotFocusable_shouldHideNavBar_notHidden() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(false);
- when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController, never()).hide(navigationBars());
- }
-
- @Test
- public void showView_nothingVisible_windowNotFocusable_shouldShowStatusBar_statusBarsVisible() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(false);
- when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).show(statusBars());
- }
-
- @Test
- public void showView_nothingVisible_windowNotFocusable_shouldHideStatusBar_notHidden() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(false);
- when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController, never()).hide(statusBars());
- }
-
- @Test
- public void showView_nothingAlreadyShown_shouldShowNavBarFalse_navigationBarsHidden() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).hide(navigationBars());
- }
-
- @Test
- public void showView_nothingAlreadyShown_shouldShowNavBarTrue_navigationBarsShown() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).show(navigationBars());
- }
-
- @Test
- public void showView_nothingAlreadyShown_shouldShowStatusBarFalse_statusBarsHidden() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).hide(statusBars());
- }
-
- @Test
- public void showView_nothingAlreadyShown_shouldShowStatusBarTrue_statusBarsShown() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).show(statusBars());
- }
-
- @Test
- public void showView_nothingAlreadyShown_fitsNavBarInsets_insetsAdjusted() {
- setupOverlayViewController1();
- when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(navigationBars());
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setFitInsetsTypes(navigationBars());
- }
-
- @Test
- public void showView_nothingAlreadyShown_windowIsSetVisible() {
- setupOverlayViewController1();
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setWindowVisible(true);
- }
-
- @Test
- public void showView_nothingAlreadyShown_newHighestZOrder() {
- setupOverlayViewController1();
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
- mOverlayViewController1);
- }
-
- @Test
- public void showView_nothingAlreadyShown_newHighestZOrder_isVisible() {
- setupOverlayViewController1();
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsKey(
- OVERLAY_VIEW_CONTROLLER_1_Z_ORDER)).isTrue();
- }
-
- @Test
- public void showView_newHighestZOrder() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setupOverlayViewController2();
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
- mOverlayViewController2);
- }
-
- @Test
- public void showView_newHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(false);
- reset(mWindowInsetsController);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
-
- verify(mWindowInsetsController).hide(navigationBars());
- }
-
- @Test
- public void showView_newHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(true);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
-
- verify(mWindowInsetsController).show(navigationBars());
- }
-
- @Test
- public void showView_newHighestZOrder_shouldShowStatusBarFalse_statusBarsHidden() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(false);
- reset(mWindowInsetsController);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
-
- verify(mWindowInsetsController).hide(statusBars());
- }
-
- @Test
- public void showView_newHighestZOrder_shouldShowStatusBarTrue_statusBarsShown() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(true);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
-
- verify(mWindowInsetsController).show(statusBars());
- }
-
- @Test
- public void showView_newHighestZOrder_fitsNavBarInsets_insetsAdjusted() {
- setupOverlayViewController1();
- when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(statusBars());
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setupOverlayViewController2();
- when(mOverlayViewController2.getInsetTypesToFit()).thenReturn(navigationBars());
- reset(mWindowInsetsController);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setFitInsetsTypes(navigationBars());
- }
-
- @Test
- public void showView_newHighestZOrder_correctViewsShown() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setupOverlayViewController2();
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.keySet().toArray())
- .isEqualTo(Arrays.asList(OVERLAY_VIEW_CONTROLLER_1_Z_ORDER,
- OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray());
- }
-
- @Test
- public void showView_oldHighestZOrder() {
- setupOverlayViewController2();
- setOverlayViewControllerAsShowing(mOverlayViewController2);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
- mOverlayViewController2);
- }
-
- @Test
- public void showView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() {
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true);
- when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(false);
- reset(mWindowInsetsController);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).hide(navigationBars());
- }
-
- @Test
- public void showView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() {
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false);
- when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(true);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).show(navigationBars());
- }
-
- @Test
- public void showView_oldHighestZOrder_shouldShowStatusBarFalse_statusBarsHidden() {
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true);
- when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(false);
- reset(mWindowInsetsController);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).hide(statusBars());
- }
-
- @Test
- public void showView_oldHighestZOrder_shouldShowStatusBarTrue_statusBarsShown() {
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false);
- when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(true);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).show(statusBars());
- }
-
- @Test
- public void showView_oldHighestZOrder_fitsNavBarInsets_insetsAdjusted() {
- setupOverlayViewController2();
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(statusBars());
- when(mOverlayViewController2.getInsetTypesToFit()).thenReturn(navigationBars());
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setFitInsetsTypes(navigationBars());
- }
-
- @Test
- public void showView_oldHighestZOrder_correctViewsShown() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- setOverlayViewControllerAsShowing(mOverlayViewController2);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.keySet().toArray())
- .isEqualTo(Arrays.asList(OVERLAY_VIEW_CONTROLLER_1_Z_ORDER,
- OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray());
- }
-
- @Test
- public void showView_somethingAlreadyShown_windowVisibleNotCalled() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setupOverlayViewController2();
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
-
- verify(mSystemUIOverlayWindowController, never()).setWindowVisible(true);
- }
-
- @Test
- public void showView_viewControllerNotInflated_inflateViewController() {
- setupOverlayViewController2();
- when(mOverlayViewController2.isInflated()).thenReturn(false);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
-
- verify(mOverlayViewController2).inflate(mBaseLayout);
- }
-
- @Test
- public void showView_viewControllerInflated_inflateViewControllerNotCalled() {
- setupOverlayViewController2();
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
-
- verify(mOverlayViewController2, never()).inflate(mBaseLayout);
- }
-
- @Test
- public void showView_panelViewController_inflateViewControllerNotCalled() {
- setupOverlayPanelViewController();
-
- mOverlayViewGlobalStateController.showView(mOverlayPanelViewController, mRunnable);
-
- verify(mOverlayPanelViewController, never()).inflate(mBaseLayout);
- verify(mOverlayPanelViewController, never()).isInflated();
- }
-
- @Test
- public void showView_showRunnableCalled() {
- setupOverlayViewController1();
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mRunnable).run();
- }
-
- @Test
- public void hideView_viewControllerNotInflated_hideRunnableNotCalled() {
- when(mOverlayViewController2.isInflated()).thenReturn(false);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
-
- verify(mRunnable, never()).run();
- }
-
- @Test
- public void hideView_nothingShown_hideRunnableNotCalled() {
- when(mOverlayViewController2.isInflated()).thenReturn(true);
- mOverlayViewGlobalStateController.mZOrderMap.clear();
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
-
- verify(mRunnable, never()).run();
- }
-
- @Test
- public void hideView_viewControllerNotShown_hideRunnableNotCalled() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- when(mOverlayViewController2.isInflated()).thenReturn(true);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
-
- verify(mRunnable, never()).run();
- }
-
- @Test
- public void hideView_viewControllerShown_hideRunnableCalled() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- verify(mRunnable).run();
- }
-
- @Test
- public void hideView_viewControllerOnlyShown_noHighestZOrder() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isNull();
- }
-
- @Test
- public void hideView_viewControllerOnlyShown_nothingShown() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.isEmpty()).isTrue();
- }
-
- @Test
- public void hideView_viewControllerOnlyShown_viewControllerNotShown() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsKey(
- OVERLAY_VIEW_CONTROLLER_1_Z_ORDER)).isFalse();
- }
-
- @Test
- public void hideView_newHighestZOrder_twoViewsShown() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setupOverlayViewController2();
- setOverlayViewControllerAsShowing(mOverlayViewController2);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
- mOverlayViewController1);
- }
-
- @Test
- public void hideView_newHighestZOrder_threeViewsShown() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setupOverlayViewController2();
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- setupOverlayPanelViewController();
- setOverlayViewControllerAsShowing(mOverlayPanelViewController);
-
- mOverlayViewGlobalStateController.hideView(mOverlayPanelViewController, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
- mOverlayViewController2);
- }
-
- @Test
- public void hideView_newHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false);
- reset(mWindowInsetsController);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
-
- verify(mWindowInsetsController).hide(navigationBars());
- }
-
- @Test
- public void hideView_newHighestZOrder_shouldShowNavBarTrue_navigationBarShown() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true);
- reset(mWindowInsetsController);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
-
- verify(mWindowInsetsController).show(navigationBars());
- }
-
- @Test
- public void hideView_newHighestZOrder_shouldShowStatusBarFalse_statusBarHidden() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false);
- reset(mWindowInsetsController);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
-
- verify(mWindowInsetsController).hide(statusBars());
- }
-
- @Test
- public void hideView_newHighestZOrder_shouldShowStatusBarTrue_statusBarShown() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true);
- reset(mWindowInsetsController);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
-
- verify(mWindowInsetsController).show(statusBars());
- }
-
- @Test
- public void hideView_newHighestZOrder_fitsNavBarInsets_insetsAdjusted() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setupOverlayViewController2();
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(navigationBars());
- when(mOverlayViewController2.getInsetTypesToFit()).thenReturn(statusBars());
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setFitInsetsTypes(navigationBars());
- }
-
- @Test
- public void hideView_oldHighestZOrder() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setupOverlayViewController2();
- setOverlayViewControllerAsShowing(mOverlayViewController2);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo(
- mOverlayViewController2);
- }
-
- @Test
- public void hideView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(false);
- reset(mWindowInsetsController);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).hide(navigationBars());
- }
-
- @Test
- public void hideView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarShown() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(true);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).show(navigationBars());
- }
-
- @Test
- public void hideView_oldHighestZOrder_shouldShowStatusBarFalse_statusBarHidden() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(false);
- reset(mWindowInsetsController);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).hide(statusBars());
- }
-
- @Test
- public void hideView_oldHighestZOrder_shouldShowStatusBarTrue_statusBarShown() {
- setupOverlayViewController1();
- setupOverlayViewController2();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(true);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).show(statusBars());
- }
-
- @Test
- public void hideView_oldHighestZOrder_fitsNavBarInsets_insetsAdjusted() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setupOverlayViewController2();
- setOverlayViewControllerAsShowing(mOverlayViewController2);
- when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(statusBars());
- when(mOverlayViewController2.getInsetTypesToFit()).thenReturn(navigationBars());
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setFitInsetsTypes(navigationBars());
- }
-
- @Test
- public void hideView_viewControllerNotOnlyShown_windowNotCollapsed() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- setupOverlayViewController2();
- setOverlayViewControllerAsShowing(mOverlayViewController2);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable);
-
- verify(mSystemUIOverlayWindowController, never()).setWindowVisible(false);
- }
-
- @Test
- public void hideView_viewControllerOnlyShown_navigationBarShown() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).show(navigationBars());
- }
-
- @Test
- public void hideView_viewControllerOnlyShown_statusBarShown() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- verify(mWindowInsetsController).show(statusBars());
- }
-
- @Test
- public void hideView_viewControllerOnlyShown_insetsAdjustedToDefault() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setFitInsetsTypes(statusBars());
- }
-
- @Test
- public void hideView_viewControllerOnlyShown_windowCollapsed() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setWindowVisible(false);
- }
-
- @Test
- public void setOccludedTrue_viewToHideWhenOccludedVisible_viewHidden() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
-
- mOverlayViewGlobalStateController.setOccluded(true);
-
- assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
- mOverlayViewController1)).isFalse();
- }
-
- @Test
- public void setOccludedTrue_viewToNotHideWhenOccludedVisible_viewShown() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(true);
-
- mOverlayViewGlobalStateController.setOccluded(true);
-
- assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
- mOverlayViewController1)).isTrue();
- }
-
- @Test
- public void hideViewAndThenSetOccludedTrue_viewHiddenForOcclusion_viewHiddenAfterOcclusion() {
- setupOverlayViewController1();
- setOverlayViewControllerAsShowing(mOverlayViewController1);
- when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
- mOverlayViewGlobalStateController.setOccluded(true);
-
- mOverlayViewGlobalStateController.hideView(mOverlayViewController1, /* runnable= */ null);
- mOverlayViewGlobalStateController.setOccluded(false);
-
- assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
- mOverlayViewController1)).isFalse();
- }
-
- @Test
- public void setOccludedTrueAndThenShowView_viewToNotHideForOcclusion_viewShown() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(true);
-
- mOverlayViewGlobalStateController.setOccluded(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
-
- assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
- mOverlayViewController1)).isTrue();
- }
-
- @Test
- public void setOccludedTrueAndThenShowView_viewToHideForOcclusion_viewHidden() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
-
- mOverlayViewGlobalStateController.setOccluded(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
-
- assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
- mOverlayViewController1)).isFalse();
- }
-
- @Test
- public void setOccludedFalse_viewShownAfterSetOccludedTrue_viewToHideForOcclusion_viewShown() {
- setupOverlayViewController1();
- when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
- mOverlayViewGlobalStateController.setOccluded(true);
- setOverlayViewControllerAsShowing(mOverlayViewController1);
-
- mOverlayViewGlobalStateController.setOccluded(false);
-
- assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
- mOverlayViewController1)).isTrue();
- }
-
- @Test
- public void inflateView_notInflated_inflates() {
- when(mOverlayViewController2.isInflated()).thenReturn(false);
-
- mOverlayViewGlobalStateController.inflateView(mOverlayViewController2);
-
- verify(mOverlayViewController2).inflate(mBaseLayout);
- }
-
- @Test
- public void inflateView_alreadyInflated_doesNotInflate() {
- when(mOverlayViewController2.isInflated()).thenReturn(true);
-
- mOverlayViewGlobalStateController.inflateView(mOverlayViewController2);
-
- verify(mOverlayViewController2, never()).inflate(mBaseLayout);
- }
-
- @Test
- public void showView_setInsetsToFitByType_setsFitInsetsType() {
- int insetTypeToFit = WindowInsets.Type.navigationBars();
- setupOverlayViewController1();
- when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(insetTypeToFit);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setFitInsetsTypes(insetTypeToFit);
- }
-
- @Test
- public void refreshInsetsToFit_setInsetsToFitBySide_setsFitInsetsSides() {
- int insetSidesToFit = WindowInsets.Side.LEFT;
- setupOverlayViewController1();
- when(mOverlayViewController1.getInsetSidesToFit()).thenReturn(insetSidesToFit);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setFitInsetsSides(insetSidesToFit);
- }
-
- @Test
- public void refreshInsetsToFit_setInsetsToFitBySideUsed_firstFitsAllSystemBars() {
- int insetSidesToFit = WindowInsets.Side.LEFT;
- setupOverlayViewController1();
- when(mOverlayViewController1.getInsetSidesToFit()).thenReturn(insetSidesToFit);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setFitInsetsTypes(WindowInsets.Type.systemBars());
- }
-
- @Test
- public void refreshInsetsToFit_bothInsetTypeAndSideDefined_insetSideTakesPrecedence() {
- int insetTypesToFit = WindowInsets.Type.navigationBars();
- int insetSidesToFit = WindowInsets.Side.LEFT;
- setupOverlayViewController1();
- when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(insetTypesToFit);
- when(mOverlayViewController1.getInsetSidesToFit()).thenReturn(insetSidesToFit);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mSystemUIOverlayWindowController).setFitInsetsSides(insetSidesToFit);
- }
-
- @Test
- public void refreshInsetsToFit_bothInsetTypeAndSideDefined_insetTypeIgnored() {
- int insetTypesToFit = WindowInsets.Type.navigationBars();
- int insetSidesToFit = WindowInsets.Side.LEFT;
- setupOverlayViewController1();
- when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(insetTypesToFit);
- when(mOverlayViewController1.getInsetSidesToFit()).thenReturn(insetSidesToFit);
-
- mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
-
- verify(mSystemUIOverlayWindowController, never()).setFitInsetsTypes(insetTypesToFit);
- }
-
- private void setupOverlayViewController1() {
- setupOverlayViewController(mOverlayViewController1, R.id.overlay_view_controller_stub_1,
- R.id.overlay_view_controller_1);
- }
-
- private void setupOverlayViewController2() {
- setupOverlayViewController(mOverlayViewController2, R.id.overlay_view_controller_stub_2,
- R.id.overlay_view_controller_2);
- }
-
- private void setupOverlayPanelViewController() {
- setupOverlayViewController(mOverlayPanelViewController, R.id.overlay_view_controller_stub_3,
- R.id.overlay_view_controller_3);
- }
-
- private void setupOverlayViewController(OverlayViewController overlayViewController,
- int stubId, int inflatedId) {
- ViewStub viewStub = mBaseLayout.findViewById(stubId);
- View layout;
- if (viewStub == null) {
- layout = mBaseLayout.findViewById(inflatedId);
- } else {
- layout = viewStub.inflate();
- }
- when(overlayViewController.getLayout()).thenReturn(layout);
- when(overlayViewController.isInflated()).thenReturn(true);
- when(overlayViewController.getInsetSidesToFit()).thenReturn(
- OverlayViewController.INVALID_INSET_SIDE);
- }
-
- private void setOverlayViewControllerAsShowing(OverlayViewController overlayViewController) {
- mOverlayViewGlobalStateController.showView(overlayViewController, /* show= */ null);
- reset(mSystemUIOverlayWindowController);
- when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/wm/BarControlPolicyTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/wm/BarControlPolicyTest.java
deleted file mode 100644
index da7cb8e4f6ac..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/wm/BarControlPolicyTest.java
+++ /dev/null
@@ -1,195 +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.wm;
-
-import static android.view.WindowInsets.Type.navigationBars;
-import static android.view.WindowInsets.Type.statusBars;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.car.settings.CarSettings;
-import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class BarControlPolicyTest extends SysuiTestCase {
-
- private static final String PACKAGE_NAME = "sample.app";
-
- @Before
- public void setUp() {
- BarControlPolicy.reset();
- }
-
- @After
- public void tearDown() {
- Settings.Global.clearProviderForTest();
- }
-
- @Test
- public void reloadFromSetting_notSet_doesNotSetFilters() {
- BarControlPolicy.reloadFromSetting(mContext);
-
- assertThat(BarControlPolicy.sImmersiveStatusFilter).isNull();
- }
-
- @Test
- public void reloadFromSetting_invalidPolicyControlString_doesNotSetFilters() {
- String text = "sample text";
- Settings.Global.putString(
- mContext.getContentResolver(),
- CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
- text
- );
-
- BarControlPolicy.reloadFromSetting(mContext);
-
- assertThat(BarControlPolicy.sImmersiveStatusFilter).isNull();
- }
-
- @Test
- public void reloadFromSetting_validPolicyControlString_setsFilters() {
- String text = "immersive.status=" + PACKAGE_NAME;
- Settings.Global.putString(
- mContext.getContentResolver(),
- CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
- text
- );
-
- BarControlPolicy.reloadFromSetting(mContext);
-
- assertThat(BarControlPolicy.sImmersiveStatusFilter).isNotNull();
- }
-
- @Test
- public void reloadFromSetting_filtersSet_doesNotSetFiltersAgain() {
- String text = "immersive.status=" + PACKAGE_NAME;
- Settings.Global.putString(
- mContext.getContentResolver(),
- CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
- text
- );
-
- BarControlPolicy.reloadFromSetting(mContext);
-
- assertThat(BarControlPolicy.reloadFromSetting(mContext)).isFalse();
- }
-
- @Test
- public void getBarVisibilities_policyControlNotSet_showsSystemBars() {
- int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME);
-
- assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars());
- assertThat(visibilities[1]).isEqualTo(0);
- }
-
- @Test
- public void getBarVisibilities_immersiveStatusForAppAndMatchingApp_hidesStatusBar() {
- Settings.Global.putString(
- mContext.getContentResolver(),
- CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
- "immersive.status=" + PACKAGE_NAME);
- BarControlPolicy.reloadFromSetting(mContext);
-
- int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME);
-
- assertThat(visibilities[0]).isEqualTo(navigationBars());
- assertThat(visibilities[1]).isEqualTo(statusBars());
- }
-
- @Test
- public void getBarVisibilities_immersiveStatusForAppAndNonMatchingApp_showsSystemBars() {
- Settings.Global.putString(
- mContext.getContentResolver(),
- CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
- "immersive.status=" + PACKAGE_NAME);
- BarControlPolicy.reloadFromSetting(mContext);
-
- int[] visibilities = BarControlPolicy.getBarVisibilities("sample2.app");
-
- assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars());
- assertThat(visibilities[1]).isEqualTo(0);
- }
-
- @Test
- public void getBarVisibilities_immersiveStatusForAppsAndNonApp_showsSystemBars() {
- Settings.Global.putString(
- mContext.getContentResolver(),
- CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
- "immersive.status=apps");
- BarControlPolicy.reloadFromSetting(mContext);
-
- int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME);
-
- assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars());
- assertThat(visibilities[1]).isEqualTo(0);
- }
-
- @Test
- public void getBarVisibilities_immersiveFullForAppAndMatchingApp_hidesSystemBars() {
- Settings.Global.putString(
- mContext.getContentResolver(),
- CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
- "immersive.full=" + PACKAGE_NAME);
- BarControlPolicy.reloadFromSetting(mContext);
-
- int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME);
-
- assertThat(visibilities[0]).isEqualTo(0);
- assertThat(visibilities[1]).isEqualTo(statusBars() | navigationBars());
- }
-
- @Test
- public void getBarVisibilities_immersiveFullForAppAndNonMatchingApp_showsSystemBars() {
- Settings.Global.putString(
- mContext.getContentResolver(),
- CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
- "immersive.full=" + PACKAGE_NAME);
- BarControlPolicy.reloadFromSetting(mContext);
-
- int[] visibilities = BarControlPolicy.getBarVisibilities("sample2.app");
-
- assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars());
- assertThat(visibilities[1]).isEqualTo(0);
- }
-
- @Test
- public void getBarVisibilities_immersiveFullForAppsAndNonApp_showsSystemBars() {
- Settings.Global.putString(
- mContext.getContentResolver(),
- CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
- "immersive.full=apps");
- BarControlPolicy.reloadFromSetting(mContext);
-
- int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME);
-
- assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars());
- assertThat(visibilities[1]).isEqualTo(0);
- }
-}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
deleted file mode 100644
index 391f75e35382..000000000000
--- a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
+++ /dev/null
@@ -1,109 +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.wm;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.verify;
-
-import android.car.settings.CarSettings;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.IWindowManager;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.TransactionPool;
-
-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 DisplaySystemBarsControllerTest extends SysuiTestCase {
-
- private DisplaySystemBarsController mController;
-
- private static final int DISPLAY_ID = 1;
-
- @Mock
- private IWindowManager mIWindowManager;
- @Mock
- private DisplayController mDisplayController;
- @Mock
- private Handler mHandler;
- @Mock
- private TransactionPool mTransactionPool;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mController = new DisplaySystemBarsController(
- mContext,
- mIWindowManager,
- mDisplayController,
- mHandler,
- mTransactionPool
- );
- }
-
- @Test
- public void onDisplayAdded_setsDisplayWindowInsetsControllerOnWMService()
- throws RemoteException {
- mController.onDisplayAdded(DISPLAY_ID);
-
- verify(mIWindowManager).setDisplayWindowInsetsController(
- eq(DISPLAY_ID), any(DisplaySystemBarsController.PerDisplay.class));
- }
-
- @Test
- public void onDisplayAdded_loadsBarControlPolicyFilters() {
- String text = "sample text";
- Settings.Global.putString(
- mContext.getContentResolver(),
- CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE,
- text
- );
-
- mController.onDisplayAdded(DISPLAY_ID);
-
- assertThat(BarControlPolicy.sSettingValue).isEqualTo(text);
- }
-
- @Test
- public void onDisplayRemoved_unsetsDisplayWindowInsetsControllerInWMService()
- throws RemoteException {
- mController.onDisplayAdded(DISPLAY_ID);
-
- mController.onDisplayRemoved(DISPLAY_ID);
-
- verify(mIWindowManager).setDisplayWindowInsetsController(
- DISPLAY_ID, /* displayWindowInsetsController= */ null);
- }
-}
diff --git a/packages/CarrierDefaultApp/res/values-hu/strings.xml b/packages/CarrierDefaultApp/res/values-hu/strings.xml
index a492e47242af..4ae6ea67bb06 100644
--- a/packages/CarrierDefaultApp/res/values-hu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hu/strings.xml
@@ -8,7 +8,7 @@
<string name="portal_notification_detail" msgid="2295729385924660881">"Koppintson a(z) %s webhely meglátogatásához"</string>
<string name="no_data_notification_detail" msgid="3112125343857014825">"Vegye fel a kapcsolatot szolgáltatójával (%s)"</string>
<string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Nincs mobiladat-kapcsolat"</string>
- <string name="no_mobile_data_connection" msgid="544980465184147010">"Adjon hozzá előfizetést vagy roamingcsomagot a következőn keresztül: %s"</string>
+ <string name="no_mobile_data_connection" msgid="544980465184147010">"Adjon hozzá előfizetést vagy barangolási csomagot a következőn keresztül: %s"</string>
<string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Mobiladat-állapot"</string>
<string name="action_bar_label" msgid="4290345990334377177">"Bejelentkezés a mobilhálózatra"</string>
<string name="ssl_error_warning" msgid="3127935140338254180">"Biztonsági problémák vannak azzal a hálózattal, amelyhez csatlakozni szeretne."</string>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index c5876af268a9..a7e397e9563c 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -32,6 +32,7 @@ import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
@@ -84,10 +85,13 @@ public class DeviceDiscoveryService extends Service {
static DeviceDiscoveryService sInstance;
+ private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private WifiManager mWifiManager;
@Nullable private BluetoothLeScanner mBLEScanner;
- private ScanSettings mDefaultScanSettings = new ScanSettings.Builder().build();
+ private ScanSettings mDefaultScanSettings = new ScanSettings.Builder()
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+ .build();
private List<DeviceFilter<?>> mFilters;
private List<BluetoothLeDeviceFilter> mBLEFilters;
@@ -141,7 +145,8 @@ public class DeviceDiscoveryService extends Service {
if (DEBUG) Log.i(LOG_TAG, "onCreate()");
- mBluetoothAdapter = getSystemService(BluetoothManager.class).getAdapter();
+ mBluetoothManager = getSystemService(BluetoothManager.class);
+ mBluetoothAdapter = mBluetoothManager.getAdapter();
mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
mWifiManager = getSystemService(WifiManager.class);
@@ -186,6 +191,14 @@ public class DeviceDiscoveryService extends Service {
for (BluetoothDevice dev : emptyIfNull(mBluetoothAdapter.getBondedDevices())) {
onDeviceFound(DeviceFilterPair.findMatch(dev, mBluetoothFilters));
}
+ for (BluetoothDevice dev : emptyIfNull(
+ mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT))) {
+ onDeviceFound(DeviceFilterPair.findMatch(dev, mBluetoothFilters));
+ }
+ for (BluetoothDevice dev : emptyIfNull(
+ mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER))) {
+ onDeviceFound(DeviceFilterPair.findMatch(dev, mBluetoothFilters));
+ }
}
if (shouldScan(mBluetoothFilters)) {
diff --git a/packages/DynamicSystemInstallationService/res/values-af/strings.xml b/packages/DynamicSystemInstallationService/res/values-af/strings.xml
index 1b300358adb1..231a5ce50c5f 100644
--- a/packages/DynamicSystemInstallationService/res/values-af/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-af/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dinamiese stelsel is gereed. Herbegin jou toestel om dit te begin gebruik."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Installeer tans"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Kon nie installeer nie"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Kon nie prent bekragtig nie. Staak installering."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Kon nie beeldafskrif bekragtig nie. Staak installering."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Laat loop tans \'n dinamiese stelsel. Herbegin om die oorspronklike Android-weergawe te gebruik."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Kanselleer"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Gooi weg"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Herbegin"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Het dinamiese stelsel weggegooi"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Kan nie dinamiese stelsel herbegin of laai nie"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Kon nie dinamiese stelsel deaktiveer nie"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-am/strings.xml b/packages/DynamicSystemInstallationService/res/values-am/strings.xml
index a8a7b00dd03e..d0fc3ccb05e3 100644
--- a/packages/DynamicSystemInstallationService/res/values-am/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-am/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ዳግም ጀምር"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"የተጣለ ተለዋዋጭ ሥርዓት"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ዳግም ማስጀመር አይቻልም ወይም ተለዋዋጭ ሥርዓትን ይስቀሉ"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ተለዋዋጭ ስርዓትን ማሰናከል አልተሳካም"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ar/strings.xml b/packages/DynamicSystemInstallationService/res/values-ar/strings.xml
index 44a6503eec08..279cba11ceea 100644
--- a/packages/DynamicSystemInstallationService/res/values-ar/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ar/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"النظام الديناميكي جاهز. لبدء استخدامه، يجب إعادة تشغيل الجهاز."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"التثبيت قيد التقدّم."</string>
<string name="notification_install_failed" msgid="4066039210317521404">"تعذّر التثبيت."</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"تعذّر التحقّق من الصورة. يجب إلغاء التثبيت."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"تعذّر التحقّق من النسخة. يجب إلغاء التثبيت."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"‏يتم الآن تشغيل نظام ديناميكي. يجب إعادة التشغيل لاستخدام الإصدار الأصلي لنظام Android."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"إلغاء"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"تجاهل"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"إعادة التشغيل"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"تم تجاهل النظام الديناميكي."</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"لا يمكن إعادة التشغيل أو تحميل النظام الديناميكي."</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"تعذّر إيقاف النظام الديناميكي."</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-as/strings.xml b/packages/DynamicSystemInstallationService/res/values-as/strings.xml
index e93ad9bec77c..13c8abc0b56f 100644
--- a/packages/DynamicSystemInstallationService/res/values-as/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-as/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ৰিষ্টাৰ্ট কৰক"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"বাতিল কৰা ডায়নামিক ছিষ্টেম"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ডায়নামিক ছিষ্টেম ৰিষ্টার্ট অথবা ল\'ড কৰিব নোৱাৰি"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ডায়নামিক ছিষ্টেম অক্ষম কৰিব পৰা নগ’ল"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-az/strings.xml b/packages/DynamicSystemInstallationService/res/values-az/strings.xml
index ad3d3e7b1d28..03d7cca60e8e 100644
--- a/packages/DynamicSystemInstallationService/res/values-az/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-az/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dinamik sistem hazırdır. İstifadəyə başlamaq üçün cihazınızı yenidən başladın."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Quraşdırılır"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Quraşdırılmadı"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Şəkil təsdiqlənmədi. Quraşdırmanı dayandırın."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Görüntü doğrulanması alınmadı. Quraşdırmanı dayandırın."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Hazırda dinamik sistem icra olunur. Orijinal Android versiyasından istifadə etmək üçün yenidən başladın."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Ləğv edin"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"İmtina edin"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Yenidən başladın"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamik sistemdən imtina edildi"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dinamik sistemi yenidən başlatmaq və ya yükləmək mümkün deyil"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Dinamik sistemi deaktiv etmək alınmadı"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-b+sr+Latn/strings.xml b/packages/DynamicSystemInstallationService/res/values-b+sr+Latn/strings.xml
index 01070479cd53..0e770da7da09 100644
--- a/packages/DynamicSystemInstallationService/res/values-b+sr+Latn/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-b+sr+Latn/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dinamični sistem je spreman. Da biste počeli da ga koristite, restartujte uređaj."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Instalira se"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Instaliranje nije uspelo"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Validacija slike nije uspela. Otkažite instalaciju."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Validacija slike diska nije uspela. Otkažite instalaciju."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Trenutno je pokrenut dinamični sistem. Restartujte da biste koristili originalnu verziju Android-a."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Otkaži"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Odbaci"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restartuj"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamični sistem je odbačen"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Restartovanje ili učitavanje dinamičnog sistema nije uspelo"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Onemogućavanje dinamičnog sistema nije uspelo"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-be/strings.xml b/packages/DynamicSystemInstallationService/res/values-be/strings.xml
index 5a52f735aee1..2044655a3eea 100644
--- a/packages/DynamicSystemInstallationService/res/values-be/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-be/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Перазапусціць"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Дынамічная сістэма адхілена"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Не ўдалося перазапусціць або загрузіць дынамічную сістэму"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Не ўдалося адключыць дынамічную сістэму"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-bg/strings.xml b/packages/DynamicSystemInstallationService/res/values-bg/strings.xml
index 194bf2dd5a58..f8c4fd9a69e2 100644
--- a/packages/DynamicSystemInstallationService/res/values-bg/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-bg/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Рестартиране"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамичната система е отхвърлена"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Динамичната система не може да се рестартира или зареди"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Деактивирането на динамичната система не бе успешно"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-bn/strings.xml b/packages/DynamicSystemInstallationService/res/values-bn/strings.xml
index 43886b348888..87d015851674 100644
--- a/packages/DynamicSystemInstallationService/res/values-bn/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-bn/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"ডায়নামিক সিস্টেম রেডি হয়ে গেছে। সেটি ব্যবহার করা শুরু করতে আপনার ডিভাইস রিস্টার্ট করুন।"</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"ইনস্টল করা হচ্ছে"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ইনস্টল করা যায়নি"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"ছবি যাচাই করা যায়নি। ইনস্টলেশন বন্ধ করুন।"</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"ইমেজ যাচাই করা যায়নি। ইনস্টলেশন বন্ধ করুন।"</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"বর্তমানে ডায়নামিক সিস্টেম চালানো হচ্ছে। আসল Android ভার্সন ব্যবহার করার জন্য রিস্টার্ট করুন।"</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"বাতিল করুন"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"বাতিল করুন"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"রিস্টার্ট করুন"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ডায়নামিক সিস্টেম বাতিল করা হয়েছে"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ডায়নামিক সিস্টেম রিস্টার্ট বা লোড করা যাচ্ছে না"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ডায়নামিক সিস্টেম বন্ধ করা যায়নি"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-bs/strings.xml b/packages/DynamicSystemInstallationService/res/values-bs/strings.xml
index 342230b25f9d..7798424f5dd8 100644
--- a/packages/DynamicSystemInstallationService/res/values-bs/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-bs/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dinamični sistem je spreman. Da ga počnete koristiti, ponovo pokrenite uređaj."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Instaliranje je u toku"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Instaliranje nije uspjelo"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Potvrda slike sistema nije uspjela. Prekini instalaciju."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Potvrda slike diska nije uspjela. Prekini instalaciju."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Dinamični sistem je sada aktivan. Ponovo pokrenite da koristite originalnu verziju Androida."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Otkaži"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Odbaci"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Ponovo pokreni"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamični sistem je odbačen"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nije moguće ponovo pokrenuti ili učitati dinamični sistem"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Onemogućavanje dinamičnog sistema nije uspjelo"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ca/strings.xml b/packages/DynamicSystemInstallationService/res/values-ca/strings.xml
index e9e4d3573f58..da6bd8af9e36 100644
--- a/packages/DynamicSystemInstallationService/res/values-ca/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ca/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reinicia"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"S\'ha descartat el sistema dinàmic"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"No es pot reiniciar ni carregar el sistema dinàmic"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"No s\'ha pogut desactivar el sistema dinàmic"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-cs/strings.xml b/packages/DynamicSystemInstallationService/res/values-cs/strings.xml
index 6ae71c6c438b..41e0bbe0ca07 100644
--- a/packages/DynamicSystemInstallationService/res/values-cs/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-cs/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dynamický systém je připraven. Chcete-li ho začít používat, restartujte zařízení."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Probíhá instalace"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Instalace se nezdařila"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Obraz se nepodařilo ověřit. Zrušte instalaci."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Obraz disku se nepodařilo ověřit. Zrušte instalaci."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Je spuštěn dynamický systém. Chcete-li použít původní verzi systému Android, restartujte zařízení."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Zrušit"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Zahodit"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restartovat"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Zahodit dynamický systém"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dynamický systém nelze znovu spustit nebo načíst"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Dynamický systém se nepodařilo deaktivovat"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-da/strings.xml b/packages/DynamicSystemInstallationService/res/values-da/strings.xml
index 10b798c2ce29..252ae5adcdd0 100644
--- a/packages/DynamicSystemInstallationService/res/values-da/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-da/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Det dynamiske system er klar. Hvis du vil begynde at bruge det, skal du genstarte din enhed."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Installation i gang"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Installationen mislykkedes"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Billedet kunne ikke valideres. Afbryd installationen."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Systembilledet kunne ikke valideres. Afbryd installationen."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Der køres i øjeblikket et dynamisk system. Genstart for at bruge den oprindelige Android-version."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Annuller"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Afbryd"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Genstart"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Det dynamiske system blev slettet"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Det dynamiske system kan ikke genstartes eller indlæses"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Det dynamiske system kunne ikke deaktiveres"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-de/strings.xml b/packages/DynamicSystemInstallationService/res/values-de/strings.xml
index 82459b2f368d..382fc019fce1 100644
--- a/packages/DynamicSystemInstallationService/res/values-de/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-de/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Neu starten"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynamisches System verworfen"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Neustart und Laden des dynamischen Systems nicht möglich"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Fehler beim Deaktivieren des dynamischen Systems"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-el/strings.xml b/packages/DynamicSystemInstallationService/res/values-el/strings.xml
index ef029063f544..61dfd34fc660 100644
--- a/packages/DynamicSystemInstallationService/res/values-el/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-el/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Επανεκκίνηση"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Οι δυναμικές συστήματος απορρίφθηκαν."</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Δεν είναι δυνατή η επανεκκίνηση ή η φόρτωση δυναμικών συστήματος"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Απέτυχε η απενεργοποίηση των δυναμικών συστήματος"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-en-rAU/strings.xml b/packages/DynamicSystemInstallationService/res/values-en-rAU/strings.xml
index 6f3f88763597..62dba985f715 100644
--- a/packages/DynamicSystemInstallationService/res/values-en-rAU/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-en-rAU/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restart"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Discarded dynamic system"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Can’t restart or load dynamic system"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Failed to disable dynamic system"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-en-rCA/strings.xml b/packages/DynamicSystemInstallationService/res/values-en-rCA/strings.xml
index 6f3f88763597..62dba985f715 100644
--- a/packages/DynamicSystemInstallationService/res/values-en-rCA/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-en-rCA/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restart"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Discarded dynamic system"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Can’t restart or load dynamic system"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Failed to disable dynamic system"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-en-rGB/strings.xml b/packages/DynamicSystemInstallationService/res/values-en-rGB/strings.xml
index 6f3f88763597..62dba985f715 100644
--- a/packages/DynamicSystemInstallationService/res/values-en-rGB/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-en-rGB/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restart"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Discarded dynamic system"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Can’t restart or load dynamic system"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Failed to disable dynamic system"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-en-rIN/strings.xml b/packages/DynamicSystemInstallationService/res/values-en-rIN/strings.xml
index 6f3f88763597..62dba985f715 100644
--- a/packages/DynamicSystemInstallationService/res/values-en-rIN/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-en-rIN/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restart"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Discarded dynamic system"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Can’t restart or load dynamic system"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Failed to disable dynamic system"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-es-rUS/strings.xml b/packages/DynamicSystemInstallationService/res/values-es-rUS/strings.xml
index aeb65be46f27..1d8a48b40867 100644
--- a/packages/DynamicSystemInstallationService/res/values-es-rUS/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-es-rUS/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Se descartó el sistema dinámico"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"No se puede reiniciar o cargar el sistema dinámico"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"No se pudo inhabilitar el sistema dinámico"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-es/strings.xml b/packages/DynamicSystemInstallationService/res/values-es/strings.xml
index 0c3ae5381453..fe47884e3ec6 100644
--- a/packages/DynamicSystemInstallationService/res/values-es/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-es/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Se ha descartado el sistema dinámico"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"No se ha podido reiniciar o cargar el sistema dinámico"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"No se ha podido inhabilitar el sistema dinámico"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-et/strings.xml b/packages/DynamicSystemInstallationService/res/values-et/strings.xml
index ab20a04493ef..058d6b909ec1 100644
--- a/packages/DynamicSystemInstallationService/res/values-et/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-et/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Taaskäivita"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dünaamilisest süsteemist loobuti"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dünaamilist süsteemi ei saa taaskäivitada ega laadida"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Dünaamilise süsteemi keelamine ebaõnnestus"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-eu/strings.xml b/packages/DynamicSystemInstallationService/res/values-eu/strings.xml
index 18637786ebea..6576edd386d6 100644
--- a/packages/DynamicSystemInstallationService/res/values-eu/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-eu/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Berrabiarazi"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Baztertu da sistema dinamikoa"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Ezin da berrabiarazi edo kargatu sistema dinamikoa"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Ezin izan da desgaitu sistema dinamikoa"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-fa/strings.xml b/packages/DynamicSystemInstallationService/res/values-fa/strings.xml
index 5b0b21891a09..9976d56973e9 100644
--- a/packages/DynamicSystemInstallationService/res/values-fa/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-fa/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"سیستم پویا آماده است. برای استفاده از آن، دستگاه را بازراه‌اندازی کنید."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"درحال نصب"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"نصب نشد"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"راستی‌آزمایی تصویر انجام نشد. نصب را لغو کنید."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"اعتبارسنجی نسخه دیسک انجام نشد. نصب را لغو کنید."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"‏درحال‌حاضر سیستم پویا اجرا می‌شود. برای استفاده از نسخه اصلی Android، بازراه‌اندازی کنید."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"لغو کردن"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"صرف‌نظر کردن"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"بازراه‌اندازی"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"از سیستم پویا صرف‌نظر شد"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"نمی‌توان سیستم پویا را بازراه‌اندازی یا بار کرد"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"سیستم پویا غیرفعال نشد"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-fi/strings.xml b/packages/DynamicSystemInstallationService/res/values-fi/strings.xml
index b4315e7a22ef..f32fc3737121 100644
--- a/packages/DynamicSystemInstallationService/res/values-fi/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-fi/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dynaaminen järjestelmä on valmis. Aloita sen käyttö käynnistämällä laite uudelleen."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Asennus käynnissä"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Asennus epäonnistui"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Kuvavahvistus epäonnistui. Keskeytä asennus."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Levykuvan vahvistus epäonnistui. Keskeytä asennus."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Käyttää tällä hetkellä dynaamista järjestelmää. Käynnistä uudelleen käyttääksesi alkuperäistä Android-versiota."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Peruuta"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Hylkää"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Käynn. uudelleen"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynaaminen järjestelmä hylätty"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dynaamista järjestelmää ei voi käynnistää uudelleen tai ladata"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Dynaamisen järjestelmän käytöstäpoisto epäonnistui"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-fr-rCA/strings.xml b/packages/DynamicSystemInstallationService/res/values-fr-rCA/strings.xml
index 973efef68a47..f5e394a0a1ce 100644
--- a/packages/DynamicSystemInstallationService/res/values-fr-rCA/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-fr-rCA/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Le système dynamique est prêt. Pour commencer à l\'utiliser, redémarrez votre appareil."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Installation en cours…"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Échec de l\'installation"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Impossible de valider l\'image. Annulation de l\'installation."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Impossible de valider l\'image. Annulez l\'installation."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Un système dynamique est en cours d\'exécution. Pour utiliser la version originale d\'Android, redémarrez l\'appareil."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Annuler"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Annuler"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Redémarrer"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Système dynamique supprimé"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Impossible de redémarrer ou de charger le système dynamique"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Échec de la désactivation du système dynamique"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-fr/strings.xml b/packages/DynamicSystemInstallationService/res/values-fr/strings.xml
index 5422e8e4ec5b..c4cd92d0b671 100644
--- a/packages/DynamicSystemInstallationService/res/values-fr/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-fr/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Redémarrer"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Système dynamique supprimé"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Impossible de redémarrer ou de charger le système dynamique"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Échec de la désactivation du système dynamique"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-gl/strings.xml b/packages/DynamicSystemInstallationService/res/values-gl/strings.xml
index e24f495a425f..58a80a7f4999 100644
--- a/packages/DynamicSystemInstallationService/res/values-gl/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-gl/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Descartouse o sistema dinámico"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Non se puido reiniciar nin cargar o sistema dinámico"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Produciuse un erro ao desactivar o sistema dinámico"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-gu/strings.xml b/packages/DynamicSystemInstallationService/res/values-gu/strings.xml
index 6c2e67336c21..aa1c3c5b74f8 100644
--- a/packages/DynamicSystemInstallationService/res/values-gu/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-gu/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ફરી શરૂ કરો"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ડાઇનૅમિક સિસ્ટમ કાઢી નાખવામાં આવી"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ડાઇનૅમિક સિસ્ટમને ફરી શરૂ અથવા લોડ કરી શકાતી નથી"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ડાઇનૅમિક સિસ્ટમ બંધ કરવામાં નિષ્ફળ રહ્યાં"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-hi/strings.xml b/packages/DynamicSystemInstallationService/res/values-hi/strings.xml
index 13dc9e8a3984..e2d535f2b7f1 100644
--- a/packages/DynamicSystemInstallationService/res/values-hi/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-hi/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"रीस्टार्ट करें"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"डाइनैमिक सिस्टम खारिज किया गया"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"डाइनैमिक सिस्टम रीस्टार्ट या लोड नहीं हो सका"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"डाइनैमिक सिस्टम को बंद नहीं किया जा सका"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-hr/strings.xml b/packages/DynamicSystemInstallationService/res/values-hr/strings.xml
index 3318d2040196..1df6a81ffd43 100644
--- a/packages/DynamicSystemInstallationService/res/values-hr/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-hr/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dinamični sustav je spreman. Da biste ga počeli upotrebljavati, ponovno pokrenite svoj uređaj."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Instalacija u tijeku"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Instaliranje nije uspjelo"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Provjera slike nije uspjela. Prekini instalaciju."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Provjera slike diska nije uspjela. Prekini instalaciju."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Trenutačno je pokrenut dinamični sustav. Ponovno pokrenite kako biste upotrebljavali izvornu verziju Androida."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Otkaži"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Odbaci"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Pokreni"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Odbačeni dinamični sustav"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nije moguće ponovno pokretanje ili učitavanje dinamičnog sustava"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Onemogućivanje dinamičnog sustava nije uspjelo"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-hu/strings.xml b/packages/DynamicSystemInstallationService/res/values-hu/strings.xml
index 208ab3bdd260..2540ce6175b8 100644
--- a/packages/DynamicSystemInstallationService/res/values-hu/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-hu/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"A dinamikus rendszer készen áll. A használatához indítsa újra az eszközt."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Telepítés…"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Sikertelen telepítés"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"A kép ellenőrzése nem sikerült. A telepítés megszakad."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"A lemezkép ellenőrzése nem sikerült. A telepítés megszakad."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Jelenleg dinamikus rendszert futtat. Az eredeti Android-verzió használatához indítsa újra az eszközt."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Mégse"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Elvetés"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Újraindítás"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Elvetett dinamikus rendszer"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nem lehet újraindítani vagy betölteni a dinamikus rendszert"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Nem sikerült kikapcsolni a dinamikus rendszert"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-hy/strings.xml b/packages/DynamicSystemInstallationService/res/values-hy/strings.xml
index 4dcc72e38121..e85a2917d2b1 100644
--- a/packages/DynamicSystemInstallationService/res/values-hy/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-hy/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Դինամիկ համակարգը պատրաստ է։ Այն օգտագործելու համար վերագործարկեք ձեր սարքը։"</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Տեղադրում"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Չհաջողվեց տեղադրել"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Չհաջողվեց հաստատել պատկերը։ Չեղարկել տեղադրումը։"</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Չհաջողվեց հաստատել սկավառակի պատկերը։ Չեղարկեք տեղադրումը։"</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Աշխատեցվում է դինամիկ համակարգը։ Վերագործարկեք՝ Android-ի նախկին տարբերակին անցնելու համար։"</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Չեղարկել"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Հրաժարվել"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Վերագործարկել"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Դինամիկ համակարգի գործարկումը չեղարկվեց"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Չհաջողվեց վերագործարկել կամ բեռնել դինամիկ համակարգը"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Չհաջողվեց անջատել դինամիկ համակարգը"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-in/strings.xml b/packages/DynamicSystemInstallationService/res/values-in/strings.xml
index 2fa4f113341a..6986005813b6 100644
--- a/packages/DynamicSystemInstallationService/res/values-in/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-in/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Mulai ulang"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynamic System dihapus"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Tidak dapat memulai ulang atau memuat Dynamic System"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Gagal menonaktifkan sistem dinamis"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-is/strings.xml b/packages/DynamicSystemInstallationService/res/values-is/strings.xml
index ef7484c1d6cc..4499c147af9e 100644
--- a/packages/DynamicSystemInstallationService/res/values-is/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-is/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Breytilegt kerfi er tilbúið. Endurræstu tækið til að byrja að nota það."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Uppsetning stendur yfir"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Uppsetning mistókst"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Ekki tókst að staðfesta mynd. Hættu við uppsetninguna."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Ekki tókst að staðfesta diskmynd. Hættu við uppsetninguna."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Tækið keyrir á breytilegu kerfi. Endurræstu til að nota upprunalega Android útgáfu."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Hætta við"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Fleygja"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Endurræsa"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Breytilegu kerfi fleygt"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Ekki tókst að endurræsa eða hlaða breytilegu kerfi"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Ekki tókst að slökkva á breytilegu kerfi"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-it/strings.xml b/packages/DynamicSystemInstallationService/res/values-it/strings.xml
index c8fa41b3c92c..2c91aebd7e37 100644
--- a/packages/DynamicSystemInstallationService/res/values-it/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-it/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Riavvia"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistema dinamico annullato"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Impossibile riavviare o caricare il sistema dinamico"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Impossibile disattivare il sistema dinamico"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-iw/strings.xml b/packages/DynamicSystemInstallationService/res/values-iw/strings.xml
index d9bf983d4d76..2f539e3c19e0 100644
--- a/packages/DynamicSystemInstallationService/res/values-iw/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-iw/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"המערכת הדינמית מוכנה. כדי להתחיל להשתמש בה, יש להפעיל מחדש את המכשיר."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"ההתקנה מתבצעת"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ההתקנה נכשלה"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"אימות התמונה נכשל. יש לבטל את ההתקנה."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"האימות של קובץ האימג\' נכשל. ההתקנה תבוטל."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"‏בשלב זה פועלת מערכת דינמית. כדי להשתמש בגרסת Android המקורית, יש לבצע הפעלה מחדש."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"ביטול"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"סגירה"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"הפעלה מחדש"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"המערכת הדינמית נסגרה"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"לא ניתן להפעיל מחדש או לטעון את המערכת הדינמית"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"השבתת המערכת הדינמית נכשלה"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ja/strings.xml b/packages/DynamicSystemInstallationService/res/values-ja/strings.xml
index 2082d91294da..2d5fc4f19277 100644
--- a/packages/DynamicSystemInstallationService/res/values-ja/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ja/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"再起動"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"動的システムを破棄しました"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"動的システムの再起動や読み込みを行えません"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"動的システムを無効にできませんでした"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ka/strings.xml b/packages/DynamicSystemInstallationService/res/values-ka/strings.xml
index e57de2c1016a..3cc1932ac35f 100644
--- a/packages/DynamicSystemInstallationService/res/values-ka/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ka/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"დინამიური სისტემა მზადაა. გადატვირთეთ მოწყობილობა მის გამოსაყენებლად."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"ინსტალირდება"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ინსტალაცია ვერ მოხერხდა"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"სურათის ვალიდაცია ვერ მოხერხდა. ინსტალაციის შეწყვეტა."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"იმიჯის ვალიდაცია ვერ მოხერხდა. ინსტალაციის შეწყვეტა."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"ამჟამად გამოიყენება დინამიური სისტემა. გადატვირთეთ Android-ის ორიგინალი ვერსიის გამოსაყენებლად."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"გაუქმება"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"გაუქმება"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"გადატვირთვა"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"გაუქმებული დინამიური სისტემა"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"დინამიური სისტემის გადატვირთვა ან ჩატვირთვა ვერ ხერხდება"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"დინამიკური სისტემის გათიშვა ვარ მოხერხდა"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-kk/strings.xml b/packages/DynamicSystemInstallationService/res/values-kk/strings.xml
index da10e9c582c0..9aafc2f47066 100644
--- a/packages/DynamicSystemInstallationService/res/values-kk/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-kk/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Қайта қосу"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамикалық жүйе өшірілді."</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Динамикалық жүйені қайта қосу не жүктеу мүмкін емес."</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Динамикалық жүйе өшірілмеді."</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-km/strings.xml b/packages/DynamicSystemInstallationService/res/values-km/strings.xml
index 7bb5980ca1d4..502ae9384155 100644
--- a/packages/DynamicSystemInstallationService/res/values-km/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-km/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"ប្រព័ន្ធឌីណាមិច​អាចប្រើ​បានហើយ។ ដើម្បីចាប់ផ្ដើមប្រើ​ប្រព័ន្ធឌីណាមិច សូមចាប់ផ្ដើម​ឧបករណ៍របស់អ្នក​ឡើងវិញ។"</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"ការដំឡើងកំពុង​ដំណើរការ"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ការដំឡើង​មិនបានសម្រេច"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"បញ្ជាក់​ភាពត្រឹមត្រូវ​នៃរូបភាព​មិនបានសម្រេច។ បោះបង់​ការដំឡើង។"</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"ការផ្ទៀងផ្ទាត់ច្បាប់ចម្លងថាស​មិនបានសម្រេច។ បោះបង់​ការដំឡើង។"</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"បច្ចុប្បន្ន​កំពុងដំណើរការ​ប្រព័ន្ធឌីណាមិច។ ចាប់ផ្ដើម​ឡើងវិញ ដើម្បីប្រើ​កំណែ Android ដើម។"</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"បោះបង់"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"លុបចោល"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ចាប់ផ្ដើមឡើងវិញ"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"បានលុបចោល​ប្រព័ន្ធឌីណាមិច"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"មិនអាច​ចាប់ផ្ដើមឡើងវិញ ឬផ្ទុក​ប្រព័ន្ធឌីណាមិច​បានទេ"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"មិនអាចបិទ​ប្រព័ន្ធឌីណាមិច​បានទេ"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-kn/strings.xml b/packages/DynamicSystemInstallationService/res/values-kn/strings.xml
index f41f2eff5cde..cd5044d2994e 100644
--- a/packages/DynamicSystemInstallationService/res/values-kn/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-kn/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"ಡೈನಾಮಿಕ್ ಸಿಸ್ಟಂ ಸಿದ್ದವಾಗಿದೆ. ಇದನ್ನು ಬಳಸಲು, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿ."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"ಇನ್‌ಸ್ಟಾಲ್ ಆಗುತ್ತಿದೆ"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"ಚಿತ್ರದ ಮೌಲ್ಯೀಕರಣ ವಿಫಲವಾಗಿದೆ. ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡುವಿಕೆಯನ್ನು ರದ್ದುಗೊಳಿಸಿ."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"ಇಮೇಜ್ ಮೌಲ್ಯೀಕರಣ ವಿಫಲವಾಗಿದೆ. ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡುವಿಕೆಯನ್ನು ರದ್ದುಗೊಳಿಸಿ."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"ಪ್ರಸ್ತುತವಾಗಿ ಡೈನಾಮಿಕ್ ಸಿಸ್ಟಂ ರನ್ ಆಗುತ್ತಿದೆ ಮೂಲ Android ಆವೃತ್ತಿ ಬಳಸಲು, ಮರುಪ್ರಾರಂಭಿಸಿ."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"ರದ್ದುಗೊಳಿಸಿ"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"ತ್ಯಜಿಸಿ"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ಮರುಪ್ರಾರಂಭಿಸಿ"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ಡೈನಮಿಕ್ ಸಿಸ್ಟಂ ಅನ್ನು ತ್ಯಜಿಸಲಾಗಿದೆ"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ಡೈನಾಮಿಕ್ ಸಿಸ್ಟಂ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲು ಅಥವಾ ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ಡೈನಾಮಿಕ್ ಸಿಸ್ಟಂ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ko/strings.xml b/packages/DynamicSystemInstallationService/res/values-ko/strings.xml
index bca9e0725a6e..0db6d0648dc1 100644
--- a/packages/DynamicSystemInstallationService/res/values-ko/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ko/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"다시 시작"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"동적 시스템 삭제됨"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"동적 시스템을 다시 시작하거나 로드할 수 없음"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"동적 시스템을 사용 중지하는 데 실패함"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ky/strings.xml b/packages/DynamicSystemInstallationService/res/values-ky/strings.xml
index d2ad56a44897..320faff4d7f8 100644
--- a/packages/DynamicSystemInstallationService/res/values-ky/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ky/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Динамикалык система даяр. Аны колдонуу үчүн, түзмөктү өчүрүп күйгүзүңүз."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Орнотулууда"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Орнотулбай койду"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Сүрөт текшерилбей калды. Орнотууну токтотуңуз."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Дисктин сүрөтү текшерилбей калды. Орнотууну токтотуңуз."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Учурда динамикалык система колдонулууда. Android\'дин түпнуска версиясын колдонуу үчүн, өчүрүп күйгүзүңүз."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Жок"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Жоюу"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Өчүрүп күйгүзүү"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамикалык система жоюлду"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Динамикалык система өчүрүлүп күйгүзүлбөй же жүктөлбөй жатат"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Динамикалык система өчпөй койду"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-lo/strings.xml b/packages/DynamicSystemInstallationService/res/values-lo/strings.xml
index a732aa414780..0ee3990f8032 100644
--- a/packages/DynamicSystemInstallationService/res/values-lo/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-lo/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"ລະບົບໄດນາມິກພ້ອມແລ້ວ. ກະລຸນາຣີສະຕາດອຸປະກອນຂອງທ່ານເພື່ອເລີ່ມນຳໃຊ້ມັນ."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"ກຳລັງຕິດຕັ້ງຢູ່"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ຕິດຕັ້ງບໍ່ສຳເລັດ"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"ການກວດສອບໄຟລ໌ຮູບບໍ່ສຳເລັດ. ຍົກເລີກການຕິດຕັ້ງ."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"ກວດສອບໄຟລ໌ອິມເມກບໍ່ສຳເລັດ. ຍົກເລີກການຕິດຕັ້ງ."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"ຕອນນີ້ກຳລັງໃຊ້ລະບົບໄດນາມິກ. ກະລຸນາຣີສະຕາດເພື່ອໃຊ້ເວີຊັນ Android ຕົ້ນສະບັບ."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"ຍົກເລີກ"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"ປິດໄວ້"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ຣີສະຕາດ"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ລະບົບໄດນາມິກທີ່ຍົກເລີກແລ້ວ"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ບໍ່ສາມາດຣີສະຕາດ ຫຼື ໂຫຼດລະບົບໄດນາມິກໄດ້"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ປິດການນຳໃຊ້ລະບົບໄດນາມິກບໍ່ສຳເລັດ"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-lt/strings.xml b/packages/DynamicSystemInstallationService/res/values-lt/strings.xml
index b25c62a5f4ff..2352c22688bb 100644
--- a/packages/DynamicSystemInstallationService/res/values-lt/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-lt/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dinaminė sistema paruošta. Jei norite pradėti ją naudoti, paleiskite įrenginį iš naujo."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Diegiama"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Įdiegti nepavyko"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Nepavyko patvirtinti vaizdo. Nutraukti diegimą."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Nepavyko patvirtinti atvaizdžio. Nutraukti diegimą."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Šiuo metu paleista dinaminė sistema. Paleiskite iš naujo, jei norite naudoti pradinę „Android“ versiją."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Atšaukti"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Atmesti"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Pal. iš naujo"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinaminė sistema atmesta"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nepavyko paleisti iš naujo ar įkelti dinaminės sistemos"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Nepavyko išjungti dinaminės sistemos"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-lv/strings.xml b/packages/DynamicSystemInstallationService/res/values-lv/strings.xml
index 4ca6ace3f5b3..4f83563a9f12 100644
--- a/packages/DynamicSystemInstallationService/res/values-lv/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-lv/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Restartēt"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamiskā sistēma tika atmesta"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nevar restartēt vai ielādēt dinamisko sistēmu"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Neizdevās atspējot dinamisko sistēmu."</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-mk/strings.xml b/packages/DynamicSystemInstallationService/res/values-mk/strings.xml
index 52a52a5ca10d..e205b7314107 100644
--- a/packages/DynamicSystemInstallationService/res/values-mk/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-mk/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Динамичниот систем е подготвен. За да започнете со користење, рестартирајте го уредот."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Инсталирањето е во тек"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Неуспешно инсталирање"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Проверката на сликата не успеа. Прекини ја инсталацијата."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Проверката на сликата на дискот не успеа. Прекини ја инсталацијата."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Во моментов се извршува динамичен систем. Рестартирајте за да ја користите оригиналната верзија на Android."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Откажи"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Отфрли"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Рестартирај"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Отфрлен динамичен систем"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Не може да го рестартира или вчита динамичниот систем"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Не успеа да се оневозможи динамичниот систем"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ml/strings.xml b/packages/DynamicSystemInstallationService/res/values-ml/strings.xml
index 25040694bbda..2d4824ab0b60 100644
--- a/packages/DynamicSystemInstallationService/res/values-ml/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ml/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"ഡെെനാമിക് സിസ്റ്റം തയ്യാറാണ്. അത് ഉപയോഗിച്ച് തുടങ്ങാൻ നിങ്ങളുടെ ഉപകരണം റീസ്റ്റാർട്ട് ചെയ്യുക."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"ഇൻസ്‌റ്റാൾ ചെയ്യൽ പുരോഗതിയിലാണ്"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ഇൻസ്‌റ്റാൾ ചെയ്യാനായില്ല"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"ചിത്രത്തിന്റെ മൂല്യനിർണ്ണയം നടത്താനായില്ല. ഇൻസ്‌റ്റലേഷൻ റദ്ദാക്കുക."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"ഇമേജ് മൂല്യനിർണ്ണയം നടത്താനായില്ല. ഇൻസ്‌റ്റലേഷൻ റദ്ദാക്കുക."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"നിലവിൽ ഒരു ഡെെനാമിക് സിസ്റ്റം റൺ ചെയ്യുന്നുണ്ട്. ഒറിജിനൽ Android പതിപ്പ് ഉപയോഗിക്കാൻ റീസ്റ്റാർട്ട് ചെയ്യുക."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"റദ്ദാക്കുക"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"നിരസിക്കുക"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"റീസ്റ്റാർട്ട് ചെയ്യൂ"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ഡെെനാമിക് സിസ്റ്റം നിരസിച്ചു"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"റീസ്റ്റാർട്ട് ചെയ്യാനോ ഡെെനാമിക് സിസ്റ്റം ലോഡ് ചെയ്യാനോ ആവില്ല"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ഡൈനാമിക് സിസ്‌റ്റം പ്രവർത്തനരഹിതമാക്കാനായില്ല"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-mn/strings.xml b/packages/DynamicSystemInstallationService/res/values-mn/strings.xml
index fe93f65939b3..367cc6214696 100644
--- a/packages/DynamicSystemInstallationService/res/values-mn/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-mn/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Дахин эхлүүлэх"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамик системийг устгасан"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Динамик системийг дахин эхлүүлэх эсвэл ачаалах боломжгүй байна"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Динамик системийг идэвхгүй болгож чадсангүй"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-mr/strings.xml b/packages/DynamicSystemInstallationService/res/values-mr/strings.xml
index 5f27af01f635..3b6741d6c5a8 100644
--- a/packages/DynamicSystemInstallationService/res/values-mr/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-mr/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"डायनॅमिक सिस्टम तयार आहे. ती वापरणे सुरू करण्यासाठी, तुमचे डिव्हाइस रीस्टार्ट करा."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"इंस्टॉल प्रगतीपथावर आहे"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"इंस्टॉल करता आली नाही"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"इमेज प्रमाणीकरण करता आले नाही. इंस्टॉलेशन रद्द करा."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"इमेज प्रमाणित करता आली नाही. इंस्टॉलेशन रद्द करा."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"सध्या डायनॅमिक सिस्टम रन करत आहे. मूळ Android आवृत्ती वापरण्यासाठी रीस्टार्ट करा."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"रद्द करा"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"काढून टाका"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"रीस्टार्ट करा"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"डायनॅमिक सिस्टम काढून टाकली"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"डायनॅमिक सिस्टम रीस्टार्ट किंवा लोड करू शकत नाही"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"डायनॅमिक सिस्टम बंद करता आली नाही"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ms/strings.xml b/packages/DynamicSystemInstallationService/res/values-ms/strings.xml
index 797152c937ed..17b2c707ad86 100644
--- a/packages/DynamicSystemInstallationService/res/values-ms/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ms/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Mulakan semula"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistem dinamik dibuang"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Tidak dapat memulakan semula atau memuatkan sistem dinamik"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Gagal melumpuhkan sistem dinamik"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-my/strings.xml b/packages/DynamicSystemInstallationService/res/values-my/strings.xml
index 3ee85b2136ee..809f4dc45766 100644
--- a/packages/DynamicSystemInstallationService/res/values-my/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-my/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"ပြောင်းလဲနိုင်သောစနစ် အသင့်ဖြစ်ပါပြီ။ ၎င်းကို စတင်အသုံးပြုရန် သင့်စက်ကို ပြန်စပါ။"</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"ထည့်သွင်းနေဆဲဖြစ်သည်"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ထည့်သွင်း၍မရပါ"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"ပုံအတည်ပြု၍ မရပါ။ ထည့်သွင်းမှုကို ရပ်ပါ။"</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"ဒစ်ခ် မိတ္တူကို အတည်ပြု၍ မရပါ။ ထည့်သွင်းမှုကို ရပ်ပါ။"</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"လက်ရှိတွင် ပြောင်းလဲနိုင်သောစနစ်ကို အသုံးပြုနေသည်။ မူလ Android ဗားရှင်း အသုံးပြုရန် ပြန်စတင်ပါ။"</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"မလုပ်တော့"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"ဖယ်ပစ်ရန်"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ပြန်စရန်"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ပြောင်းလဲနိုင်သောစနစ်ကို ဖယ်လိုက်သည်"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ပြန်စ၍ မရပါ (သို့) ပြောင်းလဲနိုင်သောစနစ် ဖွင့်၍မရပါ"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ပြောင်းလဲနိုင်သောစနစ်ကို ပိတ်၍မရပါ"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-nb/strings.xml b/packages/DynamicSystemInstallationService/res/values-nb/strings.xml
index 88087e542b0c..2f8fce86a44d 100644
--- a/packages/DynamicSystemInstallationService/res/values-nb/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-nb/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Det dynamiske systemet er klart. Start enheten din på nytt for å begynne å bruke det."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Installeringen pågår"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Installeringen mislyktes"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Bildebekreftelsen mislyktes. Avbryt installeringen."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Kunne ikke validere diskbildet. Avbryt installeringen."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Kjører et dynamisk system nå. Start på nytt for å bruke den opprinnelige Android-versjonen."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Avbryt"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Forkast"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Start på nytt"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Det dynamiske systemet er forkastet"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Det dynamiske systemet kan ikke startes på nytt eller lastes inn"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Kunne ikke slå av det dynamiske systemet"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ne/strings.xml b/packages/DynamicSystemInstallationService/res/values-ne/strings.xml
index da98fee056e5..7afbfd9a7264 100644
--- a/packages/DynamicSystemInstallationService/res/values-ne/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ne/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dynamic System तयार छ। यसको प्रयोग सुरु गर्न आफ्नो यन्त्र रिस्टार्ट गर्नुहोस्।"</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"इन्स्टल हुँदै छ"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"स्थापना गर्न सकिएन"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"छवि पुष्टि गर्न सकिएन। स्थापना गर्ने प्रक्रिया रद्द गर्नुहोस्।"</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"डिस्कको इमेज पुष्टि गर्न सकिएन। स्थापना गर्ने प्रक्रिया रद्द गर्नुहोस्।"</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"हाल Dynamic System चलिरहेको छ। Android को मूल संस्करण प्रयोग गर्न यन्त्र रिस्टार्ट गर्नुहोस्।"</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"रद्द गर्नुहोस्"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"खारेज गर्नुहोस्"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"रिस्टार्ट गर्नु…"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynamic System खारेज गरियो"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"रिस्टार्ट गर्न वा Dynamic System लोड गर्न सकिएन"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"गतिशील प्रणाली अफ गर्न सकिएन"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-nl/strings.xml b/packages/DynamicSystemInstallationService/res/values-nl/strings.xml
index 5120c90eadc6..3bf7247f3e47 100644
--- a/packages/DynamicSystemInstallationService/res/values-nl/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-nl/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dynamisch systeem is klaar. Start je apparaat opnieuw op om het te gebruiken."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Installatie wordt uitgevoerd"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Installatie mislukt"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Valideren van afbeelding mislukt. Installatie afbreken."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Valideren van image mislukt. Installatie afbreken."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Er is momenteel een dynamisch systeem actief. Start je apparaat opnieuw op om de oorspronkelijke Android-versie te gebruiken."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Annuleren"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Niet opslaan"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Herstarten"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynamisch systeem niet opgeslagen"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Kan dynamisch systeem niet opnieuw opstarten of laden"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Kan dynamisch systeem niet uitschakelen"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-or/strings.xml b/packages/DynamicSystemInstallationService/res/values-or/strings.xml
index 878947e48579..05b9016d45b0 100644
--- a/packages/DynamicSystemInstallationService/res/values-or/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-or/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"ଡାଇନାମିକ୍ ସିଷ୍ଟମ୍ ପ୍ରସ୍ତୁତ ଅଛି। ଏହାକୁ ବ୍ୟବହାର କରିବା ଆରମ୍ଭ କରିବାକୁ, ଆପଣଙ୍କ ଡିଭାଇସକୁ ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ।"</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"ଇନଷ୍ଟଲ୍ ହେଉଛି"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ଇନଷ୍ଟଲ୍ କରିବା ବିଫଳ ହୋଇଛି"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"ଛବି ବୈଧକରଣ ବିଫଳ ହୋଇଛି। ଇନଷ୍ଟଲେସନ୍ ରଦ୍ଦ କରନ୍ତୁ।"</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"ଇମେଜ୍ ବୈଧକରଣ ବିଫଳ ହୋଇଛି। ଇନଷ୍ଟଲେସନ୍ ରଦ୍ଦ କରନ୍ତୁ।"</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"ବର୍ତ୍ତମାନ ଏକ ଡାଇନାମିକ୍ ସିଷ୍ଟମ୍ ଚାଲୁଛି। ମୂଳ Android ସଂସ୍କରଣ ବ୍ୟବହାର କରିବାକୁ ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ।"</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"ଖାରଜ କରନ୍ତୁ"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ଡାଇନାମିକ୍ ସିଷ୍ଟମ୍ ଖାରଜ କରାଯାଇଛି"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ଡାଇନାମିକ୍ ସିଷ୍ଟମ୍ ରିଷ୍ଟାର୍ଟ କିମ୍ବା ଲୋଡ୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ଡାଇନାମିକ୍ ସିଷ୍ଟମ୍ ଅକ୍ଷମ କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-pa/strings.xml b/packages/DynamicSystemInstallationService/res/values-pa/strings.xml
index 2695aaf39b25..8f2fd1801a4b 100644
--- a/packages/DynamicSystemInstallationService/res/values-pa/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-pa/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"ਪਰਿਵਰਤਨਸ਼ੀਲ ਸਿਸਟਮ ਤਿਆਰ ਹੈ। ਇਸ ਦੀ ਵਰਤੋਂ ਸ਼ੁਰੂ ਕਰਨ ਲਈ, ਆਪਣਾ ਡੀਵਾਈਸ ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ।"</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"ਸਥਾਪਨਾ ਜਾਰੀ ਹੈ"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ਸਥਾਪਤ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"ਚਿੱਤਰ ਪ੍ਰਮਾਣਿਕਤਾ ਅਸਫਲ ਰਹੀ। ਸਥਾਪਨਾ ਨੂੰ ਰੱਦ ਕਰੋ।"</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"ਇਮੇਜ ਪ੍ਰਮਾਣਿਕਤਾ ਅਸਫਲ ਰਹੀ। ਸਥਾਪਨਾ ਨੂੰ ਰੱਦ ਕਰੋ।"</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"ਫ਼ਿਲਹਾਲ ਪਰਿਵਰਤਨਸ਼ੀਲ ਸਿਸਟਮ ਚੱਲ ਰਿਹਾ ਹੈ। ਮੂਲ Android ਵਰਜਨ ਵਰਤਣ ਲਈ ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ।"</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"ਰੱਦ ਕਰੋ"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"ਖਾਰਜ ਕਰੋ"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ਪਰਿਵਰਤਨਸ਼ੀਲ ਸਿਸਟਮ ਰੱਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ਪਰਿਵਰਤਨਸ਼ੀਲ ਸਿਸਟਮ ਮੁੜ-ਸ਼ੁਰੂ ਜਾਂ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ਪਰਿਵਰਤਨਸ਼ੀਲ ਸਿਸਟਮ ਨੂੰ ਬੰਦ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-pl/strings.xml b/packages/DynamicSystemInstallationService/res/values-pl/strings.xml
index 33592c86a090..9aa45586ef17 100644
--- a/packages/DynamicSystemInstallationService/res/values-pl/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-pl/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Uruchom ponownie"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Usunięto system dynamiczny"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nie można ponownie uruchomić lub wczytać systemu dynamicznego"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Nie udało się wyłączyć systemu dynamicznego"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml b/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml
index 43bd02135672..6513a9e1d794 100644
--- a/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-pt-rBR/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"O sistema dinâmico está pronto. Para começar a usá-lo, reinicie o dispositivo."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Instalação em andamento"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Falha na instalação"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Falha ao validar imagem. Cancele a instalação."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Falha ao validar imagem do disco. Cancele a instalação."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Um sistema dinâmico está sendo executado no momento. Reinicie para usar a versão original do Android."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Cancelar"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Descartar"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistema dinâmico descartado"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Não é possível reiniciar ou carregar o sistema dinâmico"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Falha ao desativar o sistema dinâmico"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-pt-rPT/strings.xml b/packages/DynamicSystemInstallationService/res/values-pt-rPT/strings.xml
index dc29a659d24c..4b1a92c027f6 100644
--- a/packages/DynamicSystemInstallationService/res/values-pt-rPT/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-pt-rPT/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"O sistema dinâmico está pronto. Para o começar a utilizar, reinicie o dispositivo."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Instalação em curso"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Falha na instalação"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Falha ao validar a imagem. A instalação foi interrompida."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Falha ao validar a imagem. Interrompa a instalação."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Está atualmente em execução um sistema dinâmico. Reinicie para utilizar a versão original do Android."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Cancelar"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Rejeitar"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistema dinâmico rejeitado"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Não é possível reiniciar ou carregar o sistema dinâmico."</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Falha ao desativar o sistema dinâmico"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-pt/strings.xml b/packages/DynamicSystemInstallationService/res/values-pt/strings.xml
index 43bd02135672..6513a9e1d794 100644
--- a/packages/DynamicSystemInstallationService/res/values-pt/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-pt/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"O sistema dinâmico está pronto. Para começar a usá-lo, reinicie o dispositivo."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Instalação em andamento"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Falha na instalação"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Falha ao validar imagem. Cancele a instalação."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Falha ao validar imagem do disco. Cancele a instalação."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Um sistema dinâmico está sendo executado no momento. Reinicie para usar a versão original do Android."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Cancelar"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Descartar"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reiniciar"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistema dinâmico descartado"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Não é possível reiniciar ou carregar o sistema dinâmico"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Falha ao desativar o sistema dinâmico"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ro/strings.xml b/packages/DynamicSystemInstallationService/res/values-ro/strings.xml
index c9d391a7fb88..27b88db6eef4 100644
--- a/packages/DynamicSystemInstallationService/res/values-ro/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ro/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reporniți"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"S-a renunțat la sistemul dinamic"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nu se poate reporni sau încărca sistemul dinamic"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Sistemul dinamic nu a fost dezactivat"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ru/strings.xml b/packages/DynamicSystemInstallationService/res/values-ru/strings.xml
index cba9a713f8fa..b36b4f94b132 100644
--- a/packages/DynamicSystemInstallationService/res/values-ru/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ru/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Перезапустить"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамическая система удалена."</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Не удается запустить или загрузить динамическую систему."</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Не удалось отключить динамическую систему."</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-si/strings.xml b/packages/DynamicSystemInstallationService/res/values-si/strings.xml
index 7aab6e9b0ada..ab0b977fcd12 100644
--- a/packages/DynamicSystemInstallationService/res/values-si/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-si/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"ගතික පද්ධතිය සූදානම්ය. එය භාවිතා කිරීම ආරම්භ කිරීමට, ඔබගේ උපාංගය නැවත ආරම්භ කරන්න."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"ස්ථාපනය කෙරෙමින් පවතී"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ස්ථාපනය අසාර්ථක විය"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"රූප වලංගු කිරීම අසාර්ථක විය. ස්ථාපනය අවලංගු කරන්න"</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"තැටි රූපය වලංගු කිරීම අසාර්ථක විය. ස්ථාපනය අවලංගු කරන්න"</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"දැනට ගතික පද්ධතියක් ක්‍රියාත්මක කරයි. මුල් Android අනුවාදය භාවිතා කිරීමට නැවත ආරම්භ කරන්න."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"අවලංගු කරන්න"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"ඉවත ලන්න"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"යළි අරඹන්න"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ගතික පද්ධතිය ඉවත දමන ලදි"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ගතික පද්ධතිය නැවත ආරම්භ කිරීමට හෝ පූරණය කිරීමට නොහැක"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ගතික පද්ධතිය අබල කිරීමට අසමත් විය"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-sk/strings.xml b/packages/DynamicSystemInstallationService/res/values-sk/strings.xml
index 61c176fb8905..01d6a73dfcf6 100644
--- a/packages/DynamicSystemInstallationService/res/values-sk/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-sk/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dynamický systém je k dispozícii. Ak ho chcete začať používať, reštartujte zariadenie."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Prebieha inštalácia"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Nepodarilo sa nainštalovať"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Obrázok sa nepodarilo overiť. Prerušte inštaláciu."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Obraz disku sa nepodarilo overiť. Prerušte inštaláciu."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Momentálne je spustený dynamický systém. Ak chcete používať pôvodnú verziu Androidu, reštartujte."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Zrušiť"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Zahodiť"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Reštartovať"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Zahodený dynamický systém"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Nie je možné reštartovať alebo načítať dynamický systém"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Dynamický systém sa nepodarilo deaktivovať"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-sl/strings.xml b/packages/DynamicSystemInstallationService/res/values-sl/strings.xml
index 0be1248bcff1..1827a9d0f636 100644
--- a/packages/DynamicSystemInstallationService/res/values-sl/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-sl/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Znova zaženi"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamični sistem je bil zavržen"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dinamičnega sistema ni mogoče znova zagnati ali naložiti"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Dinamičnega sistema ni bilo mogoče onemogočiti"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-sq/strings.xml b/packages/DynamicSystemInstallationService/res/values-sq/strings.xml
index 43a5f7bbc876..581a9e157461 100644
--- a/packages/DynamicSystemInstallationService/res/values-sq/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-sq/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Rinis"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Sistemi dinamik u hoq"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Sistemi dinamik nuk mund të rinisej ose të ngarkohej"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Çaktivizimi i sistemit dinamik dështoi"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-sr/strings.xml b/packages/DynamicSystemInstallationService/res/values-sr/strings.xml
index a5ba6565d1ea..e0c6b2f38133 100644
--- a/packages/DynamicSystemInstallationService/res/values-sr/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-sr/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Динамични систем је спреман. Да бисте почели да га користите, рестартујте уређај."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Инсталира се"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Инсталирање није успело"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Валидација слике није успела. Откажите инсталацију."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Валидација слике диска није успела. Откажите инсталацију."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Тренутно је покренут динамични систем. Рестартујте да бисте користили оригиналну верзију Android-а."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Откажи"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Одбаци"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Рестартуј"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамични систем је одбачен"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Рестартовање или учитавање динамичног система није успело"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Онемогућавање динамичног система није успело"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-sv/strings.xml b/packages/DynamicSystemInstallationService/res/values-sv/strings.xml
index 99e6752c0bed..3da2b1825722 100644
--- a/packages/DynamicSystemInstallationService/res/values-sv/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-sv/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Det dynamiska systemet är klart. Om du vill använda det startar du om enheten."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Installation pågår"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Installationen misslyckades"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Bildvalideringen misslyckades. Avbryt installationen."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Valideringen av diskavbildningen misslyckades. Avbryt installationen."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Ett dynamiskt system körs. Om du vill använda den ursprungliga Android-versionen startar du om."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Avbryt"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Ignorera"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Starta om"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Det dynamiska systemet ignorerades"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Det gick inte att starta om eller läsa in det dynamiska systemet"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Det gick inte att inaktivera det dynamiska systemet"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-sw/strings.xml b/packages/DynamicSystemInstallationService/res/values-sw/strings.xml
index 8af9ad35a763..2f18edb6b6ce 100644
--- a/packages/DynamicSystemInstallationService/res/values-sw/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-sw/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dynamic system iko tayari. Ili uanze kuitumia, zima kisha uwashe kifaa chako."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Inasakinisha"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Imeshindwa kusakinisha"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Imeshindwa kuthibitisha picha. Ghairi usakinishaji."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Imeshindwa kuthibitisha nakala. Ghairi usakinishaji."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Inatumia Dynamic System kwa sasa. Zima kisha uwashe ili utumie toleo halisi la Android."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Ghairi"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Ondoa"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Zima kisha uwashe"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Umeondoa Dynamic System"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Imeshindwa kuzima na kuwasha au kupakia Dynamic System"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Imeshindwa kuzima Dynamic System"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ta/strings.xml b/packages/DynamicSystemInstallationService/res/values-ta/strings.xml
index bbe8c4e5e03e..6726a4ad57bb 100644
--- a/packages/DynamicSystemInstallationService/res/values-ta/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ta/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dynamic system தயாராக உள்ளது. இதைப் பயன்படுத்தத் தொடங்க உங்கள் சாதனத்தை மீண்டும் தொடங்கவும்."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"நிறுவப்படுகிறது"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"நிறுவ முடியவில்லை"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"படத்தைச் சரிபார்க்க முடியவில்லை. நிறுவலை ரத்துசெய்யவும்."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"டிஸ்க் இமேஜைச் சரிபார்க்க முடியவில்லை. நிறுவலை ரத்துசெய்யவும்."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Dynamic system தற்போது இயக்கத்தில் உள்ளது. அசல் Android பதிப்பைப் பயன்படுத்த மீண்டும் தொடங்கவும்."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"ரத்துசெய்"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"நிராகரி"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"மீண்டும் தொடங்கு"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dynamic system நிராகரிக்கப்பட்டது"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dynamic systemமை மீண்டும் தொடங்கவோ ஏற்றவோ முடியவில்லை"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Dynamic systemமை முடக்க இயலவில்லை"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-te/strings.xml b/packages/DynamicSystemInstallationService/res/values-te/strings.xml
index 4a9433e7116e..f014467c6b45 100644
--- a/packages/DynamicSystemInstallationService/res/values-te/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-te/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"రీస్టార్ట్ చేయి"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"డైనమిక్ సిస్టమ్ విస్మరించబడింది"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"డైనమిక్ సిస్టమ్‌ను రీస్టార్ట్ చేయడం లేదా లోడ్ చేయడం సాధ్యపడలేదు"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"డైనమిక్ సిస్టమ్‌ను డిజేబుల్ చేయడంలో విఫలమైంది"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-th/strings.xml b/packages/DynamicSystemInstallationService/res/values-th/strings.xml
index 5b81a03c51e3..24a55a96b9ce 100644
--- a/packages/DynamicSystemInstallationService/res/values-th/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-th/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"ระบบแบบไดนามิกพร้อมแล้ว โปรดรีสตาร์ทอุปกรณ์เพื่อเริ่มใช้"</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"กำลังติดตั้ง"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"ติดตั้งไม่สำเร็จ"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"ตรวจสอบรูปภาพไม่สำเร็จ ล้มเลิกการติดตั้ง"</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"ตรวจสอบอิมเมจดิสก์ไม่สำเร็จ ล้มเลิกการติดตั้ง"</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"ปัจจุบันใช้ระบบแบบไดนามิกอยู่ รีสตาร์ทเพื่อใช้ Android เวอร์ชันดั้งเดิม"</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"ยกเลิก"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"ยกเลิก"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"รีสตาร์ท"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"ยกเลิกระบบแบบไดนามิกแล้ว"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"รีสตาร์ทหรือโหลดระบบแบบไดนามิกไม่ได้"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ปิดใช้ระบบไดนามิกไม่สำเร็จ"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-tl/strings.xml b/packages/DynamicSystemInstallationService/res/values-tl/strings.xml
index d6c2f1508f75..0ec7434092a1 100644
--- a/packages/DynamicSystemInstallationService/res/values-tl/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-tl/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"I-restart"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Na-discard ang dynamic system"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Hindi ma-restart o ma-load ang dynamic system"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Hindi na-disable ang dynamic na system"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-tr/strings.xml b/packages/DynamicSystemInstallationService/res/values-tr/strings.xml
index a98526e0cdbe..c2f3dfaa1bfb 100644
--- a/packages/DynamicSystemInstallationService/res/values-tr/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-tr/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dinamik sistem hazır. Kullanmaya başlamak için cihazınızı yeniden başlatın."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Yükleme devam ediyor"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Yükleme başarısız oldu"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Resim doğrulanamadı. Yüklemeyi iptal edin."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Görüntü doğrulanamadı. Yüklemeyi iptal edin."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Şu anda dinamik sistem çalıştırılıyor. Orijinal Android sürümünü kullanmak için cihazı yeniden başlatın."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"İptal"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Sil"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Yeniden başlat"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamik sistem silindi"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dinamik sistem yeniden başlatılamıyor veya yüklenemiyor"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Dinamik sistem devre dışı bırakılamadı"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-uk/strings.xml b/packages/DynamicSystemInstallationService/res/values-uk/strings.xml
index 65267872b724..2712fb265b05 100644
--- a/packages/DynamicSystemInstallationService/res/values-uk/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-uk/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Перезапустити"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Динамічну систему видалено"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Не вдається перезапустити пристрій або завантажити динамічну систему"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Не вдалося вимкнути динамічну систему"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-ur/strings.xml b/packages/DynamicSystemInstallationService/res/values-ur/strings.xml
index f5e2b744e5b2..2f96e8100d9d 100644
--- a/packages/DynamicSystemInstallationService/res/values-ur/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ur/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"ری سٹارٹ کریں"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"مسترد کردہ ڈائنیمک سسٹم"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"ڈائنیمک سسٹم کو ری سٹارٹ یا لوڈ نہیں کر سکتے"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"ڈائنیمک سسٹم کو غیر فعال کرنے میں ناکام"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-uz/strings.xml b/packages/DynamicSystemInstallationService/res/values-uz/strings.xml
index 3c347e2e87ba..5597fb5e0e51 100644
--- a/packages/DynamicSystemInstallationService/res/values-uz/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-uz/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Dinamik tizim tayyor. Foydalanishni boshlash uchun qurilmani qayta ishga tushiring."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Oʻrnatilmoqda"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Oʻrnatilmadi"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Rasm tekshiruvi amalga oshmadi Oʻrnatishni bekor qilish."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Disk tasviri tekshiruvi amalga oshmadi. Oʻrnatishni bekor qiling."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Hozirda dinamik tizim ishga tushirilgan. Asl Android versiyasidan foydlanish uchun qayta ishga tushiring."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Bekor qilish"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Bekor qilish"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Boshidan"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Dinamik tizim bekor qilindi"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Dinamik tizim qayta ishga tushmadi yoki yuklanmadi"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Dinamik tizim faolsizlantirilmadi"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-vi/strings.xml b/packages/DynamicSystemInstallationService/res/values-vi/strings.xml
index a93d29e383ca..83881aa3c003 100644
--- a/packages/DynamicSystemInstallationService/res/values-vi/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-vi/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Hệ thống động đã sẵn sàng. Để bắt đầu sử dụng hệ thống này, hãy khởi động lại thiết bị của bạn."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Đang cài đặt"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Không cài đặt được"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Không xác thực được hình ảnh. Hủy cài đặt."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Không xác thực được ảnh ổ đĩa. Hủy cài đặt."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Thiết bị đang chạy một hệ thống động. Hãy khởi động lại để sử dụng Android phiên bản gốc."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Hủy"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Hủy"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Khởi động lại"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Đã hủy hệ thống động"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Không thể khởi động lại hoặc tải hệ thống động"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Không vô hiệu hóa được hệ thống động"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-zh-rCN/strings.xml b/packages/DynamicSystemInstallationService/res/values-zh-rCN/strings.xml
index c27718ea8c76..9a64aa1c0b3c 100644
--- a/packages/DynamicSystemInstallationService/res/values-zh-rCN/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-zh-rCN/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"动态系统已准备就绪。重启您的设备即可开始使用动态系统。"</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"正在安装"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"安装失败"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"图片验证失败。安装将中止。"</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"映像验证失败。安装将中止。"</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"目前正在运行动态系统。需重启才能使用原 Android 版本。"</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"取消"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"舍弃"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"重启"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"已舍弃动态系统"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"无法重启或加载动态系统"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"无法停用动态系统"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-zh-rHK/strings.xml b/packages/DynamicSystemInstallationService/res/values-zh-rHK/strings.xml
index 656c2af188c4..f477c23fd5a8 100644
--- a/packages/DynamicSystemInstallationService/res/values-zh-rHK/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-zh-rHK/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"重新啟動"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"已捨棄動態系統"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"無法重新啟動或載入動態系統"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"無法停用動態系統"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-zh-rTW/strings.xml b/packages/DynamicSystemInstallationService/res/values-zh-rTW/strings.xml
index a6f9b56e438c..96fb5e7cb5f5 100644
--- a/packages/DynamicSystemInstallationService/res/values-zh-rTW/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-zh-rTW/strings.xml
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"重新啟動"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"已捨棄動態系統"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"無法重新啟動或載入動態系統"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"無法停用動態系統"</string>
</resources>
diff --git a/packages/DynamicSystemInstallationService/res/values-zu/strings.xml b/packages/DynamicSystemInstallationService/res/values-zu/strings.xml
index 0cf79ba51b45..6ef965f01f5f 100644
--- a/packages/DynamicSystemInstallationService/res/values-zu/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-zu/strings.xml
@@ -5,7 +5,7 @@
<string name="notification_install_completed" msgid="6252047868415172643">"Uhlole Okunhlobonhlobo kulungile. Ukuze uqale ukuyisebenzisa, qalisa kabusha idivayisi yakho."</string>
<string name="notification_install_inprogress" msgid="7383334330065065017">"Ukufaka kuyaqhubeka"</string>
<string name="notification_install_failed" msgid="4066039210317521404">"Ukufaka kwehlulekile"</string>
- <string name="notification_image_validation_failed" msgid="2720357826403917016">"Ukuqinisekiswa kwesithombe kuhlulekile. Yekisa ukufakwa."</string>
+ <string name="notification_image_validation_failed" msgid="2720357826403917016">"Ukuqinisekiswa kwe-disk image kuhlulekile. Yekisa ukufakwa."</string>
<string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Manje iqalisa uhlole olunhlobonhlobo. Qalisa kabusha ukuze usebenzise inguqulo yangempela ye-Android."</string>
<string name="notification_action_cancel" msgid="5929299408545961077">"Khansela"</string>
<string name="notification_action_discard" msgid="1817481003134947493">"Lahla"</string>
@@ -13,6 +13,5 @@
<string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Qala kabusha"</string>
<string name="toast_dynsystem_discarded" msgid="1733249860276017050">"Kulahlwe uhlole olunhlobonhlobo"</string>
<string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"Ayikwazi ukuqalisa kabusha noma ukulayisha uhlole olunhlobonhlobo"</string>
- <!-- no translation found for toast_failed_to_disable_dynsystem (3285742944977744413) -->
- <skip />
+ <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"Yehlulekile ukukhubaza isistimu eguqukayo"</string>
</resources>
diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
index 61349d9bb8e8..f9f1607dfc95 100644
--- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
+++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
@@ -26,6 +26,7 @@ import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationRequest;
+import android.location.LocationResult;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.os.WorkSource;
@@ -167,8 +168,15 @@ public class FusedLocationServiceTest {
}
@Override
- public void onReportLocation(Location location) {
- mLocations.add(location);
+ public void onReportLocation(LocationResult locationResult) {
+ for (int i = 0; i < locationResult.size(); i++) {
+ mLocations.add(locationResult.get(i));
+ }
+ }
+
+ @Override
+ public void onFlushComplete() {
+
}
public Location getNextLocation(long timeoutMs) throws InterruptedException {
diff --git a/packages/PackageInstaller/res/values-kn/strings.xml b/packages/PackageInstaller/res/values-kn/strings.xml
index 19842eba0ef3..fa93f0d71fd6 100644
--- a/packages/PackageInstaller/res/values-kn/strings.xml
+++ b/packages/PackageInstaller/res/values-kn/strings.xml
@@ -69,7 +69,7 @@
<string name="uninstall_failed_app" msgid="5506028705017601412">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡುವಿಕೆ ಯಶಸ್ವಿಯಾಗಿಲ್ಲ."</string>
<string name="uninstall_failed_device_policy_manager" msgid="785293813665540305">"ಸಕ್ರಿಯ ಸಾಧನ ನಿರ್ವಹಣೆ ಆ್ಯಪ್‌ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="uninstall_failed_device_policy_manager_of_user" msgid="4813104025494168064">"<xliff:g id="USERNAME">%1$s</xliff:g> ಗಾಗಿ ಸಕ್ರಿಯ ಸಾಧನ ನಿರ್ವಹಣೆ ಆ್ಯಪ್‌ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
- <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"ಕೆಲವು ಬಳಕೆದಾರರು ಅಥವಾ ಪ್ರೊಫೈಲ್‌ಗಳಿಗೆ ಈ ಆಪ್‌ ಅಗತ್ಯ ಮತ್ತು ಇತರರ ಸಾಧನದಿಂದ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"ಕೆಲವು ಬಳಕೆದಾರರು ಅಥವಾ ಪ್ರೊಫೈಲ್‌ಗಳಿಗೆ ಈ ಆ್ಯಪ್‌ ಅಗತ್ಯ ಮತ್ತು ಇತರರ ಸಾಧನದಿಂದ ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲಾಗಿದೆ"</string>
<string name="uninstall_blocked_profile_owner" msgid="6373897407002404848">"ಈ ಆ್ಯಪ್‌ಗೆ ನಿಮ್ಮ ಪ್ರೊಫೈಲ್‌‌ನ ಅಗತ್ಯವಿದೆ ಮತ್ತು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
<string name="uninstall_blocked_device_owner" msgid="6724602931761073901">"ಈ ಆ್ಯಪ್‌ ನಿಮ್ಮ ಸಾಧನ ನಿರ್ವಾಹಕರಿಗೆ ಅಗತ್ಯವಿದೆ ಮತ್ತು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
<string name="manage_device_administrators" msgid="3092696419363842816">"ಸಾಧನದ ನಿರ್ವಹಣೆ ಆ್ಯಪ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
index dd991e097e1a..a9c754d3df79 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@@ -344,6 +344,10 @@ public class InstallInstalling extends AlertActivity {
try {
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
+ synchronized (this) {
+ isDone = true;
+ notifyAll();
+ }
return null;
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index 271b70daa41e..bbcc6a27babf 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -108,7 +108,8 @@ public class InstallStart extends Activity {
}
Intent nextActivity = new Intent(intent);
- nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+ | Intent.FLAG_GRANT_READ_URI_PERMISSION);
// The the installation source as the nextActivity thinks this activity is the source, hence
// set the originating UID and sourceInfo explicitly
diff --git a/packages/PrintSpooler/res/values-uz/strings.xml b/packages/PrintSpooler/res/values-uz/strings.xml
index ea0a6ea2f7b8..dbab9039f009 100644
--- a/packages/PrintSpooler/res/values-uz/strings.xml
+++ b/packages/PrintSpooler/res/values-uz/strings.xml
@@ -94,7 +94,7 @@
<item msgid="2762241247228983754">"Rang"</item>
</string-array>
<string-array name="duplex_mode_labels">
- <item msgid="3882302912790928315">"Yo‘q"</item>
+ <item msgid="3882302912790928315">"Hech qanday"</item>
<item msgid="7296563835355641719">"Uzun tomoni"</item>
<item msgid="79513688117503758">"Qisqa tomoni"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index e2b04d485488..5119c5602d19 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Geaktiveer"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Jou toestel moet herselflaai om hierdie verandering toe te pas. Herselflaai nou of kanselleer."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedraade oorfoon"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Af"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 0e3684e27527..de823406856f 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ነቅቷል"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"የእርስዎን መሣሪያ ይህ ለው ለማመልከት እንደገና መነሣት አለበት። አሁን እንደገና ያስነሡ ወይም ይተዉት።"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ባለገመድ ጆሮ ማዳመጫ"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"አብራ"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"አጥፋ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 7ec46d223d11..e61f5275bf29 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -562,4 +562,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"مفعّل"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"يجب إعادة تشغيل جهازك ليتم تطبيق هذا التغيير. يمكنك إعادة التشغيل الآن أو إلغاء التغيير."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة سلكية"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"تفعيل"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"إيقاف"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index fe0409451fb5..8d9d71abfa0b 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"সক্ষম কৰা আছে"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"এই সলনিটো কার্যকৰী হ’বলৈ আপোনাৰ ডিভাইচটো ৰিবুট কৰিবই লাগিব। এতিয়াই ৰিবুট কৰক অথবা বাতিল কৰক।"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তাঁৰযুক্ত হেডফ\'ন"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"অন"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"অফ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index bd10cfb928ac..0e74042c992b 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu dəyişikliyin tətbiq edilməsi üçün cihaz yenidən başladılmalıdır. İndi yenidən başladın və ya ləğv edin."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli qulaqlıq"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktiv"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Deaktiv"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index ebbe9969b686..4cd3b160831e 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -559,4 +559,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate da restartujete uređaj da bi se ova promena primenila. Restartujte ga odmah ili otkažite."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 9aad825d91ae..39023177c773 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -560,4 +560,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Уключана"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Перазагрузіце прыладу, каб прымяніць гэта змяненне. Перазагрузіце ці скасуйце."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Правадныя навушнікі"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Уключана"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выключана"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 8bf13fe56c05..a9c80f5f69fb 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Активирано"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да бъде приложена тази промяна, устройството ви трябва да бъде рестартирано. Рестартирайте сега или анулирайте."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Слушалки с кабел"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Включване"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Изключване"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 8bcf9a6ba19f..a86e93cc3699 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -558,4 +558,8 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"চালু করা আছে"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"এই পরিবর্তনটি প্রয়োগ করার জন্য আপনার ডিভাইসটি অবশ্যই রিবুট করতে হবে। এখনই রিবুট করুন বা বাতিল করুন।"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তার যুক্ত হেডফোন"</string>
+ <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
+ <skip />
+ <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 6e4ce03c5d93..77090cacc1cf 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -559,4 +559,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate ponovo pokrenuti uređaj da se ova promjena primijeni. Ponovo pokrenite odmah ili otkažite."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključi"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključi"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 525a1878c45c..9409e65414dd 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -531,7 +531,7 @@
<string name="user_add_profile_item_title" msgid="3111051717414643029">"Perfil restringit"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"Vols afegir un usuari nou?"</string>
<string name="user_add_user_message_long" msgid="1527434966294733380">"Pots compartir aquest dispositiu amb altres persones creant usuaris addicionals. Cada usuari té el seu propi espai, que pot personalitzar amb aplicacions i fons de pantalla, entre d\'altres. Els usuaris també poden ajustar opcions de configuració del dispositiu, com ara la Wi-Fi, que afecten els altres usuaris.\n\nQuan afegeixis un usuari nou, haurà de configurar el seu espai.\n\nTots els usuaris poden actualitzar les aplicacions de la resta. És possible que la configuració i els serveis d\'accessibilitat no es transfereixin a l\'usuari nou."</string>
- <string name="user_add_user_message_short" msgid="3295959985795716166">"Quan s\'afegeix un usuari nou, aquest usuari ha de configurar el seu espai.\n\nQualsevol usuari pot actualitzar les aplicacions dels altres usuaris."</string>
+ <string name="user_add_user_message_short" msgid="3295959985795716166">"Quan s\'afegeix un usuari nou, aquesta persona ha de configurar el seu espai.\n\nQualsevol usuari pot actualitzar les aplicacions dels altres usuaris."</string>
<string name="user_setup_dialog_title" msgid="8037342066381939995">"Vols configurar l\'usuari ara?"</string>
<string name="user_setup_dialog_message" msgid="269931619868102841">"Assegura\'t que la persona estigui disponible per accedir al dispositiu i configurar el seu espai."</string>
<string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Vols configurar el perfil ara?"</string>
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Has de reiniciar el teu dispositiu perquè s\'apliquin els canvis. Reinicia\'l ara o cancel·la."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculars amb cable"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activa"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactiva"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 64ad700c65bc..65687bef5b8d 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -560,4 +560,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuto"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aby se tato změna projevila, je třeba zařízení restartovat. Restartujte zařízení nebo zrušte akci."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelová sluchátka"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnout"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnout"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 433368bb9a83..73ed769ed34e 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiveret"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Din enhed skal genstartes for at anvende denne ændring. Genstart nu, eller annuller."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Høretelefoner med ledning"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Til"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Fra"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 9946eed222e2..8eb4b8570fb2 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiviert"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Damit diese Änderung übernommen wird, musst du dein Gerät neu starten. Du kannst es jetzt neu starten oder den Vorgang abbrechen."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelgebundene Kopfhörer"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"An"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Aus"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index c265dbc427ec..d934aeb5caa0 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ενεργή"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Για να εφαρμοστεί αυτή η αλλαγή, θα πρέπει να επανεκκινήσετε τη συσκευή σας. Επανεκκίνηση τώρα ή ακύρωση."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ενσύρματα ακουστικά"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ενεργό"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ανενεργό"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 285c615f8224..49e3a7c771b6 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index bbd5c7600818..258942168b1a 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 285c615f8224..49e3a7c771b6 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 285c615f8224..49e3a7c771b6 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 699ad426834a..94049a70cce2 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‎‏‏‎‏‎‎Enabled‎‏‎‎‏‎"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‏‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‎‎‎‎‎Your device must be rebooted for this change to apply. Reboot now or cancel.‎‏‎‎‏‎"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‎Wired headphone‎‏‎‎‏‎"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎On‎‏‎‎‏‎"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎Off‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index ab421f6f4154..5d4c15329f21 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Debes reiniciar el dispositivo para que se aplique el cambio. Reinícialo ahora o cancela la acción."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activar"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivar"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 1d9994d52e5d..9bd32560bd85 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Es necesario reiniciar tu dispositivo para que se apliquen los cambios. Reinicia ahora o cancela la acción."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activado"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 72766c067525..732b1f5e7eb0 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Lubatud"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Selle muudatuse rakendamiseks tuleb seade taaskäivitada. Taaskäivitage kohe või tühistage."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Juhtmega kõrvaklapid"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Sees"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Väljas"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index c7462cef36b7..9f4bd1a95abf 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Gaituta"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aldaketa aplikatzeko, berrabiarazi egin behar da gailua. Berrabiaraz ezazu orain, edo utzi bertan behera."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Entzungailu kableduna"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktibatu"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desaktibatu"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 0b21a2d6c8c4..1a5acc462452 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"برای اعمال این تغییر، دستگاهتان باید راه‌اندازی مجدد شود. اکنون راه‌اندازی مجدد کنید یا لغو کنید."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"هدفون سیمی"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"روشن"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"خاموش"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 6a563f3fb0ef..954264674b3d 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Käytössä"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Laitteesi on käynnistettävä uudelleen, jotta muutos tulee voimaan. Käynnistä uudelleen nyt tai peruuta."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Langalliset kuulokkeet"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Päällä"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Poissa päältä"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index f0364c614d56..7367dc3e54b3 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Votre appareil doit être redémarré pour que ce changement prenne effet. Redémarrez-le maintenant ou annulez la modification."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Écouteurs filaires"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activé"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Désactivé"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 17d13c1568df..f1474ad5f119 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Vous devez redémarrer l\'appareil pour que cette modification soit appliquée. Redémarrez maintenant ou annulez l\'opération."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Casque filaire"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Allumé"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Éteint"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index e0b21c38ff67..1e651a410af9 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necesario reiniciar o teu dispositivo para aplicar este cambio. Reiníciao agora ou cancela o cambio."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activar"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivar"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 90d49e229fc4..d52d487432d0 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ચાલુ છે"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"આ ફેરફારને લાગુ કરવા માટે તમારા ડિવાઇસને રીબૂટ કરવાની જરૂર છે. હમણાં જ રીબૂટ કરો કે રદ કરો."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"વાયરવાળો હૅડફોન"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ચાલુ"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"બંધ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 8486e3444db6..9f6334433951 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"चालू है"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"बदली गई सेटिंग को लागू करने के लिए, डिवाइस को रीस्टार्ट करना होगा. अपने डिवाइस को रीस्टार्ट करें या रद्द करें."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर वाला हेडफ़ोन"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"चालू है"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद है"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index a4ef3230fb5e..f95f8c19692b 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -559,4 +559,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Uređaj se mora ponovno pokrenuti da bi se ta promjena primijenila. Ponovo pokrenite uređaj odmah ili odustanite."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 480552b7b6b5..3167c83cb974 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Engedélyezve"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Az eszközt újra kell indítani, hogy a módosítás megtörténjen. Indítsa újra most, vagy vesse el a módosítást."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vezetékes fejhallgató"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Be"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ki"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 9fbf998dd14f..e6ef17d3320c 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Միացված է"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Սարքն անհրաժեշտ է վերագործարկել, որպեսզի փոփոխությունը կիրառվի։ Վերագործարկեք հիմա կամ չեղարկեք փոփոխությունը։"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Լարով ականջակալ"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Միացնել"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Անջատել"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index b1391ecaae73..749847212ea8 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktif"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Perangkat Anda harus di-reboot agar perubahan ini diterapkan. Reboot sekarang atau batalkan."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Headphone berkabel"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktif"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Nonaktif"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 1636c5542a8d..5e91394b15ba 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Virkt"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Endurræsa þarf tækið til að þessi breyting taki gildi. Endurræstu núna eða hættu við."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Heyrnartól með snúru"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Kveikt"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Slökkt"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index b358d651ac19..e42f1099aeb3 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Attivo"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Per applicare questa modifica, devi riavviare il dispositivo. Riavvia ora o annulla."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Cuffie con cavo"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 0f2eb4bd5fb1..e313552cacbc 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -560,4 +560,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"מופעל"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"צריך להפעיל מחדש את המכשיר כדי להחיל את השינוי. יש להפעיל מחדש עכשיו או לבטל."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"אוזניות חוטיות"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"פועלת"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"כבויה"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index dba1c95aade0..7c1598671da6 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"有効"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"この変更を適用するには、デバイスの再起動が必要です。今すぐ再起動するか、キャンセルしてください。"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線ヘッドフォン"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ON"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"OFF"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 8302b8da95b7..dd10e397e3c9 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ჩართული"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ამ ცვლილების ასამოქმედებლად თქვენი მოწყობილობა უნდა გადაიტვირთოს. გადატვირთეთ ახლავე ან გააუქმეთ."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"სადენიანი ყურსასმენი"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ჩართვა"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"გამორთვა"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index ffb5c9aa27a6..4857fe9d4bb1 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Қосулы"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бұл өзгеріс күшіне енуі үшін, құрылғыны қайта жүктеу керек. Қазір қайта жүктеңіз не бас тартыңыз."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Сымды құлақаспап"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Қосу"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өшіру"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 6fbd2d124538..6909af8c7afe 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"បានបើក"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ត្រូវតែ​ចាប់ផ្ដើម​ឧបករណ៍​របស់អ្នក​ឡើងវិញ ដើម្បីឱ្យ​ការផ្លាស់ប្ដូរ​នេះ​មានប្រសិទ្ធភាព។ ចាប់ផ្ដើមឡើងវិញ​ឥឡូវនេះ ឬ​បោះបង់​។"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"កាស​មានខ្សែ"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"បើក"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"បិទ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 653d8ba062e9..40e3f1f2c8e6 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -306,7 +306,7 @@
<string name="adb_keys_warning_message" msgid="2968555274488101220">"ನೀವು ಹಿಂದೆ ಅಧಿಕೃತಗೊಳಿಸಿದ ಎಲ್ಲ ಕಂಪ್ಯೂಟರ್‌ಗಳಿಂದ USB ಡೀಬಗ್‌ಗೆ ಪ್ರವೇಶವನ್ನು ರದ್ದುಗೊಳಿಸುವುದೇ?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"ಅಭಿವೃದ್ಧಿಯ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"ಈ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಅಭಿವೃದ್ಧಿಯ ಬಳಕೆಗೆ ಮಾತ್ರ. ಅವುಗಳು ನಿಮ್ಮ ಸಾಧನ ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌‌ಗಳಿಗೆ ಧಕ್ಕೆ ಮಾಡಬಹುದು ಅಥವಾ ಅವು ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸದಿರುವಂತೆ ಮಾಡಬಹುದು."</string>
- <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ಮೂಲಕ ಆಪ್‌ ಪರಿಶೀಲಿಸಿ"</string>
+ <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ಮೂಲಕ ಆ್ಯಪ್‌ ಪರಿಶೀಲಿಸಿ"</string>
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"ಹಾನಿಮಾಡುವಂತಹ ವರ್ತನೆಗಾಗಿ ADB/ADT ಮೂಲಕ ಸ್ಥಾಪಿಸಲಾದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"ಹೆಸರುಗಳಿಲ್ಲದ (ಕೇವಲ MAC ವಿಳಾಸಗಳು ಮಾತ್ರ) ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"ರಿಮೋಟ್ ಸಾಧನಗಳಲ್ಲಿ ಕಂಡುಬರುವ ಸ್ವೀಕಾರಾರ್ಹವಲ್ಲದ ಜೋರಾದ ವಾಲ್ಯೂಮ್ ಅಥವಾ ನಿಯಂತ್ರಣದ ಕೊರತೆಯಂತಹ ವಾಲ್ಯೂಮ್ ಸಮಸ್ಯೆಗಳಂತಹ ಸಂದರ್ಭದಲ್ಲಿ ಬ್ಲೂಟೂತ್‍ನ ನಿಚ್ಚಳ ವಾಲ್ಯೂಮ್ ವೈಶಿಷ್ಟ್ಯವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ಈ ಬದಲಾವಣೆ ಅನ್ವಯವಾಗಲು ನಿಮ್ಮ ಸಾಧನವನ್ನು ರೀಬೂಟ್ ಮಾಡಬೇಕು. ಇದೀಗ ರೀಬೂಟ್ ಮಾಡಿ ಅಥವಾ ರದ್ದುಗೊಳಿಸಿ."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ವೈಯರ್ ಹೊಂದಿರುವ ಹೆಡ್‌ಫೋನ್"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ಆನ್ ಆಗಿದೆ"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ಆಫ್ ಆಗಿದೆ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 761f8133f569..3b7a9e557058 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"사용 설정됨"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"변경사항을 적용하려면 기기를 재부팅해야 합니다. 지금 재부팅하거나 취소하세요."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"유선 헤드폰"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"사용"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"사용 안함"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index c72b93f4498b..44654fceb18e 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Күйүк"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бул өзгөрүү күчүнө кириши үчүн, түзмөктү өчүрүп күйгүзүңүз. Азыр же кийинчерээк өчүрүп күйгүзсөңүз болот."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Зымдуу гарнитура"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Күйгүзүү"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өчүрүү"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 78833086d2ca..bcb5ad1c3f80 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ເປີດການນຳໃຊ້ແລ້ວ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ທ່ານຕ້ອງປິດເປີດອຸປະກອນຄືນໃໝ່ເພື່ອນຳໃຊ້ການປ່ຽນແປງນີ້. ປິດເປີດໃໝ່ດຽວນີ້ ຫຼື ຍົກເລີກ."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ຫູຟັງແບບມີສາຍ"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ເປີດ"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ປິດ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index e3aa3687d5f9..3fc631a9a0c4 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -560,4 +560,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Įgalinta"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kad pakeitimas būtų pritaikytas, įrenginį reikia paleisti iš naujo. Dabar paleiskite iš naujo arba atšaukite."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Laidinės ausinės"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Įjungta"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Išjungta"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index e994974d813d..617a4f118dd5 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -559,4 +559,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Iespējots"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Lai šīs izmaiņas tiktu piemērotas, nepieciešama ierīces atkārtota palaišana. Atkārtoti palaidiet to tūlīt vai atceliet izmaiņas."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vadu austiņas"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ieslēgts"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izslēgts"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index e711747f328f..18a62d28c5b1 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Овозможено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да се примени променава, уредот мора да се рестартира. Рестартирајте сега или откажете."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичени слушалки"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вклучено"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Исклучено"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index cebd55213599..0ff31a61680d 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"പ്രവർത്തനക്ഷമമാക്കി"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ഈ മാറ്റം ബാധകമാകുന്നതിന് നിങ്ങളുടെ ഉപകരണം റീബൂട്ട് ചെയ്യേണ്ടതുണ്ട്. ഇപ്പോൾ റീബൂട്ട് ചെയ്യുകയോ റദ്ദാക്കുകയോ ചെയ്യുക."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"വയേർഡ് ഹെഡ്ഫോൺ"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ഓണാണ്"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ഓഫാണ്"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 80743665ca22..2fb4e447ca6c 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -70,7 +70,7 @@
<string name="bluetooth_pairing" msgid="4269046942588193600">"Хослуулж байна…"</string>
<string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Холбогдсон (утас байхгүй)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Холбогдсон (медиа байхгүй)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
- <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"Холбогдсон (зурвасын хандалт байхгүй)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+ <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"Холбогдсон (мессежийн хандалт байхгүй)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"Холбогдсон (утас эсвэл медиа байхгүй)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"Холбогдсон, батерей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
<string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Холбогдсон (утас байхгүй), батерей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Идэвхжүүлсэн"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Энэ өөрчлөлтийг хэрэгжүүлэхийн тулд таны төхөөрөмжийг дахин асаах ёстой. Одоо дахин асаах эсвэл цуцлана уу."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Утастай чихэвч"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Асаах"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Унтраах"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 8c55328bdc67..5ea183e519f8 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -558,4 +558,8 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"सुरू केले आहे"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"हा बदल लागू करण्यासाठी तुमचे डिव्हाइस रीबूट करणे आवश्यक आहे. आता रीबूट करा किंवा रद्द करा."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर असलेला हेडफोन"</string>
+ <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
+ <skip />
+ <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index d988dd01de92..56d3f0f36b56 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Didayakan"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Peranti anda mesti dibut semula supaya perubahan ini berlaku. But semula sekarang atau batalkan."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fon kepala berwayar"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Hidup"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Mati"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 5a167439ec82..0ba21029de2a 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ဖွင့်ထားသည်"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ဤအပြောင်းအလဲ ထည့်သွင်းရန် သင့်စက်ကို ပြန်လည်စတင်ရမည်။ ယခု ပြန်လည်စတင်ပါ သို့မဟုတ် ပယ်ဖျက်ပါ။"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ကြိုးတပ်နားကြပ်"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ဖွင့်ထားသည်"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ပိတ်ထားသည်"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index df96ea66ad25..47150e538298 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Slått på"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten din må startes på nytt for at denne endringen skal tre i kraft. Start på nytt nå eller avbryt."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hodetelefoner med kabel"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index e34732faf95d..8a86692fdd44 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -558,4 +558,8 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"सक्षम पारिएको छ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"यो परिवर्तन लागू गर्न तपाईंको यन्त्र अनिवार्य रूपमा रिबुट गर्नु पर्छ। अहिले रिबुट गर्नुहोस् वा रद्द गर्नुहोस्।"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"तारसहितको हेडफोन"</string>
+ <!-- no translation found for wifi_hotspot_switch_on_text (9212273118217786155) -->
+ <skip />
+ <!-- no translation found for wifi_hotspot_switch_off_text (7245567251496959764) -->
+ <skip />
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 729d57bac3b9..87bb8d55e281 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ingeschakeld"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Je apparaat moet opnieuw worden opgestart om deze wijziging toe te passen. Start nu opnieuw op of annuleer de wijziging."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedrade hoofdtelefoon"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Uit"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 1ce7d56ea6d6..1fe6d7feb944 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ସକ୍ଷମ କରାଯାଇଛି"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ଏହି ପରିବର୍ତ୍ତନ ଲାଗୁ କରିବା ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସକୁ ନିଶ୍ଚିତ ରୂପେ ରିବୁଟ୍ କରାଯିବା ଆବଶ୍ୟକ। ବର୍ତ୍ତମାନ ରିବୁଟ୍ କରନ୍ତୁ କିମ୍ବା ବାତିଲ୍ କରନ୍ତୁ।"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ତାରଯୁକ୍ତ ହେଡଫୋନ୍"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ଚାଲୁ ଅଛି"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ବନ୍ଦ ଅଛି"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index c122a280097b..934f11155b03 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ਇਸ ਤਬਦੀਲੀ ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨੂੰ ਰੀਬੂਟ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ। ਹੁਣੇ ਰੀਬੂਟ ਕਰੋ ਜਾਂ ਰੱਦ ਕਰੋ।"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ਤਾਰ ਵਾਲੇ ਹੈੱਡਫ਼ੋਨ"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ਚਾਲੂ"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ਬੰਦ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 112ae476c86e..8629b05a6b10 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -560,4 +560,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Włączono"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Wprowadzenie zmiany wymaga ponownego uruchomienia urządzenia. Uruchom ponownie teraz lub anuluj."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Słuchawki przewodowe"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Włączono"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Wyłączono"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 102961ab31ea..bac1ae4844f4 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -147,7 +147,7 @@
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Ponto de acesso portátil"</string>
<string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Tethering Bluetooth"</string>
<string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Tethering"</string>
- <string name="tether_settings_title_all" msgid="8910259483383010470">"Tethering e acesso portátil"</string>
+ <string name="tether_settings_title_all" msgid="8910259483383010470">"Tethering e ponto de acesso"</string>
<string name="managed_user_title" msgid="449081789742645723">"Todos os apps de trabalho"</string>
<string name="user_guest" msgid="6939192779649870792">"Convidado"</string>
<string name="unknown" msgid="3544487229740637809">"Desconhecido"</string>
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 7354835989ce..edc2cea14438 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativada"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reiniciar o dispositivo para aplicar esta alteração. Reinicie agora ou cancele."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auscultadores com fios"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ligado"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desligado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 102961ab31ea..bac1ae4844f4 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -147,7 +147,7 @@
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Ponto de acesso portátil"</string>
<string name="tether_settings_title_bluetooth" msgid="916519902721399656">"Tethering Bluetooth"</string>
<string name="tether_settings_title_usb_bluetooth" msgid="1727111807207577322">"Tethering"</string>
- <string name="tether_settings_title_all" msgid="8910259483383010470">"Tethering e acesso portátil"</string>
+ <string name="tether_settings_title_all" msgid="8910259483383010470">"Tethering e ponto de acesso"</string>
<string name="managed_user_title" msgid="449081789742645723">"Todos os apps de trabalho"</string>
<string name="user_guest" msgid="6939192779649870792">"Convidado"</string>
<string name="unknown" msgid="3544487229740637809">"Desconhecido"</string>
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 32e70da5d216..6445b9ef6028 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -559,4 +559,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pentru ca modificarea să se aplice, trebuie să reporniți dispozitivul. Reporniți-l acum sau anulați."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Căști cu fir"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activat"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Dezactivat"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index b04d93bf552c..0b18af817234 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -560,4 +560,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Включено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Чтобы изменение вступило в силу, необходимо перезапустить устройство. Вы можете сделать это сейчас или позже."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Проводные наушники"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вкл."</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выкл."</string>
</resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 86725c26e878..40327132c3f6 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"සබලයි"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"මෙම වෙනස යෙදීමට ඔබේ උපාංගය නැවත පණ ගැන්විය යුතුය. දැන් නැවත පණ ගන්වන්න හෝ අවලංගු කරන්න."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"රැහැන්ගත කළ හෙඩ්ෆෝන්"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ක්‍රියාත්මකයි"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ක්‍රියාවිරහිතයි"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 91e9564a8c80..4e3529f57e58 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -560,4 +560,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuté"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Zmena sa prejaví až po reštarte zariadenia. Môžete ho teraz reštartovať alebo akciu zrušiť."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Slúchadlá s káblom"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnúť"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnúť"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 45ffcde74872..22dd5dd4bb56 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -560,4 +560,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogočeno"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Napravo je treba znova zagnati, da bo ta sprememba uveljavljena. Znova zaženite zdaj ali prekličite."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žične slušalke"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vklop"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izklop"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index c3983636ffe8..db29b41fe155 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pajisja jote duhet të riniset që ky ndryshim të zbatohet. Rinise tani ose anuloje."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kufje me tela"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktive"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Joaktive"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 18cf808cdccf..97398d0b7aee 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -559,4 +559,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Омогућено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Морате да рестартујете уређај да би се ова промена применила. Рестартујте га одмах или откажите."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичане слушалице"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Укључено"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Искључено"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 197655ef5e58..8bdfa0da8b69 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiverat"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten måste startas om för att ändringen ska börja gälla. Starta om nu eller avbryt."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hörlurar med sladd"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 1f0d167f6df2..bbd1b8a5e428 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Imewashwa"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Ni lazima uwashe tena kifaa chako ili mabadiliko haya yatekelezwe. Washa tena sasa au ughairi."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vipokea sauti vya waya"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Umewashwa"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Umezimwa"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index b6d8be8ae54d..a38673903e09 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"இயக்கப்பட்டது"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"இந்த மாற்றங்கள் செயல்படுத்தப்பட உங்கள் சாதனத்தை மறுபடி தொடங்க வேண்டும். இப்போதே மறுபடி தொடங்கவும் அல்லது ரத்துசெய்யவும்."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"வயருள்ள ஹெட்ஃபோன்"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ஆன்"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ஆஃப்"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index 1d7e88c64717..e1c0406ee168 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -86,7 +86,7 @@
<item msgid="8147982633566548515">"map14"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_titles">
- <item msgid="2494959071796102843">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="2494959071796102843">"సిస్టమ్ ఎంపికను ఉపయోగించండి (ఆటోమేటిక్)"</item>
<item msgid="4055460186095649420">"SBC"</item>
<item msgid="720249083677397051">"AAC"</item>
<item msgid="1049450003868150455">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ఆడియో"</item>
@@ -94,7 +94,7 @@
<item msgid="3825367753087348007">"LDAC"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_summaries">
- <item msgid="8868109554557331312">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="8868109554557331312">"సిస్టమ్ ఎంపికను ఉపయోగించండి (ఆటోమేటిక్)"</item>
<item msgid="9024885861221697796">"SBC"</item>
<item msgid="4688890470703790013">"AAC"</item>
<item msgid="8627333814413492563">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ఆడియో"</item>
@@ -102,38 +102,38 @@
<item msgid="2553206901068987657">"LDAC"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
- <item msgid="926809261293414607">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="926809261293414607">"సిస్టమ్ ఎంపికను ఉపయోగించండి (ఆటోమేటిక్)"</item>
<item msgid="8003118270854840095">"44.1 kHz"</item>
<item msgid="3208896645474529394">"48.0 kHz"</item>
<item msgid="8420261949134022577">"88.2 kHz"</item>
<item msgid="8887519571067543785">"96.0 kHz"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_summaries">
- <item msgid="2284090879080331090">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="2284090879080331090">"సిస్టమ్ ఎంపికను ఉపయోగించండి (ఆటోమేటిక్)"</item>
<item msgid="1872276250541651186">"44.1 kHz"</item>
<item msgid="8736780630001704004">"48.0 kHz"</item>
<item msgid="7698585706868856888">"88.2 kHz"</item>
<item msgid="8946330945963372966">"96.0 kHz"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
- <item msgid="2574107108483219051">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="2574107108483219051">"సిస్టమ్ ఎంపికను ఉపయోగించండి (ఆటోమేటిక్)"</item>
<item msgid="4671992321419011165">"16 బిట్‌లు/నమూనా"</item>
<item msgid="1933898806184763940">"24 బిట్‌లు/నమూనా"</item>
<item msgid="1212577207279552119">"32 బిట్‌లు/నమూనా"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
- <item msgid="9196208128729063711">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="9196208128729063711">"సిస్టమ్ ఎంపికను ఉపయోగించండి (ఆటోమేటిక్)"</item>
<item msgid="1084497364516370912">"16 బిట్‌లు/నమూనా"</item>
<item msgid="2077889391457961734">"24 బిట్‌లు/నమూనా"</item>
<item msgid="3836844909491316925">"32 బిట్‌లు/నమూనా"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_channel_mode_titles">
- <item msgid="3014194562841654656">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="3014194562841654656">"సిస్టమ్ ఎంపికను ఉపయోగించండి (ఆటోమేటిక్)"</item>
<item msgid="5982952342181788248">"మోనో"</item>
<item msgid="927546067692441494">"స్టీరియో"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
- <item msgid="1997302811102880485">"సిస్టమ్ ఎంపికను ఉపయోగించండి (డిఫాల్ట్)"</item>
+ <item msgid="1997302811102880485">"సిస్టమ్ ఎంపికను ఉపయోగించండి (ఆటోమేటిక్)"</item>
<item msgid="8005696114958453588">"మోనో"</item>
<item msgid="1333279807604675720">"స్టీరియో"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 5a8e734ab878..4023897bbfd0 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -156,14 +156,14 @@
<string name="launch_defaults_none" msgid="8049374306261262709">"ఆటోమేటిక్ ఆప్ష‌న్‌లు ఏవీ సెట్ చేయ‌‌లేదు"</string>
<string name="tts_settings" msgid="8130616705989351312">"వచనం నుండి ప్రసంగం సెట్టింగ్‌లు"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"టెక్స్ట్-టు-స్పీచ్ అవుట్‌పుట్"</string>
- <string name="tts_default_rate_title" msgid="3964187817364304022">"ప్రసంగం రేట్"</string>
+ <string name="tts_default_rate_title" msgid="3964187817364304022">"స్పీచ్ రేట్"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"వచనాన్ని చదివి వినిపించాల్సిన వేగం"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"పిచ్"</string>
<string name="tts_default_pitch_summary" msgid="9132719475281551884">"సమన్వయం చేసిన ప్రసంగం యొక్క టోన్‌ను ప్రభావితం చేస్తుంది"</string>
<string name="tts_default_lang_title" msgid="4698933575028098940">"భాష"</string>
<string name="tts_lang_use_system" msgid="6312945299804012406">"సిస్టమ్ భాషను ఉపయోగించు"</string>
<string name="tts_lang_not_selected" msgid="7927823081096056147">"భాష ఎంచుకోబడలేదు"</string>
- <string name="tts_default_lang_summary" msgid="9042620014800063470">"చదవి వినిపించబడే వచనం కోసం భాష-నిర్దిష్ట వాయిస్‌ను సెట్ చేస్తుంది"</string>
+ <string name="tts_default_lang_summary" msgid="9042620014800063470">"టెక్స్ట్‌ను చదివి వినిపించేటప్పుడు, ఒక్కో భాషకు వాడాల్సిన నిర్దిష్ట వాయిస్‌ను సెట్ చేస్తుంది"</string>
<string name="tts_play_example_title" msgid="1599468547216481684">"ఒక ఉదాహరణ వినండి"</string>
<string name="tts_play_example_summary" msgid="634044730710636383">"ప్రసంగ సమన్వయం గురించి సంక్షిప్త ప్రదర్శనను ప్లే చేయి"</string>
<string name="tts_install_data_title" msgid="1829942496472751703">"వాయిస్ డేటాను ఇన్‌స్టాల్ చేయి"</string>
@@ -196,7 +196,7 @@
<string name="choose_profile" msgid="343803890897657450">"ప్రొఫైల్‌ను ఎంచుకోండి"</string>
<string name="category_personal" msgid="6236798763159385225">"వ్యక్తిగతం"</string>
<string name="category_work" msgid="4014193632325996115">"ఆఫీస్"</string>
- <string name="development_settings_title" msgid="140296922921597393">"డెవలపర్ ఎంపికలు"</string>
+ <string name="development_settings_title" msgid="140296922921597393">"డెవలపర్ ఆప్షన్‌లు"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"డెవలపర్ ఎంపికలను ప్రారంభించండి"</string>
<string name="development_settings_summary" msgid="8718917813868735095">"అనువర్తన అభివృద్ధి కోసం ఎంపికలను సెట్ చేయండి"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"ఈ వినియోగదారు కోసం డెవలపర్ ఎంపికలు అందుబాటులో లేవు"</string>
@@ -280,7 +280,7 @@
<string name="private_dns_mode_provider" msgid="3619040641762557028">"ప్రైవేట్ DNS ప్రదాత హోస్ట్‌పేరు"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"DNS ప్రదాత యొక్క హోస్ట్‌పేరును నమోదు చేయండి"</string>
<string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"కనెక్ట్ చేయడం సాధ్యపడలేదు"</string>
- <string name="wifi_display_certification_summary" msgid="8111151348106907513">"వైర్‌లెస్ ప్రదర్శన సర్టిఫికెట్ కోసం ఎంపికలను చూపు"</string>
+ <string name="wifi_display_certification_summary" msgid="8111151348106907513">"వైర్‌లెస్ డిస్‌ప్లే సర్టిఫికేషన్ ఆప్షన్‌లను చూపు"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Wi‑Fi ఎంపికలో SSID RSSI ప్రకారం చూపబడే Wi‑Fi లాగింగ్ స్థాయిని పెంచండి"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"బ్యాటరీ శక్తి వినియోగాన్ని తగ్గించి &amp; నెట్‌వర్క్ పనితీరును మెరుగుపరుస్తుంది"</string>
<string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"ఈ మోడ్ ఎనేబుల్ అయ్యాక, MAC ర్యాండమైజేషన్‌ను ఎనేబుల్ చేసిన నెట్‌వర్క్‌తో కనెక్ట్ అయ్యే ప్రతిసారీ ఈ పరికరం MAC అడ్రస్ మారవచ్చు."</string>
@@ -366,7 +366,7 @@
<string name="overlay_display_devices_title" msgid="5411894622334469607">"ప్రత్యామ్నాయ ప్రదర్శనలను అనుకరించండి"</string>
<string name="debug_applications_category" msgid="5394089406638954196">"యాప్‌లు"</string>
<string name="immediately_destroy_activities" msgid="1826287490705167403">"కార్యకలాపాలను ఉంచవద్దు"</string>
- <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"ప్రతి కార్యకలాపాన్ని వినియోగదారు నిష్క్రమించిన వెంటనే తొలగించండి"</string>
+ <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"యూజర్ నిష్క్రమించాక పూర్తి యాక్టివిటీ తొలగింపు"</string>
<string name="app_process_limit_title" msgid="8361367869453043007">"బ్యాక్‌గ్రౌండ్ ప్రాసెస్ పరిమితి"</string>
<string name="show_all_anrs" msgid="9160563836616468726">"బ్యాక్‌గ్రౌండ్ ANRలను చూపు"</string>
<string name="show_all_anrs_summary" msgid="8562788834431971392">"నేపథ్య యాప్‌ల కోసం యాప్ ప్రతిస్పందించడం లేదు అనే డైలాగ్‌ను చూపు"</string>
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ఎనేబుల్ చేయబడింది"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ఈ మార్పును వర్తింపజేయాలంటే మీరు మీ పరికరాన్ని తప్పనిసరిగా రీబూట్ చేయాలి. ఇప్పుడే రీబూట్ చేయండి లేదా రద్దు చేయండి."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"వైర్ ఉన్న హెడ్‌ఫోన్"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ఆన్‌లో ఉంది"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ఆఫ్‌లో ఉంది"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 2ae4131ba415..4d22fb0f0d48 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"เปิดใช้"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"คุณต้องรีบูตอุปกรณ์เพื่อให้การเปลี่ยนแปลงนี้มีผล รีบูตเลยหรือยกเลิก"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"หูฟังแบบมีสาย"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"เปิด"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ปิด"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index e9f1da3c5c4b..875bbff10d74 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Na-enable"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Dapat i-reboot ang iyong device para mailapat ang pagbabagong ito. Mag-reboot ngayon o kanselahin."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired na headphone"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Naka-on"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Naka-off"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 0502359dc9da..9604c94bfb49 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Etkin"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu değişikliğin geçerli olması için cihazınızın yeniden başlatılması gerekir. Şimdi yeniden başlatın veya iptal edin."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kablolu kulaklık"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Açık"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Kapalı"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 8e13afd480f7..03eb42c9ff8f 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -560,4 +560,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Увімкнено"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Щоб застосувати ці зміни, потрібний перезапуск. Перезапустіть пристрій або скасуйте зміни."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Дротові навушники"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Увімкнено"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Вимкнено"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index b971aeef9c9b..12f36fbc5e56 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"اس تبدیلی کو لاگو کرنے کے ليے آپ کے آلہ کو ریبوٹ کرنا ضروری ہے۔ ابھی ریبوٹ کریں یا منسوخ کریں۔"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"وائرڈ ہیڈ فون"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"آن"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"آف"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 3df33b681470..aaaa0291e467 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Yoniq"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Oʻzgarishlar kuchga kirishi uchun qurilmani oʻchirib yoqing. Buni hozir yoki keyinroq bajarishingiz mumkin."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli quloqlik"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Yoniq"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Oʻchiq"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 4d4808f77d04..94494c784cd4 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -305,7 +305,7 @@
<string name="adbwifi_warning_message" msgid="8005936574322702388">"Tính năng gỡ lỗi qua Wi-Fi chỉ dành cho mục đích phát triển. Hãy sử dụng tính năng này để sao chép dữ liệu giữa máy tính và thiết bị của bạn, cài đặt ứng dụng trên thiết bị mà không thông báo và đọc dữ liệu nhật ký."</string>
<string name="adb_keys_warning_message" msgid="2968555274488101220">"Thu hồi quyền truy cập gỡ lỗi USB từ tất cả máy tính mà bạn đã ủy quyền trước đó?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"Cho phép cài đặt phát triển?"</string>
- <string name="dev_settings_warning_message" msgid="37741686486073668">"Những cài đặt này chỉ dành cho mục đích phát triển. Chúng có thể làm cho thiết bị và ứng dụng trên thiết bị của bạn bị lỗi và hoạt động sai."</string>
+ <string name="dev_settings_warning_message" msgid="37741686486073668">"Những tùy chọn cài đặt này chỉ dành cho mục đích phát triển. Chúng có thể làm cho thiết bị và ứng dụng trên thiết bị của bạn bị lỗi và hoạt động không đúng cách."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Xác minh ứng dụng qua USB"</string>
<string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Kiểm tra các ứng dụng được cài đặt qua ADB/ADT để xem có hoạt động gây hại hay không."</string>
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Các thiết bị Bluetooth không có tên (chỉ có địa chỉ MAC) sẽ được hiển thị"</string>
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Đã bật"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bạn phải khởi động lại thiết bị để áp dụng sự thay đổi này. Hãy khởi động lại ngay hoặc hủy."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Tai nghe có dây"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Đang bật"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Đang tắt"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index b6e8eba2e159..00233c570ab2 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已启用"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"设备必须重新启动才能应用此更改。您可以立即重新启动或取消。"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有线耳机"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"开启"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"关闭"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 07bc88731a71..b83ad35cbd25 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"您的裝置必須重新開機,才能套用此變更。請立即重新開機或取消。"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 833a82ff244f..e5ef61365a07 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"裝置必須重新啟動才能套用這項變更。請立即重新啟動或取消變更。"</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 0065eb616d0c..ba3070045b9e 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -113,7 +113,7 @@
<string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Isetshenziselwa okufakwayo"</string>
<string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Sebenzisa izinsiza zokuzwa"</string>
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Bhangqa"</string>
- <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"BHANQA"</string>
+ <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"BHANGQA"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Khansela"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Ukubhanqa kunika ukufinyelela koxhumana nabo nomlando wekholi uma uxhumekile."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Ayikwazanga ukuhlangana ne <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -558,4 +558,6 @@
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Inikwe amandla"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kufanele idivayisi yakho iqaliswe ukuze lolu shintsho lusebenze. Qalisa manje noma khansela."</string>
<string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ama-headphone anentambo"</string>
+ <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vuliwe"</string>
+ <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Valiwe"</string>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 6a4c8c301cbe..4d054ecc9914 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -992,6 +992,15 @@
<string name="standby_bucket_summary">App standby
state:<xliff:g id="bucket"> %s</xliff:g></string>
+ <!-- Settings item title for transcode settings for apps. [CHAR LIMIT=85] -->
+ <string name="transcode_settings_title">Media transcode settings</string>
+
+ <!-- Settings item title to enable or disable transcoding for all apps. [CHAR LIMIT=85] -->
+ <string name="transcode_enable_all">Enable transcoding for all apps</string>
+
+ <!-- Settings category title for selecting apps to be skipped from transcoding. [CHAR LIMIT=85] -->
+ <string name="transcode_skip_apps">Disable transcoding for apps</string>
+
<!-- Services settings screen, setting option name for the user to go to the screen to view running services -->
<string name="runningservices_settings_title">Running services</string>
<!-- Services settings screen, setting option summary for the user to go to the screen to view running services -->
@@ -1385,4 +1394,9 @@
<!-- Name of the 3.5mm and usb audio device. [CHAR LIMIT=50] -->
<string name="media_transfer_wired_usb_device_name">Wired headphone</string>
+
+ <!-- Label for Wifi hotspot switch on. Toggles hotspot on [CHAR LIMIT=30] -->
+ <string name="wifi_hotspot_switch_on_text">On</string>
+ <!-- Label for Wifi hotspot switch off. Toggles hotspot off [CHAR LIMIT=30] -->
+ <string name="wifi_hotspot_switch_off_text">Off</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java
index 9ea7a4af8d12..6ce72bbc6909 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java
@@ -38,7 +38,7 @@ public class BluetoothDiscoverableTimeoutReceiver extends BroadcastReceiver {
Intent intent = new Intent(INTENT_DISCOVERABLE_TIMEOUT);
intent.setClass(context, BluetoothDiscoverableTimeoutReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(
- context, 0, intent, 0);
+ context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
AlarmManager alarmManager =
(AlarmManager) context.getSystemService (Context.ALARM_SERVICE);
@@ -47,8 +47,7 @@ public class BluetoothDiscoverableTimeoutReceiver extends BroadcastReceiver {
alarmManager.cancel(pending);
Log.d(TAG, "setDiscoverableAlarm(): cancel prev alarm");
}
- pending = PendingIntent.getBroadcast(
- context, 0, intent, 0);
+ pending = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, pending);
}
@@ -59,7 +58,7 @@ public class BluetoothDiscoverableTimeoutReceiver extends BroadcastReceiver {
Intent intent = new Intent(INTENT_DISCOVERABLE_TIMEOUT);
intent.setClass(context, BluetoothDiscoverableTimeoutReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(
- context, 0, intent, PendingIntent.FLAG_NO_CREATE);
+ context, 0, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE);
if (pending != null) {
// Cancel any previous alarms that do the same thing.
AlarmManager alarmManager =
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
index f6cd971ec4f3..12ef639093bf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
@@ -16,6 +16,8 @@
package com.android.settingslib.volume;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -23,20 +25,21 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
-import android.media.IRemoteVolumeController;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
+import android.media.session.MediaSession;
import android.media.session.MediaSession.QueueItem;
import android.media.session.MediaSession.Token;
import android.media.session.MediaSessionManager;
import android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
+import android.media.session.MediaSessionManager.RemoteVolumeControllerCallback;
import android.media.session.PlaybackState;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
import android.util.Log;
import java.io.PrintWriter;
@@ -58,6 +61,7 @@ public class MediaSessions {
private final Context mContext;
private final H mHandler;
+ private final HandlerExecutor mHandlerExecutor;
private final MediaSessionManager mMgr;
private final Map<Token, MediaControllerRecord> mRecords = new HashMap<>();
private final Callbacks mCallbacks;
@@ -67,6 +71,7 @@ public class MediaSessions {
public MediaSessions(Context context, Looper looper, Callbacks callbacks) {
mContext = context;
mHandler = new H(looper);
+ mHandlerExecutor = new HandlerExecutor(mHandler);
mMgr = (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
mCallbacks = callbacks;
}
@@ -95,7 +100,8 @@ public class MediaSessions {
mMgr.addOnActiveSessionsChangedListener(mSessionsListener, null, mHandler);
mInit = true;
postUpdateSessions();
- mMgr.registerRemoteVolumeController(mRvc);
+ mMgr.registerRemoteVolumeControllerCallback(mHandlerExecutor,
+ mRemoteVolumeControllerCallback);
}
protected void postUpdateSessions() {
@@ -110,7 +116,7 @@ public class MediaSessions {
if (D.BUG) Log.d(TAG, "destroy");
mInit = false;
mMgr.removeOnActiveSessionsChangedListener(mSessionsListener);
- mMgr.unregisterRemoteVolumeController(mRvc);
+ mMgr.unregisterRemoteVolumeControllerCallback(mRemoteVolumeControllerCallback);
}
/**
@@ -330,19 +336,19 @@ public class MediaSessions {
}
};
- private final IRemoteVolumeController mRvc = new IRemoteVolumeController.Stub() {
- @Override
- public void remoteVolumeChanged(Token sessionToken, int flags)
- throws RemoteException {
- mHandler.obtainMessage(H.REMOTE_VOLUME_CHANGED, flags, 0,
- sessionToken).sendToTarget();
- }
+ private final RemoteVolumeControllerCallback mRemoteVolumeControllerCallback =
+ new RemoteVolumeControllerCallback() {
+ @Override
+ public void onVolumeChanged(@NonNull MediaSession.Token sessionToken,
+ int flags) {
+ mHandler.obtainMessage(H.REMOTE_VOLUME_CHANGED, flags, 0,
+ sessionToken).sendToTarget();
+ }
- @Override
- public void updateRemoteController(final Token sessionToken)
- throws RemoteException {
- mHandler.obtainMessage(H.UPDATE_REMOTE_CONTROLLER, sessionToken).sendToTarget();
- }
+ @Override
+ public void onSessionChanged(@Nullable MediaSession.Token sessionToken) {
+ mHandler.obtainMessage(H.UPDATE_REMOTE_CONTROLLER, sessionToken).sendToTarget();
+ }
};
private final class H extends Handler {
diff --git a/packages/SettingsProvider/src/android/provider/settings/OWNERS b/packages/SettingsProvider/src/android/provider/settings/OWNERS
index 7e7710b4d550..0f888113d730 100644
--- a/packages/SettingsProvider/src/android/provider/settings/OWNERS
+++ b/packages/SettingsProvider/src/android/provider/settings/OWNERS
@@ -1,4 +1,4 @@
# Bug component: 656484
-include platform/frameworks/base/services/backup:/OWNERS
+include platform/frameworks/base:/services/backup/OWNERS
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index b9e30fb950c6..ffbc7f4cecf3 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -89,6 +89,7 @@ public class SecureSettings {
Settings.Secure.RTT_CALLING_MODE,
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
Settings.Secure.MINIMAL_POST_PROCESSING_ALLOWED,
+ Settings.Secure.MATCH_CONTENT_FRAME_RATE,
Settings.Secure.NIGHT_DISPLAY_CUSTOM_START_TIME,
Settings.Secure.NIGHT_DISPLAY_CUSTOM_END_TIME,
Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 721bf730a343..46c42fc8fdd6 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -135,6 +135,9 @@ public class SecureSettingsValidators {
Secure.INCALL_POWER_BUTTON_BEHAVIOR,
new DiscreteValueValidator(new String[] {"1", "2"}));
VALIDATORS.put(Secure.MINIMAL_POST_PROCESSING_ALLOWED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(
+ Secure.MATCH_CONTENT_FRAME_RATE,
+ new DiscreteValueValidator(new String[] {"0", "1", "2"}));
VALIDATORS.put(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, NON_NEGATIVE_INTEGER_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 38ff447a71b5..2e551fa80f74 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -888,8 +888,8 @@ class SettingsProtoDumpUtil {
Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
GlobalSettingsProto.Location.SETTINGS_LINK_TO_PERMISSIONS_ENABLED);
dumpSetting(s, p,
- Settings.Global.GNSS_SATELLITE_BLACKLIST,
- GlobalSettingsProto.Location.GNSS_SATELLITE_BLACKLIST);
+ Settings.Global.GNSS_SATELLITE_BLOCKLIST,
+ GlobalSettingsProto.Location.GNSS_SATELLITE_BLOCKLIST);
dumpSetting(s, p,
Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
GlobalSettingsProto.Location.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 36213a020783..a61e3cd5f4ab 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3342,7 +3342,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 194;
+ private static final int SETTINGS_VERSION = 195;
private final int mUserId;
@@ -4761,6 +4761,22 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 194;
}
+ if (currentVersion == 194) {
+ // Version 194: migrate the GNSS_SATELLITE_BLOCKLIST setting
+ final SettingsState globalSettings = getGlobalSettingsLocked();
+ final Setting newSetting = globalSettings.getSettingLocked(
+ Global.GNSS_SATELLITE_BLOCKLIST);
+ final String oldName = "gnss_satellite_blacklist";
+ final Setting oldSetting = globalSettings.getSettingLocked(oldName);
+ if (newSetting.isNull() && !oldSetting.isNull()) {
+ globalSettings.insertSettingLocked(
+ Global.GNSS_SATELLITE_BLOCKLIST, oldSetting.getValue(), null, true,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ globalSettings.deleteSettingLocked(oldName);
+ }
+ currentVersion = 195;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/android/provider/OWNERS b/packages/SettingsProvider/test/src/android/provider/OWNERS
index 7e7710b4d550..0f888113d730 100644
--- a/packages/SettingsProvider/test/src/android/provider/OWNERS
+++ b/packages/SettingsProvider/test/src/android/provider/OWNERS
@@ -1,4 +1,4 @@
# Bug component: 656484
-include platform/frameworks/base/services/backup:/OWNERS
+include platform/frameworks/base:/services/backup/OWNERS
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 2412a32bd71b..a3bda96337bb 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -230,6 +230,7 @@ public class SettingsBackupTest {
Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR,
Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV,
Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_VR,
+ Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS,
Settings.Global.DEVICE_DEMO_MODE,
Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS,
Settings.Global.BATTERY_SAVER_CONSTANTS,
@@ -290,7 +291,7 @@ public class SettingsBackupTest {
Settings.Global.GLOBAL_HTTP_PROXY_PAC,
Settings.Global.GLOBAL_HTTP_PROXY_PORT,
Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
- Settings.Global.GNSS_SATELLITE_BLACKLIST,
+ Settings.Global.GNSS_SATELLITE_BLOCKLIST,
Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
Settings.Global.HDMI_CEC_SWITCH_ENABLED,
Settings.Global.HDMI_CEC_VERSION,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ec47c717ac3c..a97af4bbe324 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -249,6 +249,10 @@
<!-- Permission required for CTS test - UiModeManagerTest -->
<uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
+ <uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
+
+ <!-- Permission required for CTS tests - UiModeManagerTest, CarModeInCallServiceTest -->
+ <uses-permission android:name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION"/>
<!-- Permission required for CTS test - SystemConfigTest -->
<uses-permission android:name="android.permission.READ_CARRIER_APP_INFO"/>
diff --git a/packages/Shell/src/com/android/shell/HeapDumpReceiver.java b/packages/Shell/src/com/android/shell/HeapDumpReceiver.java
index 858c521eaed5..7433c3ee37b6 100644
--- a/packages/Shell/src/com/android/shell/HeapDumpReceiver.java
+++ b/packages/Shell/src/com/android/shell/HeapDumpReceiver.java
@@ -180,7 +180,7 @@ public class HeapDumpReceiver extends BroadcastReceiver {
.setContentText(context.getText(
com.android.internal.R.string.dump_heap_notification_detail))
.setContentIntent(PendingIntent.getActivity(context, 2, shareIntent,
- PendingIntent.FLAG_UPDATE_CURRENT));
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE));
Log.v(TAG, "Creating share heap dump notification");
NotificationManager.from(context).notify(NOTIFICATION_ID, builder.build());
diff --git a/packages/SoundPicker/res/values-kk/strings.xml b/packages/SoundPicker/res/values-kk/strings.xml
index 810192f92ef9..ad6d0e071d7d 100644
--- a/packages/SoundPicker/res/values-kk/strings.xml
+++ b/packages/SoundPicker/res/values-kk/strings.xml
@@ -19,7 +19,7 @@
<string name="ringtone_default" msgid="798836092118824500">"Әдепкі рингтон"</string>
<string name="notification_sound_default" msgid="8133121186242636840">"Әдепкі хабарландыру дыбысы"</string>
<string name="alarm_sound_default" msgid="4787646764557462649">"Әдепкі дабыл дыбысы"</string>
- <string name="add_ringtone_text" msgid="6642389991738337529">"Рингтон енгізу"</string>
+ <string name="add_ringtone_text" msgid="6642389991738337529">"Рингтон қосу"</string>
<string name="add_alarm_text" msgid="3545497316166999225">"Оятқыш енгізу"</string>
<string name="add_notification_text" msgid="4431129543300614788">"Хабарландыру енгізу"</string>
<string name="delete_ringtone_text" msgid="201443984070732499">"Жою"</string>
diff --git a/packages/SoundPicker/res/values-te/strings.xml b/packages/SoundPicker/res/values-te/strings.xml
index 6b8a62e58526..10b4e7cfe615 100644
--- a/packages/SoundPicker/res/values-te/strings.xml
+++ b/packages/SoundPicker/res/values-te/strings.xml
@@ -17,8 +17,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="ringtone_default" msgid="798836092118824500">"డిఫాల్ట్ రింగ్‌టోన్"</string>
- <string name="notification_sound_default" msgid="8133121186242636840">"డిఫాల్ట్ నోటిఫికేషన్ ధ్వని"</string>
- <string name="alarm_sound_default" msgid="4787646764557462649">"డిఫాల్ట్ అలారం ధ్వని"</string>
+ <string name="notification_sound_default" msgid="8133121186242636840">"నోటిఫికేషన్ ఆటోమేటిక్ సౌండ్"</string>
+ <string name="alarm_sound_default" msgid="4787646764557462649">"అలారం ఆటోమేటిక్ సౌండ్"</string>
<string name="add_ringtone_text" msgid="6642389991738337529">"రింగ్‌టోన్‌ను జోడించు"</string>
<string name="add_alarm_text" msgid="3545497316166999225">"అలారాన్ని జోడించు"</string>
<string name="add_notification_text" msgid="4431129543300614788">"నోటిఫికేషన్‌‌ని జోడించు"</string>
diff --git a/packages/SoundPicker/res/values-uz/strings.xml b/packages/SoundPicker/res/values-uz/strings.xml
index a617733737e7..c39db5f8dd01 100644
--- a/packages/SoundPicker/res/values-uz/strings.xml
+++ b/packages/SoundPicker/res/values-uz/strings.xml
@@ -20,7 +20,7 @@
<string name="notification_sound_default" msgid="8133121186242636840">"Standart bildirishnoma tovushi"</string>
<string name="alarm_sound_default" msgid="4787646764557462649">"Standart signal tovushi"</string>
<string name="add_ringtone_text" msgid="6642389991738337529">"Rington qo‘shish"</string>
- <string name="add_alarm_text" msgid="3545497316166999225">"Signal qo‘shish"</string>
+ <string name="add_alarm_text" msgid="3545497316166999225">"Signal kiritish"</string>
<string name="add_notification_text" msgid="4431129543300614788">"Bildirishnoma kiritish"</string>
<string name="delete_ringtone_text" msgid="201443984070732499">"O‘chirish"</string>
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Maxsus rington qo‘shib bo‘lmadi"</string>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index f9268eece293..3de0fbdf8fb1 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -352,7 +352,7 @@
android:exported="true" />
<activity
- android:name=".bubbles.BubbleOverflowActivity"
+ android:name="com.android.wm.shell.bubbles.BubbleOverflowActivity"
android:theme="@style/BubbleOverflow"
android:excludeFromRecents="true"
android:documentLaunchMode="always"
@@ -669,7 +669,7 @@
</activity>
<activity
- android:name=".settings.BrightnessDialog"
+ android:name=".settings.brightness.BrightnessDialog"
android:label="@string/quick_settings_brightness_dialog_title"
android:theme="@*android:style/Theme.DeviceDefault.QuickSettings.Dialog"
android:finishOnCloseSystemDialogs="true"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationListenerController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationListenerController.java
index fac9e98a6caf..6799450079af 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationListenerController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NotificationListenerController.java
@@ -14,6 +14,8 @@
package com.android.systemui.plugins;
+import android.app.NotificationChannel;
+import android.os.UserHandle;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
@@ -30,13 +32,32 @@ public interface NotificationListenerController extends Plugin {
void onListenerConnected(NotificationProvider provider);
+ /**
+ * @return whether plugin wants to skip the default callbacks.
+ */
default boolean onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
return false;
}
+
+ /**
+ * @return whether plugin wants to skip the default callbacks.
+ */
default boolean onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
return false;
}
+ /**
+ * Called when a notification channel is modified.
+ * @param modificationType One of {@link #NOTIFICATION_CHANNEL_OR_GROUP_ADDED},
+ * {@link #NOTIFICATION_CHANNEL_OR_GROUP_UPDATED},
+ * {@link #NOTIFICATION_CHANNEL_OR_GROUP_DELETED}.
+ * @return whether a plugin wants to skip the default callbacks.
+ */
+ default boolean onNotificationChannelModified(
+ String pkgName, UserHandle user, NotificationChannel channel, int modificationType) {
+ return false;
+ }
+
default StatusBarNotification[] getActiveNotifications(
StatusBarNotification[] activeNotifications) {
return activeNotifications;
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 46079810aee4..09488718fd1a 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -72,7 +72,7 @@
<string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"Introduce o PIN da SIM para \"<xliff:g id="CARRIER">%1$s</xliff:g>\"."</string>
<string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g> Desactiva a eSIM para usar o dispositivo sen o servizo móbil."</string>
<string name="kg_pin_instructions" msgid="822353548385014361">"Introduce o PIN"</string>
- <string name="kg_password_instructions" msgid="324455062831719903">"Insire o teu contrasinal"</string>
+ <string name="kg_password_instructions" msgid="324455062831719903">"Escribe o teu contrasinal"</string>
<string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"Agora a tarxeta SIM está desactivada. Introduce o código PUK para continuar. Ponte en contacto co operador para obter máis información."</string>
<string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"Agora a SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" está desactivada. Introduce o código PUK para continuar. Ponte en contacto co operador para obter máis información."</string>
<string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Introduce o código PIN desexado"</string>
diff --git a/packages/CarSystemUI/res/anim/car_user_switcher_open_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml
index 80b38b388aed..257bf35c8e76 100644
--- a/packages/CarSystemUI/res/anim/car_user_switcher_open_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2018 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,9 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<animator xmlns:android="http://schemas.android.com/apk/res/android"
- android:duration="200"
- android:valueType="intType"
- android:valueFrom="0"
- android:valueTo="@dimen/car_user_switcher_container_height"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="100" />
diff --git a/packages/CarSystemUI/res/anim/car_user_switcher_close_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml
index 6f12338d8db8..e032008b3750 100644
--- a/packages/CarSystemUI/res/anim/car_user_switcher_close_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2018 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,9 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<animator xmlns:android="http://schemas.android.com/apk/res/android"
- android:duration="133"
- android:valueType="intType"
- android:valueFrom="@dimen/car_user_switcher_container_height"
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
android:valueTo="0"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="100" />
diff --git a/packages/CarSystemUI/res/anim/car_user_switcher_close_pages_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
index dec5c05dbce8..257bf35c8e76 100644
--- a/packages/CarSystemUI/res/anim/car_user_switcher_close_pages_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2018 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,12 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android">
- <objectAnimator
- android:duration="83"
- android:propertyName="alpha"
- android:valueType="floatType"
- android:valueFrom="1"
- android:valueTo="0" />
-</set> \ No newline at end of file
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
+ android:valueTo="1"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
new file mode 100644
index 000000000000..e032008b3750
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:propertyName="alpha"
+ android:valueTo="0"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="100" />
diff --git a/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml b/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml
new file mode 100644
index 000000000000..ca56ec17014b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/brightness_progress_drawable_thick.xml
@@ -0,0 +1,36 @@
+<?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">
+ <item android:id="@android:id/progress"
+ android:gravity="center_vertical|fill_horizontal">
+ <clip
+ android:drawable="@drawable/brightness_progress_full_drawable"
+ android:clipOrientation="horizontal"
+ android:gravity="left"
+ />
+ </item>
+ <item android:id="@android:id/background"
+ android:gravity="center_vertical|fill_horizontal">
+ <shape android:shape="rectangle"
+ android:tint="?android:attr/colorControlNormal">
+ <size android:height="48dp" />
+ <solid android:color="@color/white_disabled" />
+ <corners android:radius="24dp" />
+ </shape>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/CarSystemUI/samples/sample1/rro/res/values/colors.xml b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
index c32d638681a2..a38b8b4e62db 100644
--- a/packages/CarSystemUI/samples/sample1/rro/res/values/colors.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
@@ -14,7 +14,11 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <color name="car_nav_icon_fill_color">#8F8F8F</color>
- <color name="car_nav_icon_fill_color_selected">#FFFFFF</color>
-</resources>
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle"
+ android:tint="?android:attr/colorControlActivated">
+ <size android:height="48dp" />
+ <solid android:color="@android:color/white" />
+ <corners android:radius="24dp"/>
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/bubble_dismiss_circle.xml b/packages/SystemUI/res/drawable/bubble_dismiss_circle.xml
deleted file mode 100644
index 8c7e82f82186..000000000000
--- a/packages/SystemUI/res/drawable/bubble_dismiss_circle.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<!--
- The transparent circle outline that encircles the bubbles when they're in the dismiss target.
--->
-<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/bubble_dismiss_icon.xml b/packages/SystemUI/res/drawable/bubble_dismiss_icon.xml
deleted file mode 100644
index 5c8de581f8d1..000000000000
--- a/packages/SystemUI/res/drawable/bubble_dismiss_icon.xml
+++ /dev/null
@@ -1,26 +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.
--->
-<!-- The 'X' bubble dismiss icon. This is just ic_close with a stroke. -->
-<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>
diff --git a/packages/CarSystemUI/res/anim/car_user_switcher_close_name_animation.xml b/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
index adc1f720e91b..6a0695e817c7 100644
--- a/packages/CarSystemUI/res/anim/car_user_switcher_close_name_animation.xml
+++ b/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2018 The Android Open Source Project
+<?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.
@@ -12,12 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android">
-
- <objectAnimator
- android:duration="83"
- android:propertyName="alpha"
- android:valueType="floatType"
- android:valueFrom="0"
- android:valueTo="1" />
-</set> \ No newline at end of file
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@color/transparent" />
+ <item android:drawable="@drawable/floating_dismiss_gradient" />
+</transition> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_brightness.xml b/packages/SystemUI/res/drawable/ic_brightness.xml
new file mode 100644
index 000000000000..f44333236a12
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_brightness.xml
@@ -0,0 +1,29 @@
+<!--
+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.0"
+ android:viewportHeight="24.0">
+
+ <path
+ android:pathData="M18,14.48V18h-3.52L12,20.48L9.52,18H6v-3.52L3.52,12L6,9.52V6h3.52L12,3.52L14.48,6H18v3.52L20.48,12L18,14.48z"
+ />
+
+ <path
+ android:pathData=" M20,8.69 V4h-4.69L12,0.69L8.69,4H4v4.69L0.69,12L4,15.31V20h4.69L12,23.31L15.31,20H20v-4.69L23.31,12L20,8.69z M18,14.48V18h-3.52L12,20.48L9.52,18H6v-3.52L3.52,12L6,9.52V6h3.52L12,3.52L14.48,6H18v3.52L20.48,12L18,14.48z M12,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S14.76,7 12,7z"
+ android:fillColor="#FFFFFF" />
+</vector>
diff --git a/packages/CarSystemUI/res/drawable/stat_sys_signal_null.xml b/packages/SystemUI/res/drawable/ic_pause_white.xml
index 2b487f9e3ebd..5b65f100490c 100644
--- a/packages/CarSystemUI/res/drawable/stat_sys_signal_null.xml
+++ b/packages/SystemUI/res/drawable/ic_pause_white.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,12 +14,12 @@ Copyright (C) 2014 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
<path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M2.000000,22.000000l20.000000,0.000000L22.000000,2.000000L2.000000,22.000000zM20.000000,20.000000L6.800000,20.000000L20.000000,6.800000L20.000000,20.000000z"/>
+ android:fillColor="#FFFFFF"
+ android:pathData="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_create_bubble.xml b/packages/SystemUI/res/drawable/ic_play_arrow_white.xml
index 4abbc8179b4d..ddc9e8dd17a0 100644
--- a/packages/SystemUI/res/drawable/ic_create_bubble.xml
+++ b/packages/SystemUI/res/drawable/ic_play_arrow_white.xml
@@ -1,8 +1,7 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2019 The Android Open Source Project
+Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -15,11 +14,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
+ android:width="24dp"
+ android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
- <path
- android:fillColor="#FF000000"
- android:pathData="M23,5v8h-2V5H3v14h10v2v0H3c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h18C22.1,3 23,3.9 23,5zM10,8v2.59L5.71,6.29L4.29,7.71L8.59,12H6v2h6V8H10zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M8 5v14l11-7z" />
</vector>
diff --git a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_home.xml b/packages/SystemUI/res/drawable/ic_screenshot_scroll.xml
index c78f0edd5594..c260ba9bf421 100644
--- a/packages/CarSystemUI/samples/sample3/rro/res/drawable/car_ic_home.xml
+++ b/packages/SystemUI/res/drawable/ic_screenshot_scroll.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -14,12 +13,13 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+<!-- ic_unfold_more_24px.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/system_bar_icon_drawing_size"
- android:height="@dimen/system_bar_icon_drawing_size"
+ android:width="24dp"
+ android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"
- android:fillColor="@color/car_nav_icon_fill_color" />
-</vector> \ No newline at end of file
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,5.83L15.17,9l1.41,-1.41L12,3 7.41,7.59 8.83,9 12,5.83zM12,18.17L8.83,15l-1.41,1.41L12,21l4.59,-4.59L15.17,15 12,18.17z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_stop_bubble.xml b/packages/SystemUI/res/drawable/pip_icon.xml
index 6cf67a77ff55..bd92ccd2e6e3 100644
--- a/packages/SystemUI/res/drawable/ic_stop_bubble.xml
+++ b/packages/SystemUI/res/drawable/pip_icon.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2020 The Android Open Source Project
+Copyright (C) 2017 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -15,11 +15,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="20dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="#FF000000"
- android:pathData="M11.29,14.71L7,10.41V13H5V7h6v2H8.41l4.29,4.29L11.29,14.71zM21,3H3C1.9,3 1,3.9 1,5v14c0,1.1 0.9,2 2,2h10v0v-2H3V5h18v8h2V5C23,3.9 22.1,3 21,3zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
-</vector>
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="25"
+ android:viewportHeight="25">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M19,7h-8v6h8L19,7zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,1.98 2,1.98h18c1.1,0 2,-0.88 2,-1.98L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.98h18v14.03z"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_resize_handle.xml b/packages/SystemUI/res/drawable/pip_resize_handle.xml
new file mode 100644
index 000000000000..0a8cbc429dd8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/pip_resize_handle.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="12.0dp"
+ android:height="12.0dp"
+ android:viewportWidth="12"
+ android:viewportHeight="12">
+ <group
+ android:translateX="12"
+ android:rotation="90">
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M3.41421 0L2 1.41422L10.4853 9.8995L11.8995 8.48528L3.41421 0ZM2.41421 4.24268L1 5.65689L6.65685 11.3137L8.07107 9.89953L2.41421 4.24268Z" />
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/layout-land/global_screenshot_preview.xml b/packages/SystemUI/res/layout-land/global_screenshot_preview.xml
index 040303a9b963..71b414fd419e 100644
--- a/packages/SystemUI/res/layout-land/global_screenshot_preview.xml
+++ b/packages/SystemUI/res/layout-land/global_screenshot_preview.xml
@@ -28,6 +28,6 @@
android:visibility="gone"
android:background="@drawable/screenshot_rounded_corners"
android:adjustViewBounds="true"
- android:contentDescription="@string/screenshot_edit"
+ android:contentDescription="@string/screenshot_edit_label"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
index a87c7b3fa927..aed067c30253 100644
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml
@@ -37,13 +37,32 @@
android:gravity="@integer/biometric_dialog_text_gravity"
style="@style/TextAppearance.AuthCredential.Description"/>
- <ImageView
- android:id="@+id/biometric_icon"
- android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
- android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
- android:paddingTop="48dp"
- android:layout_gravity="center_horizontal"
- android:scaleType="fitXY" />
+ <Space android:id="@+id/space_above_icon"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:visibility="visible" />
+
+ <!-- Use a frame layout since certain biometrics (such as UDFPS) require the icon to be centered
+ within a certain area on the display. This makes it easy to 1) guarantee max size, and
+ 2) center the icon within the reserved area. -->
+ <FrameLayout android:id="@+id/biometric_icon_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal">
+ <ImageView
+ android:id="@+id/biometric_icon"
+ android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
+ android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
+ android:layout_gravity="center"
+ android:scaleType="fitXY" />
+ </FrameLayout>
+
+ <!-- For sensors such as UDFPS, this view is used during custom measurement/layoutto add extra
+ padding so that the biometric icon is always in the right physical position. -->
+ <Space android:id="@+id/space_below_icon"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:visibility="gone" />
<TextView
android:id="@+id/indicator"
@@ -54,6 +73,8 @@
android:textSize="12sp"
android:gravity="center_horizontal"
android:accessibilityLiveRegion="polite"
+ android:singleLine="true"
+ android:ellipsize="marquee"
android:textColor="@color/biometric_dialog_gray"/>
<LinearLayout
@@ -67,7 +88,8 @@
android:layout_width="8dp"
android:layout_height="match_parent"
android:visibility="visible" />
- <!-- Negative Button -->
+
+ <!-- Negative Button, reserved for app -->
<Button android:id="@+id/button_negative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -76,13 +98,32 @@
android:ellipsize="end"
android:maxLines="2"
android:maxWidth="@dimen/biometric_dialog_button_negative_max_width"/>
+ <!-- Cancel Button, replaces negative button when biometric is accepted -->
+ <Button android:id="@+id/button_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ android:layout_gravity="center_vertical"
+ android:maxWidth="@dimen/biometric_dialog_button_negative_max_width"
+ android:text="@string/cancel"
+ android:visibility="gone"/>
+ <!-- "Use Credential" Button, replaces if device credential is allowed -->
+ <Button android:id="@+id/button_use_credential"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ android:layout_gravity="center_vertical"
+ android:maxWidth="@dimen/biometric_dialog_button_negative_max_width"
+ android:visibility="gone"/>
+
<Space android:id="@+id/middleSpacer"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:visibility="visible"/>
+
<!-- Positive Button -->
- <Button android:id="@+id/button_positive"
+ <Button android:id="@+id/button_confirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@*android:style/Widget.DeviceDefault.Button.Colored"
@@ -103,6 +144,7 @@
android:maxWidth="@dimen/biometric_dialog_button_positive_max_width"
android:text="@string/biometric_dialog_try_again"
android:visibility="gone"/>
+
<Space android:id="@+id/rightSpacer"
android:layout_width="8dp"
android:layout_height="match_parent"
diff --git a/packages/CarSystemUI/tests/res/layout/overlay_view_controller_stub.xml b/packages/SystemUI/res/layout/auth_biometric_udfps_view.xml
index 5e5efe7614fc..238288eb9f69 100644
--- a/packages/CarSystemUI/tests/res/layout/overlay_view_controller_stub.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_udfps_view.xml
@@ -14,9 +14,13 @@
~ limitations under the License.
-->
-<LinearLayout
+<com.android.systemui.biometrics.AuthBiometricUdfpsView
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/contents"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/overlay_view_controller_test">
-</LinearLayout> \ No newline at end of file
+ android:orientation="vertical">
+
+ <include layout="@layout/auth_biometric_contents"/>
+
+</com.android.systemui.biometrics.AuthBiometricUdfpsView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/brightness_mirror.xml b/packages/SystemUI/res/layout/brightness_mirror.xml
index e3440b53d215..8b47ab915fb4 100644
--- a/packages/SystemUI/res/layout/brightness_mirror.xml
+++ b/packages/SystemUI/res/layout/brightness_mirror.xml
@@ -21,12 +21,5 @@
android:layout_height="@dimen/brightness_mirror_height"
android:layout_gravity="@integer/notification_panel_layout_gravity"
android:visibility="invisible">
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginLeft="@dimen/notification_side_paddings"
- android:layout_marginRight="@dimen/notification_side_paddings"
- android:background="@drawable/brightness_mirror_background">
- <include layout="@layout/quick_settings_brightness_dialog" />
- </FrameLayout>
+
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 1b5f9c1ced8f..6c20c1e95c6d 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -46,7 +46,7 @@
android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
android:elevation="7dp"
android:visibility="gone"
- android:contentDescription="@string/screenshot_dismiss_ui_description">
+ android:contentDescription="@string/screenshot_dismiss_description">
<ImageView
android:id="@+id/global_screenshot_dismiss_image"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/global_screenshot_preview.xml b/packages/SystemUI/res/layout/global_screenshot_preview.xml
index c745854b1c6c..5262407ffef9 100644
--- a/packages/SystemUI/res/layout/global_screenshot_preview.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_preview.xml
@@ -28,6 +28,6 @@
android:visibility="gone"
android:background="@drawable/screenshot_rounded_corners"
android:adjustViewBounds="true"
- android:contentDescription="@string/screenshot_edit"
+ android:contentDescription="@string/screenshot_edit_label"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml
index 26edf3afc0c5..096ec7ddd004 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_static.xml
@@ -56,6 +56,9 @@
android:id="@+id/screenshot_share_chip"/>
<include layout="@layout/global_screenshot_action_chip"
android:id="@+id/screenshot_edit_chip"/>
+ <include layout="@layout/global_screenshot_action_chip"
+ android:id="@+id/screenshot_scroll_chip"
+ android:visibility="gone" />
</LinearLayout>
</HorizontalScrollView>
<include layout="@layout/global_screenshot_preview"/>
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml
new file mode 100644
index 000000000000..2b33e17a5fbd
--- /dev/null
+++ b/packages/SystemUI/res/layout/pip_menu_activity.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- Menu layout -->
+ <FrameLayout
+ android:id="@+id/menu_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:forceHasOverlappingRendering="false"
+ android:accessibilityTraversalAfter="@id/dismiss">
+
+ <!-- The margins for this container is calculated in the code depending on whether the
+ actions_container is visible. -->
+ <FrameLayout
+ android:id="@+id/expand_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageButton
+ android:id="@+id/expand_button"
+ android:layout_width="60dp"
+ android:layout_height="60dp"
+ android:layout_gravity="center"
+ android:contentDescription="@string/pip_phone_expand"
+ android:padding="10dp"
+ android:src="@drawable/pip_expand"
+ android:background="?android:selectableItemBackgroundBorderless" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/actions_container"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/pip_action_size"
+ android:layout_gravity="bottom"
+ android:visibility="invisible">
+ <LinearLayout
+ android:id="@+id/actions_group"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal"
+ android:orientation="horizontal"
+ android:divider="@android:color/transparent"
+ android:showDividers="middle" />
+ </FrameLayout>
+ </FrameLayout>
+
+ <ImageButton
+ android:id="@+id/settings"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:layout_gravity="top|start"
+ android:padding="@dimen/pip_action_padding"
+ android:contentDescription="@string/pip_phone_settings"
+ android:src="@drawable/ic_settings"
+ android:background="?android:selectableItemBackgroundBorderless" />
+
+ <ImageButton
+ android:id="@+id/dismiss"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:layout_gravity="top|end"
+ android:padding="@dimen/pip_action_padding"
+ android:contentDescription="@string/pip_phone_close"
+ android:src="@drawable/ic_close_white"
+ android:background="?android:selectableItemBackgroundBorderless" />
+
+ <!--TODO (b/156917828): Add content description for a11y purposes?-->
+ <ImageButton
+ android:id="@+id/resize_handle"
+ android:layout_width="@dimen/pip_resize_handle_size"
+ android:layout_height="@dimen/pip_resize_handle_size"
+ android:layout_gravity="top|start"
+ android:layout_margin="@dimen/pip_resize_handle_margin"
+ android:src="@drawable/pip_resize_handle"
+ android:background="?android:selectableItemBackgroundBorderless" />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 4527c6c793d5..89bf12d70b84 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -29,25 +29,6 @@
android:elevation="4dp"
android:background="@drawable/qs_background_primary" />
- <!-- Black part behind the status bar -->
- <View
- android:id="@+id/quick_settings_status_bar_background"
- android:layout_width="match_parent"
- android:layout_height="@*android:dimen/quick_qs_offset_height"
- android:clipToPadding="false"
- android:clipChildren="false"
- android:background="#ff000000" />
-
- <!-- Gradient view behind QS -->
- <View
- android:id="@+id/quick_settings_gradient_view"
- android:layout_width="match_parent"
- android:layout_height="126dp"
- android:layout_marginTop="@*android:dimen/quick_qs_offset_height"
- android:clipToPadding="false"
- android:clipChildren="false"
- android:background="@drawable/qs_bg_gradient" />
-
<com.android.systemui.qs.NonInterceptingScrollView
android:id="@+id/expanded_qs_scroll_view"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 12127f529054..9cc09aa42f40 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -20,14 +20,62 @@
android:layout_gravity="center_vertical"
style="@style/BrightnessDialogContainer">
- <com.android.systemui.settings.ToggleSliderView
+ <com.android.systemui.settings.brightness.BrightnessSliderView
android:id="@+id/brightness_slider"
android:layout_width="0dp"
- android:layout_height="48dp"
+ android:layout_height="@dimen/brightness_mirror_height"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:contentDescription="@string/accessibility_brightness"
android:importantForAccessibility="no"
- systemui:text="@string/status_bar_settings_auto_brightness_label" />
+ systemui:text="@string/status_bar_settings_auto_brightness_label" >
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <CheckBox
+ android:id="@+id/toggle"
+ android:layout_width="48dp"
+ android:layout_height="0dp"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:button="@null"
+ android:background="@*android:drawable/switch_track_material"
+ android:visibility="gone"
+ />
+ <com.android.systemui.settings.brightness.ToggleSeekBar
+ android:id="@+id/slider"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_toEndOf="@id/toggle"
+ android:layout_centerVertical="true"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentEnd="true"
+ android:paddingStart="20dp"
+ android:paddingEnd="20dp"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:thumb="@drawable/ic_brightness_thumb"
+ android:progressDrawable="@drawable/brightness_progress_drawable"
+ android:splitTrack="false"
+ />
+ <TextView
+ android:id="@+id/label"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_alignStart="@id/toggle"
+ android:layout_alignEnd="@id/toggle"
+ android:layout_centerVertical="true"
+ android:gravity="center"
+ android:paddingTop="26dp"
+ android:textColor="#666666"
+ android:textSize="12sp"
+ android:visibility="gone"
+ />
+
+ </RelativeLayout>
+ </com.android.systemui.settings.brightness.BrightnessSliderView>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog_thick.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog_thick.xml
new file mode 100644
index 000000000000..e08b44af1068
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog_thick.xml
@@ -0,0 +1,53 @@
+<?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_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_gravity="center"
+ style="@style/BrightnessDialogContainer">
+
+ <com.android.systemui.settings.brightness.BrightnessSliderView
+ android:id="@+id/brightness_slider"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/brightness_mirror_height"
+ android:layout_gravity="center_vertical"
+ android:contentDescription="@string/accessibility_brightness"
+ android:importantForAccessibility="no" >
+
+ <com.android.systemui.settings.brightness.ToggleSeekBar
+ android:id="@+id/slider"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:minHeight="48dp"
+ android:thumb="@null"
+ android:background="@null"
+ android:progressDrawable="@drawable/brightness_progress_drawable_thick"
+ android:splitTrack="false"
+ />
+
+ <ImageView
+ android:id="@+id/image"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginLeft="48dp"
+ android:layout_gravity="center_vertical"
+ android:src="@drawable/ic_brightness"
+ android:tint="?android:attr/textColorTertiary"
+ android:visibility="visible"
+ />
+ </com.android.systemui.settings.brightness.BrightnessSliderView>
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index 3c7480181877..f663ab4eb4aa 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -43,8 +43,7 @@
android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
- systemui:showDark="false" />
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock" />
</LinearLayout>
<android.widget.Space
diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
deleted file mode 100644
index 942f3dd03a8d..000000000000
--- a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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:background="@drawable/status_bar_closed_default_background" -->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <CheckBox
- android:id="@+id/toggle"
- android:layout_width="48dp"
- android:layout_height="0dp"
- android:layout_alignParentStart="true"
- android:layout_alignParentTop="true"
- android:layout_alignParentBottom="true"
- android:button="@null"
- android:background="@*android:drawable/switch_track_material"
- android:visibility="gone"
- />
- <com.android.systemui.settings.ToggleSeekBar
- android:id="@+id/slider"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_toEndOf="@id/toggle"
- android:layout_centerVertical="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentEnd="true"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
- android:thumb="@drawable/ic_brightness_thumb"
- android:progressDrawable="@drawable/brightness_progress_drawable"
- android:splitTrack="false"
- />
- <TextView
- android:id="@+id/label"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_alignStart="@id/toggle"
- android:layout_alignEnd="@id/toggle"
- android:layout_centerVertical="true"
- android:gravity="center"
- android:paddingTop="26dp"
- android:textColor="#666666"
- android:textSize="12sp"
- android:visibility="gone"
- />
-</merge>
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index d322e0905ef6..0ba546eff689 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -43,6 +43,12 @@
android:visibility="invisible" />
</com.android.systemui.statusbar.BackDropView>
+ <com.android.systemui.statusbar.LightRevealScrim
+ android:id="@+id/light_reveal_scrim"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone" />
+
<com.android.systemui.statusbar.ScrimView
android:id="@+id/scrim_behind"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 4042ef91585a..1fab4780a4c1 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Probeer weer skermkiekie neem"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Kan weens beperkte bergingspasie nie skermkiekie stoor nie"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Die program of jou organisasie laat nie toe dat skermkiekies geneem word nie"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Wysig skermkiekie"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Maak skermkiekie toe"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Wysig"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Wysig skermkiekie"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Rollees"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Rollees skermskoot"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Maak skermkiekie toe"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Skermkiekievoorskou"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skermopnemer"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Verwerk tans skermopname"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Battery, twee stawe."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Battery, drie stawe."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Battery vol."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batterypersentasie is onbekend."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Geen foon nie."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Foon, een staaf."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Foon, twee stawe."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Kennisgewing is toegemaak."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Borrel is toegemaak."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Kennisgewingskerm."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Vinnige instellings."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Sluitskerm."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Hou aan om kennisgewings van hierdie program af te wys?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Stil"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Verstek"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Borrel"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Outomaties"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Geen klank of vibrasie nie"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Geen klank of vibrasie nie en verskyn laer in gespreksafdeling"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Instellings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie gesprekskenmerke nie"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Geen onlangse borrels nie"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Onlangse borrels en borrels wat toegemaak is, sal hier verskyn"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Hierdie kennisgewings kan nie gewysig word nie."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Hierdie groep kennisgewings kan nie hier opgestel word nie"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Instaanbediener-kennisgewing"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Toesteldienste"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Titelloos"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tik om hierdie program te herbegin en maak volskerm oop."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Instellings vir <xliff:g id="APP_NAME">%1$s</xliff:g>-borrels"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Oorloop"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Voeg terug op stapel"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Bestuur"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> vanaf <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g> en <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> meer af"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Beweeg"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Beweeg na links bo"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Beweeg na regs bo"</string>
- <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="1314082410868930066">"Maak borrel toe"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Moenie dat gesprek \'n borrel word nie"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Klets met borrels"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nuwe gesprekke verskyn as swerwende ikone, of borrels Tik op borrel om dit oop te maak. Sleep om dit te skuif."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Beheer borrels enige tyd"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tik op Bestuur om borrels vanaf hierdie program af te skakel"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Het dit"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-instellings"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bind nuwe toestel saam"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Bounommer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Bounommer is na knipbord gekopieer."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kon nie jou batterymeter lees nie"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tik vir meer inligting"</string>
</resources>
diff --git a/packages/SystemUI/res/values-af/strings_tv.xml b/packages/SystemUI/res/values-af/strings_tv.xml
index f277529397f6..eb6316502e2d 100644
--- a/packages/SystemUI/res/values-af/strings_tv.xml
+++ b/packages/SystemUI/res/values-af/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofoon aktief"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s het toegang tot jou mikrofoon"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN is gekoppel"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN is ontkoppel"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index e8a8a0d359bc..5153904f3e02 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ቅጽበታዊ ገጽ ዕይታን እንደገና ማንሳት ይሞክሩ"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"ባለው ውሱን የማከማቻ ቦታ ምክንያት ቅጽበታዊ ገጽ ዕይታን ማስቀመጥ አይችልም"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ቅጽበታዊ ገጽ እይታዎችን ማንሳት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"ቅጽበታዊ ገጽ ዕይታን አርትዕ ያድርጉ"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ቅጽበታዊ ገጽ እይታን አሰናብት"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"አርትዕ ያድርጉ"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"ቅጽበታዊ ገጽ ዕይታን አርትዕ ያድርጉ"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"ሸብልል"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"ቅጽበታዊ ገጽ ዕይታን ይሸብልሉ"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ቅጽበታዊ ገጽ ዕይታን አሰናብት"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"የቅጽበታዊ ገጽ ዕይታ ቅድመ-ዕይታ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"የማያ መቅጃ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"የማያ ገጽ ቀረጻን በማሰናዳት ላይ"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ባትሪ ሁለት አሞሌዎች።"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ባትሪ ሦስት አሞሌዎች።"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ባትሪ ሙሉ ነው።"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"የባትሪ መቶኛ አይታወቅም።"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"ምንም ስልክ የለም።"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"የስልክ አንድ አሞሌ"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"የስልክ ሁለት አሞሌ"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ማሳወቂያ ተወግዷል።"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"አረፋ ተሰናብቷል።"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"የማሳወቂያ ጥላ።"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ፈጣን ቅንብሮች።"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ማያ ገጽ ቆልፍ።"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"ከዚህ መተግበሪያ ማሳወቂያዎችን ማሳየት ይቀጥል?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ፀጥ ያለ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ነባሪ"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"አረፋ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ራስ-ሰር"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ምንም ድምጽ ወይም ንዝረት የለም"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ምንም ድምጽ ወይም ንዝረት የለም እና በውይይት ክፍል ላይ አይታይም"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ቅንብሮች"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ቅድሚያ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> የውይይት ባህሪያትን አይደግፍም"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ምንም የቅርብ ጊዜ አረፋዎች የሉም"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"የቅርብ ጊዜ አረፋዎች እና የተሰናበቱ አረፋዎች እዚህ ብቅ ይላሉ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"እነዚህ ማሳወቂያዎች ሊሻሻሉ አይችሉም።"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"የማሳወቂያዎች ይህ ቡድን እዚህ ላይ ሊዋቀር አይችልም"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ተኪ ማሳወቂያ"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"የመሣሪያ አገልግሎቶች"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ርዕስ የለም"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ይህን መተግበሪያ እንደገና ለማስጀመር መታ ያድርጉ እና ወደ ሙሉ ማያ ገጽ ይሂዱ።"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"ቅንብሮች ለ <xliff:g id="APP_NAME">%1$s</xliff:g> አረፋዎች"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ትርፍ ፍሰት"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ወደ ቁልል መልሰው ያክሉ"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"ያቀናብሩ"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ከ<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ከ <xliff:g id="APP_NAME">%2$s</xliff:g> እና <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ተጨማሪ"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"አንቀሳቅስ"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ወደ ላይኛው ግራ አንቀሳቅስ"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ወደ ላይኛው ቀኝ አንቀሳቅስ"</string>
- <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="1314082410868930066">"አረፋን አሰናብት"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ውይይቶችን በአረፋ አታሳይ"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"አረፋዎችን በመጠቀም ይወያዩ"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"አዲስ ውይይቶች እንደ ተንሳፋፊ አዶዎች ወይም አረፋዎች ሆነው ይታያሉ። አረፋን ለመክፈት መታ ያድርጉ። ለመውሰድ ይጎትቱት።"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"በማንኛውም ጊዜ አረፋዎችን ይቆጣጠሩ"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"የዚህ መተግበሪያ አረፋዎችን ለማጥፋት አቀናብርን መታ ያድርጉ"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ገባኝ"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"የ<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ቅንብሮች"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"አዲስ መሣሪያ ያጣምሩ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"የግንብ ቁጥር"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"የገንባ ቁጥር ወደ ቅንጥብ ሰሌዳ ተቀድቷል።"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"የባትሪ መለኪያዎን የማንበብ ችግር"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ለበለጠ መረጃ መታ ያድርጉ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings_tv.xml b/packages/SystemUI/res/values-am/strings_tv.xml
index d9ec459d06f7..3ba5a62a52d6 100644
--- a/packages/SystemUI/res/values-am/strings_tv.xml
+++ b/packages/SystemUI/res/values-am/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"ማይክራፎን ንቁ ነው"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s የእርስዎን ማይክራፎን ደርሶበታል"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ተያይዟል"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ተቋርቷል"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"በ<xliff:g id="VPN_APP">%1$s</xliff:g> በኩል"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 83940bff0adc..f6a1cf5e711b 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"جرّب أخذ لقطة الشاشة مرة أخرى"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"يتعذر حفظ لقطة الشاشة لأن مساحة التخزين المتاحة محدودة."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"يحظر التطبيق أو تحظر مؤسستك التقاط لقطات شاشة"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"تعديل لقطة الشاشة"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"إغلاق لقطة الشاشة"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"تعديل"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"تعديل لقطة الشاشة"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"الانتقال خلال الشاشة"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"لقطة شاشة موصولة"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"إغلاق لقطة الشاشة"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"معاينة لقطة الشاشة"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"مسجّل الشاشة"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"جارٍ معالجة تسجيل الشاشة"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"إشارة البطارية تتكون من شريطين."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"إشارة البطارية تتكون من ثلاثة أشرطة."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"إشارة البطارية كاملة."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"نسبة شحن البطارية غير معروفة."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"ليست هناك إشارة بالهاتف."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"إشارة الهاتف تتكون من شريط واحد."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"إشارة الهاتف تتكون من شريطين."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"تم تجاهل الإشعار."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"تم إغلاق الفقاعة."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"مركز الإشعارات."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"الإعدادات السريعة."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"شاشة القفل."</string>
@@ -726,7 +727,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"هل تريد الاستمرار في تلقي إشعارات من هذا التطبيق؟"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"صامتة"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"تلقائية"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"فقاعة"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"تلقائي"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"بدون صوت أو اهتزاز"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"بدون صوت أو اهتزاز وتظهر في موضع أسفل في قسم المحادثات"</string>
@@ -738,8 +738,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"الإعدادات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"الأولوية"</string>
<string name="no_shortcut" msgid="8257177117568230126">"لا يدعم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> ميزات المحادثات."</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ليس هناك فقاعات محادثات"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ستظهر هنا أحدث فقاعات المحادثات وفقاعات المحادثات التي تم إغلاقها."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"يتعذّر تعديل هذه الإشعارات."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"يتعذّر ضبط مجموعة الإشعارات هذه هنا."</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"إشعار مستند إلى خادم وكيل"</string>
@@ -1006,25 +1004,7 @@
<string name="device_services" msgid="1549944177856658705">"خدمات الأجهزة"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"بلا عنوان"</string>
<string name="restart_button_description" msgid="6916116576177456480">"انقر لإعادة تشغيل هذا التطبيق والانتقال إلى وضع ملء الشاشة."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"إعدادات فقاعات المحادثات على <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"القائمة الكاملة"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"إضافة دعم إلى الحزم"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"إدارة"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> من <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> من <xliff:g id="APP_NAME">%2$s</xliff:g> و<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> أيضًا"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"نقل"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"نقل إلى أعلى يمين الشاشة"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"الانتقال إلى أعلى اليسار"</string>
- <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="1314082410868930066">"إغلاق فقاعة المحادثة"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"عدم عرض المحادثة كفقاعة محادثة"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"الدردشة باستخدام فقاعات المحادثات"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"تظهر المحادثات الجديدة كرموز عائمة أو كفقاعات. انقر لفتح فقاعة المحادثة، واسحبها لتحريكها."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"التحكّم في فقاعات المحادثات في أي وقت"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"انقر على \"إدارة\" لإيقاف فقاعات المحادثات من هذا التطبيق."</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"حسنًا"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"إعدادات <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1118,8 +1098,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"إقران جهاز جديد"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"رقم الإصدار"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"تم نسخ رقم الإصدار إلى الحافظة."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"حدثت مشكلة أثناء قراءة مقياس مستوى شحن البطارية."</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"انقر للحصول على مزيد من المعلومات."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings_tv.xml b/packages/SystemUI/res/values-ar/strings_tv.xml
index c29d804f841f..15ccb94a04a8 100644
--- a/packages/SystemUI/res/values-ar/strings_tv.xml
+++ b/packages/SystemUI/res/values-ar/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"الميكروفون نشط"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"‏تمكن %1$s من الوصول إلى الميكروفون الخاص بك."</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"‏الشبكة الافتراضية الخاصة (VPN) متصلة."</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"‏الشبكة الافتراضية الخاصة (VPN) غير متصلة."</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"عبر <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 5444b53bd1df..b84f40972af5 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"স্ক্ৰীণশ্বট আকৌ ল\'বলৈ চেষ্টা কৰক"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"সঞ্চয়াগাৰত সীমিত খালী ঠাই থকাৰ বাবে স্ক্ৰীণশ্বট ছেভ কৰিব পৰা নগ\'ল"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"এপটোৱে বা আপোনাৰ প্ৰতিষ্ঠানে স্ক্ৰীণশ্বট ল\'বলৈ অনুমতি নিদিয়ে"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"স্ক্ৰীনশ্বট সম্পাদনা কৰক"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"স্ক্ৰীনশ্বট অগ্ৰাহ্য কৰক"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"সম্পাদনা কৰক"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"স্ক্ৰীনশ্বট সম্পাদনা কৰক"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"স্ক্ৰ’ল কৰক"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"স্ক্ৰীনশ্বট স্ক্ৰ’ল কৰক"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"স্ক্ৰীনশ্বট অগ্ৰাহ্য কৰক"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"স্ক্ৰীনশ্বটৰ পূৰ্বদৰ্শন"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"স্ক্ৰীন ৰেকৰ্ডাৰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রীন ৰেকৰ্ডিঙৰ প্ৰক্ৰিয়াকৰণ হৈ আছে"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"বেটাৰিৰ দুডাল দণ্ড।"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"বেটাৰিৰ তিনিডাল দণ্ড।"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"বেটাৰি পূৰাকৈ চ্চাৰ্জ হৈছে।"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"বেটাৰীৰ চাৰ্জৰ শতাংশ অজ্ঞাত।"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"ফ\'নত ছিগনেল নাই৷"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ফ\'ন ছিগনেলৰ এডাল দণ্ড।"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ফ\'ন ছিগনেলৰ দুডাল দণ্ড।"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"জাননী অগ্ৰাহ্য কৰা হৈছে।"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"বাবল অগ্ৰাহ্য কৰা হৈছে"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"জাননী পেনেল।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ক্ষিপ্ৰ ছেটিংসমূহ।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"বন্ধ স্ক্ৰীণ।"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"এই এপটোৰ জাননী দেখুওৱাই থাকিব লাগিবনে?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"নীৰৱ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ডিফ’ল্ট"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"বাবল"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"স্বয়ংক্ৰিয়"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"কোনো ধ্বনি অথবা কম্পন নাই"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"কোনো ধ্বনি অথবা কম্পন নাই আৰু বাৰ্তালাপ শাখাটোৰ তলৰ অংশত দেখা পোৱা যায়"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ছেটিংসমূহ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্ৰাধিকাৰ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপৰ সুবিধাসমূহ সমৰ্থন নকৰে"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"কোনো শেহতীয়া bubbles নাই"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"শেহতীয়া bubbles আৰু অগ্ৰাহ্য কৰা bubbles ইয়াত প্ৰদর্শিত হ\'ব"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"এই ধৰণৰ জাননীবোৰ ইয়াত কনফিগাৰ কৰিব পৰা নাযায়"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"প্ৰক্সি হিচাপে পঠিওৱা জাননী"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"ডিভাইচ সেৱা"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনো শিৰোনাম নাই"</string>
<string name="restart_button_description" msgid="6916116576177456480">"এপ্‌টো ৰিষ্টাৰ্ট কৰক আৰু পূৰ্ণ স্ক্ৰীণ ব্যৱহাৰ কৰক।"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ bubblesৰ ছেটিংসমূহ"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"অভাৰফ্ল’"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ষ্টেকত পুনৰ যোগ দিয়ক"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"পৰিচালনা কৰক"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>ৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> আৰু<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>টাৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"আঁতৰাওক"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"শীৰ্ষৰ বাওঁফালে নিয়ক"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"শীৰ্ষৰ সোঁফালে নিয়ক"</string>
- <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="1314082410868930066">"বাবল অগ্ৰাহ্য কৰক"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"বাৰ্তালাপ বাবল নকৰিব"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bubbles ব্যৱহাৰ কৰি চাট কৰক"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"নতুন বাৰ্তালাপ উপঙি থকা চিহ্নসমূহ অথবা bubbles হিচাপে প্ৰদর্শিত হয়। Bubbles খুলিবলৈ টিপক। এইটো স্থানান্তৰ কৰিবলৈ টানি নিয়ক।"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"যিকোনো সময়তে bubbles নিয়ন্ত্ৰণ কৰক"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"এই এপ্‌টোৰ পৰা bubbles অফ কৰিবলৈ পৰিচালনা কৰকত টিপক"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"বুজি পালোঁ"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ছেটিংসমূহ"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ডৰ নম্বৰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ক্লিপব’ৰ্ডলৈ বিল্ডৰ নম্বৰ প্ৰতিলিপি কৰা হ’ল।"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"আপোনাৰ বেটাৰী মিটাৰ পঢ়োঁতে সমস্যা হৈছে"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"অধিক তথ্যৰ বাবে টিপক"</string>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings_tv.xml b/packages/SystemUI/res/values-as/strings_tv.xml
index 1db8f2297cc3..f7afcfa5c6dc 100644
--- a/packages/SystemUI/res/values-as/strings_tv.xml
+++ b/packages/SystemUI/res/values-as/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"মাইক্ৰ’ফ’ন সক্ৰিয় কৰা আছে"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$sএ আপোনাৰ মাইক্ৰ’ফ’ন এক্সেছ কৰিছে"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"ভিপিএন সংযোগ হৈ আছে"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"ভিপিএনৰ সংযোগ বিচ্ছিন্ন হৈছে"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>ৰ জৰিয়তে"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index f97b33459b40..a3292888e231 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Skrinşotu yenidən çəkin"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Yaddaş ehtiyatının az olması səbəbindən skrinşotu yadda saxlamaq olmur"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Skrinşot çəkməyə tətbiq və ya təşkilat tərəfindən icazə verilmir"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Skrinşota düzəliş edin"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ekran şəklini ötürün"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Redaktə edin"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Skrinşota düzəliş edin"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Sürüşdürün"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Sürüşdürülərək çəkilən skrinşot"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekran şəklini ötürün"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekran şəklinə önbaxış"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekran Yazıcısı"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran çəkilişi emal edilir"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batareya iki xətdir."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batareya üç xətdir."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batareya doludur"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batareyanın faizi naməlumdur."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Telefon yoxdur."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Şəbəkə bir xətdir."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Şəbəkə iki xətdir."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Bildiriş uzaqlaşdırıldı."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Qabarcıqdan imtina edilib."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bildiriş kölgəsi."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tez ayarlar."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekranı kilidləyin."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Bu tətbiqin bildirişləri göstərilməyə davam edilsin?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Səssiz"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Defolt"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Qabarcıq"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Avtomatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Səs və ya vibrasiya yoxdur"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Səs və ya vibrasiya yoxdur və söhbət bölməsinin aşağısında görünür"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> söhbət funksiyalarını dəstəkləmir"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Yumrucuqlar yoxdur"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Son yumrucuqlar və buraxılmış yumrucuqlar burada görünəcək"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirişlər dəyişdirilə bilməz."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Bu bildiriş qrupunu burada konfiqurasiya etmək olmaz"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Proksi bildirişi"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Cihaz Xidmətləri"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıq yoxdur"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Bu tətbiqi sıfırlayaraq tam ekrana keçmək üçün klikləyin."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> yumrucuqları üçün ayarlar"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Kənara çıxma"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Yenidən dəstəyə əlavə edin"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"İdarə edin"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> tətbiqindən <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> tətbiqindən <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> və daha <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> qabarcıq"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Hərəkət etdirin"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Yuxarıya sola köçürün"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Yuxarıya sağa köçürün"</string>
- <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="1314082410868930066">"Yumrucuğu ləğv edin"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Söhbəti yumrucuqda göstərmə"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Yumrucuqlardan istifadə edərək söhbət edin"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yeni söhbətlər üzən nişanlar və ya yumrucuqlar kimi görünür. Yumrucuğu açmaq üçün toxunun. Hərəkət etdirmək üçün sürüşdürün."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Yumrucuqları istənilən vaxt idarə edin"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu tətbiqdə yumrucuqları deaktiv etmək üçün \"İdarə edin\" seçiminə toxunun"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Anladım"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ayarları"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihazı qoşalaşdırın"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versiya nömrəsi"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versiya nömrəsi mübadilə buferinə kopyalandı."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya ölçüsünü oxuyarkən problem yarandı"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ətraflı məlumat üçün toxunun"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings_tv.xml b/packages/SystemUI/res/values-az/strings_tv.xml
index d690c642488f..cd9935f5f239 100644
--- a/packages/SystemUI/res/values-az/strings_tv.xml
+++ b/packages/SystemUI/res/values-az/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon Aktivdir"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s mikrofona daxil olub"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN qoşulub"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ayrılıb"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> vasitəsilə"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 48e5b72961e3..d800e8de8c2d 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Probajte da ponovo napravite snimak ekrana"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Čuvanje snimka ekrana nije uspelo zbog ograničenog memorijskog prostora"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikacija ili organizacija ne dozvoljavaju pravljenje snimaka ekrana"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Izmenite snimak ekrana"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Odbacite snimak ekrana"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Izmeni"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Izmenite snimak ekrana"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Pomeraj"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Pomerajte snimak ekrana"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacite snimak ekrana"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimka ekrana"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađujemo video snimka ekrana"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterija od dve crte."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterija od tri crte."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterija je puna."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procenat napunjenosti baterije nije poznat."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nema telefona."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Signal telefona ima jednu crtu."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Signal telefona od dve crte."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Obaveštenje je odbačeno."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Oblačić je odbačen."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Prozor sa obaveštenjima."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Brza podešavanja."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaključan ekran."</string>
@@ -717,7 +718,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Želite li da se obaveštenja iz ove aplikacije i dalje prikazuju?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Nečujno"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Podrazumevano"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Oblačić"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatska"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez zvuka i vibriranja"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Bez zvuka i vibriranja i prikazuje se u nastavku odeljka za konverzacije"</string>
@@ -729,8 +729,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Podešavanja"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije konverzacije"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nema nedavnih oblačića"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Ovde se prikazuju nedavni i odbačeni oblačići"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ova obaveštenja ne mogu da se menjaju."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ova grupa obaveštenja ne može da se konfiguriše ovde"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Obaveštenje preko proksija"</string>
@@ -991,25 +989,7 @@
<string name="device_services" msgid="1549944177856658705">"Usluge za uređaje"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Dodirnite da biste restartovali aplikaciju i prešli u režim celog ekrana."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Podešavanja za <xliff:g id="APP_NAME">%1$s</xliff:g> oblačiće"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Preklapanje"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Dodaj ponovo u grupu"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Upravljajte"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Premesti"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Premesti gore levo"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premesti gore desno"</string>
- <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="1314082410868930066">"Odbaci oblačić"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne koristi oblačiće za konverzaciju"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ćaskajte u oblačićima"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nove konverzacije se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da biste otvorili oblačić. Prevucite da biste ga premestili."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrolišite oblačiće u bilo kom trenutku"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljajte da biste isključili oblačiće iz ove aplikacije"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Važi"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Podešavanja za <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1100,8 +1080,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u privremenu memoriju."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem sa očitavanjem merača baterije"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
index d045ceaa4fca..8122e4d19ac0 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon je aktivan"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacija %1$s je pristupila mikrofonu"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN je povezan"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Veza sa VPN-om je prekinuta"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Preko: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index ed57fb392155..9fd9a5ec4c9b 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Паспрабуйце зрабіць здымак экрана яшчэ раз"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Немагчыма захаваць здымак экрана, бо мала месца ў сховішчы"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Рабіць здымкі экрана не дазваляе праграма ці ваша арганізацыя"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Змяніць здымак экрана"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Адхіліць здымак экрана"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Змяніць"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Змяніць здымак экрана"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Прагартаць"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Здымак экрана з пракруткай"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Адхіліць здымак экрана"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Перадпрагляд здымка экрана"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Запіс экрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Апрацоўваецца запіс экрана"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"2 планкі акумулятара."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Тры планкі акумулятара."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Акумулятар поўны."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Працэнт зараду акумулятара невядомы."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Няма тэлефона."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Адна планка на тэлефоне."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"2 планкі тэлефона."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Апавяшчэнне прапушчана."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Усплывальнае апавяшчэнне адхілена."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Цень апавяшчэння.."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Хуткія налады."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Экран блакіроўкі."</string>
@@ -720,7 +721,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Працягваць паказваць апавяшчэнні гэтай праграмы?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Бязгучны рэжым"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Стандартна"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Усплывальнае апавяшчэнне"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Аўтаматычна"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без гуку ці вібрацыі"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Паказваецца без гуку ці вібрацыі ў раздзеле размоў"</string>
@@ -732,8 +732,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налады"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Прыярытэт"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае функцыі размовы"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Няма нядаўніх усплывальных апавяшчэнняў"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Нядаўнія і адхіленыя ўсплывальныя апавяшчэнні будуць паказаны тут"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Гэтыя апавяшчэнні нельга змяніць."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Тут канфігурыраваць гэту групу апавяшчэнняў забаронена"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Праксіраванае апавяшчэнне"</string>
@@ -996,25 +994,7 @@
<string name="device_services" msgid="1549944177856658705">"Сэрвісы прылады"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назвы"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Націсніце, каб перазапусціць гэту праграму і перайсці ў поўнаэкранны рэжым."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Налады ўсплывальных апавяшчэнняў у праграме \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Дадатковае меню"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Зноў дадаць у стос"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Кіраваць"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ад праграмы \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ад праграмы \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" і яшчэ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Перамясціць"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Перамясціць лявей і вышэй"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перамясціце правей і вышэй"</string>
- <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="1314082410868930066">"Адхіліць апавяшчэнне"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не паказваць размову ў выглядзе ўсплывальных апавяшчэнняў"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Усплывальныя апавяшчэнні"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новыя размовы будуць паказвацца як рухомыя значкі ці ўсплывальныя апавяшчэнні. Націсніце, каб адкрыць усплывальнае апавяшчэнне. Перацягніце яго, каб перамясціць."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Кіруйце ўсплывальнымі апавяшчэннямі ў любы час"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Каб выключыць усплывальныя апавяшчэнні з гэтай праграмы, націсніце \"Кіраваць\""</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Зразумела"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Налады \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\""</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>
@@ -1106,8 +1086,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спалучыць з новай прыладай"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Нумар зборкі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Нумар зборкі скапіраваны ў буфер абмену."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Праблема з чытаннем індыкатара зараду акумулятара"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Націсніце, каб убачыць больш"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings_tv.xml b/packages/SystemUI/res/values-be/strings_tv.xml
index 37f925e1fae1..1016b8c59628 100644
--- a/packages/SystemUI/res/values-be/strings_tv.xml
+++ b/packages/SystemUI/res/values-be/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Мікрафон актыўны"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Праграма \"%1$s\" атрымала доступ да мікрафона"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN падключаны"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN адключаны"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Праз <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c968e6d25e3e..78a826b6a898 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Опитайте да направите екранна снимка отново"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Екранната снимка не може да се запази поради ограничено място в хранилището"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Правенето на екранни снимки не е разрешено от приложението или организацията ви"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Редактиране на екранната снимка"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Отхвърляне на екранната снимка"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Редактиране"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Редактиране на екранната снимка"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Превъртане"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Екранна снимка с превъртане"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Отхвърляне на екранната снимка"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Визуализация на екранната снимка"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Запис на екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Записът на екрана се обработва"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Батерията е с две чертички."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Батерията е с три чертички."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батерията е пълна."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентът на батерията е неизвестен."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Няма телефон."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Телефонът е с една чертичка."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Телефонът е с две чертички."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Известието е отхвърлено."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Балончето е отхвърлено."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Падащ панел с известия."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Бързи настройки."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заключване на екрана."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Да продължат ли да се показват известията от това приложение?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Тих режим"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Стандартно"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Балонче"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматично"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звук или вибриране"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звук или вибриране и се показва по-долу в секцията с разговори"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Настройки"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа функциите за разговор"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Няма скорошни балончета"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Скорошните и отхвърлените балончета ще се показват тук"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Тези известия не могат да бъдат променяни."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Тази група от известия не може да бъде конфигурирана тук"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Известие, получено чрез делегиране"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Услуги за устройството"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Няма заглавие"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Докоснете, за да рестартирате това приложение в режим на цял екран."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Настройки за балончетата за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Препълване"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Добавяне обратно към стека"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Управление"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> от <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ от<xliff:g id="APP_NAME">%2$s</xliff:g> и още <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Преместване"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Преместване горе вляво"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Преместване горе вдясно"</string>
- <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="1314082410868930066">"Отхвърляне на балончетата"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Без балончета за разговора"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Чат с балончета"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новите разговори се показват като плаващи икони, или балончета. Докоснете балонче, за да го отворите, или го плъзнете, за да го преместите."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Управление на балончетата по всяко време"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Докоснете „Управление“, за да изключите балончетата от това приложение"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Разбрах"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Настройки за <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Сдвояване на ново устройство"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер на компилацията"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номерът на компилацията е копиран в буферната памет."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Възникна проблем при четенето на данните за нивото на батерията"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Докоснете за още информация"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings_tv.xml b/packages/SystemUI/res/values-bg/strings_tv.xml
index f322079f77a1..6f6b8248ce79 100644
--- a/packages/SystemUI/res/values-bg/strings_tv.xml
+++ b/packages/SystemUI/res/values-bg/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Микрофонът е активен"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s осъществи достъп до микрофона ви"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN е свързана"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Връзката с VPN е прекратена"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Чрез <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index c225fd304c94..92e0c1dd9613 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"আবার স্ক্রিনশট নেওয়ার চেষ্টা করুন"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"বেশি জায়গা নেই তাই স্ক্রিনশটটি সেভ করা যাবে না৷"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"এই অ্যাপ বা আপনার প্রতিষ্ঠান স্ক্রিনশট নেওয়ার অনুমতি দেয়নি"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"স্ক্রিনশট এডিট করুন"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"স্ক্রিনশট বাতিল করুন"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"এডিট করুন"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"স্ক্রিনশট এডিট করুন"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"স্ক্রল করুন"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"স্ক্রিনশট স্ক্রল করুন"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"স্ক্রিনশট বাতিল করুন"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"স্ক্রিনশটের প্রিভিউ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"স্ক্রিন রেকর্ডার"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রিন রেকর্ডিং প্রসেস হচ্ছে"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"দুই দন্ড ব্যাটারি রয়েছে৷"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"তিন দন্ড ব্যাটারি রয়েছে৷"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ব্যাটারি পূর্ণ রয়েছে৷"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ব্যাটারি কত শতাংশ আছে তা জানা যায়নি।"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"কোনো ফোনের সংকেত নেই৷"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"এক দন্ড ফোনের সংকেত রয়েছে৷"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"দুই দন্ড ফোনের সংকেত রয়েছে৷"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"বিজ্ঞপ্তি খারিজ করা হয়েছে৷"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"বাবল বাতিল করা হয়েছে।"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"বিজ্ঞপ্তি শেড৷"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"দ্রুত সেটিংস৷"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"লক স্ক্রিন।"</string>
@@ -522,8 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"প্রোফাইল পর্যবেক্ষণ করা হতে পারে"</string>
<string name="vpn_footer" msgid="3457155078010607471">"নেটওয়ার্ক নিরীক্ষণ করা হতে পারে"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"নেটওয়ার্ক নিরীক্ষণ করা হতে পারে"</string>
- <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
- <skip />
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"আপনার অভিভাবক এই ডিভাইস ম্যানেজ করেন"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের এবং এরা ডিভাইসের নেটওয়ার্ক ট্রাফিক মনিটর করতে পারে"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> এই ডিভাইসের মালিক এবং এটির নেটওয়ার্ক ট্রাফিক মনিটর করতে পারে"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের এবং <xliff:g id="VPN_APP">%1$s</xliff:g>-এ কানেক্ট করা আছে"</string>
@@ -548,8 +548,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN অক্ষম করুন"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN এর সংযোগ বিচ্ছিন্ন করুন"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"নীতিগুলি দেখুন"</string>
- <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
- <skip />
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"কন্ট্রোল দেখুন"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"এই ডিভাইসটি <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>-এর।\n\nআপনার আইটি অ্যাডমিন এই ডিভাইসের সেটিংস, কর্পোরেট অ্যাক্সেস, অ্যাপ, ডিভাইসের সাথে সম্পর্কিত ডেটা এবং ডিভাইসের লোকেশন সম্পর্কিত ডেটা মনিটর ও ম্যানেজ করতে পারে।\n\nআরও তথ্যের জন্য আপনার আইটি অ্যাডমিনের সাথে যোগাযোগ করুন।"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"এই ডিভাইসটি আপনার প্রতিষ্ঠানের।\n\nআপনার আইটি অ্যাডমিন এই ডিভাইসের সেটিংস, কর্পোরেট অ্যাক্সেস, অ্যাপ, ডিভাইসের সাথে সম্পর্কিত ডেটা এবং ডিভাইসের লোকেশন সম্পর্কিত ডেটা মনিটর ও ম্যানেজ করতে পারে।\n\nআরও তথ্যের জন্য আপনার আইটি অ্যাডমিনের সাথে যোগাযোগ করুন।"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"আপনার প্রতিষ্ঠান আপনার অফিস প্রোফাইলে একটি সার্টিফিকেট কর্তৃপক্ষ ইনস্টল করেছে।আপনার সুরক্ষিত নেটওয়ার্ক ট্রাফিক নিরীক্ষণ বা পরিবর্তন করা হতে পারে।"</string>
@@ -573,8 +572,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"আপনার প্রশাসক নেটওয়ার্ক লগিং চালু করেছেন, যা আপনার ডিভাইসের ট্রাফিক নিরীক্ষণ করে।\n\nআরও তথ্যের জন্য আপনার প্রশাসকের সাথে যোগাযোগ করুন।"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"আপনি VPN সংযোগ সেট-আপ করার জন্য একটি অ্যাপ্লিকেশানকে অনুমতি দিন৷\n\nএই অ্যাপ্লিকেশানটি ইমেল, অ্যাপ্লিকেশান ও ওয়েবসাইটগুলি সহ আপনার ডিভাইস এবং নেটওয়ার্কের অ্যাক্টিভিটি নিরীক্ষণ করতে পারে।"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"আপনার কর্মস্থলের প্রোফাইলটি <xliff:g id="ORGANIZATION">%1$s</xliff:g> দ্বারা পরিচালিত হয়।\n\nআপনার প্রশাসক আপনার ইমেল, অ্যাপ্স ও ওয়েবসাইট সহ কর্মস্থলের নেটওয়ার্ক অ্যাক্টিভিটি নিরীক্ষণ করতে পারেন।\n\nআরও তথ্যের জন্য আপনার প্রশাসকের সঙ্গে যোগাযোগ করুন।\n\nএছাড়া আপনি একটি VPN এর সাথেও সংযুক্ত যা আপনার নেটওয়ার্ক অ্যাক্টিভিটি নিরীক্ষণ করতে পারে।"</string>
- <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
- <skip />
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"আপনার অভিভাবক এই ডিভাইস ম্যানেজ করেন। আপনার অভিভাবক আপনার ব্যবহার করা অ্যাপ, লোকেশন ও স্ক্রিন টাইমের মতো তথ্যগুলি দেখতে এবং ম্যানেজ করতে পারেন।"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> এর সাথে সংযুক্ত রয়েছেন, যেটি ইমেল, অ্যাপ, এবং ওয়েবসাইট সহ আপনার নেটওয়ার্ক কার্যকলাপে নজর রাখতে পারে৷"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> -এ সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ্লিকেশান এবং ওয়েবসাইটগুলি সমেত আপনার ব্যক্তিগত নেটওয়ার্ক অ্যাক্টিভিটি নিরীক্ষণ করতে পারে৷"</string>
@@ -717,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"এই অ্যাপের বিজ্ঞপ্তি পরেও দেখে যেতে চান?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"সাইলেন্ট"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ডিফল্ট"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"বাবল"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"অটোমেটিক"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"আওয়াজ করবে না বা ভাইব্রেট হবে না"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"আওয়াজ করবে না বা ভাইব্রেট হবে না এবং কথোপকথন বিভাগের নিচের দিকে দেখা যাবে"</string>
@@ -729,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"সেটিংস"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্রাধিকার"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এ কথোপকথন ফিচার কাজ করে না"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"কোনও সাম্প্রতিক বাবল নেই"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"সাম্প্রতিক ও বাতিল করা বাবল এখানে দেখা যাবে"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই বিজ্ঞপ্তিগুলি পরিবর্তন করা যাবে না।"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"এই সমস্ত বিজ্ঞপ্তিকে এখানে কনফিগার করা যাবে না"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"প্রক্সি করা বিজ্ঞপ্তি"</string>
@@ -989,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"ডিভাইস সংক্রান্ত পরিষেবা"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনও শীর্ষক নেই"</string>
<string name="restart_button_description" msgid="6916116576177456480">"এই অ্যাপ রিস্টার্ট করতে ট্যাপ করুন ও ফুল-স্ক্রিন ব্যবহার করুন।"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> বাবলের জন্য সেটিংস"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ওভারফ্লো"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"স্ট্যাকে আবার যোগ করুন"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"ম্যানেজ করুন"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> অ্যাপ থেকে <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> অ্যাপ এবং আরও <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>টি থেকে <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"সরান"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"উপরে বাঁদিকে সরান"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"উপরে ডানদিকে সরান"</string>
- <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="1314082410868930066">"বাবল খারিজ করুন"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"কথোপকথন বাবল হিসেবে দেখাবে না"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"বাবল ব্যবহার করে চ্যাট করুন"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"নতুন কথোপকথন ভেসে থাকা আইকন বা বাবল হিসেবে দেখানো হয়। বাবল খুলতে ট্যাপ করুন। সেটি সরাতে ধরে টেনে আনুন।"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"যেকোনও সময় বাবল নিয়ন্ত্রণ করুন"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"এই অ্যাপ থেকে বাবল বন্ধ করতে \'ম্যানেজ করুন\' বিকল্প ট্যাপ করুন"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"বুঝেছি"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> সেটিংস"</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>
@@ -1097,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"নতুন ডিভাইস পেয়ার করুন"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"বিল্ড নম্বর"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"বিল্ড নম্বর ক্লিপবোর্ডে কপি করা হয়েছে।"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ব্যাটারির মিটারের রিডিং নেওয়ার সময় সমস্যা হয়েছে"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"আরও তথ্যের জন্য ট্যাপ করুন"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings_tv.xml b/packages/SystemUI/res/values-bn/strings_tv.xml
index 56ca0233ae45..1c26840f1d18 100644
--- a/packages/SystemUI/res/values-bn/strings_tv.xml
+++ b/packages/SystemUI/res/values-bn/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"মাইক্রোফোন চালু আছে"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s আপনার ডিভাইসের মাইক্রোফোন অ্যাক্সেস করেছে"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN কানেক্ট করা হয়েছে"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ডিসকানেক্ট করা হয়েছে"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-এর মাধ্যমে"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 344bb63daa7c..1179a92547f0 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Pokušajte ponovo snimiti ekran"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Snimak ekrana se ne može sačuvati zbog manjka prostora za pohranu"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ova aplikacija ili vaša organizacija ne dozvoljavaju snimanje ekrana"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Uredite snimak ekrana"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Odbacite snimak ekrana"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Uredi"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Uredite snimak ekrana"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Klizni"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Pokretni snimak ekrana"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacite snimak ekrana"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimka ekrana"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađivanje snimka ekrana"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterija na dvije crtice."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterija na tri crtice."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterija je puna."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Postotak napunjenosti baterije nije poznat"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nema telefonskog signala."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefonski signal na jednoj crtici."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefonski signal na dvije crtice."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Obavještenje je uklonjeno."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Oblačić je odbačen."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Obavještenja sa sjenčenjem."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Brze postavke."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaključan ekran."</string>
@@ -717,7 +718,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Nastaviti prikazivanje obavještenja iz ove aplikacije?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Nečujno"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Zadano"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Oblačić"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatski"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez zvuka ili vibracije"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Bez zvuka ili vibracije i pojavljuje se pri dnu odjeljka za razgovor"</string>
@@ -729,8 +729,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Postavke"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetni"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije razgovora"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nema nedavnih oblačića"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nedavni i odbačeni oblačići će se pojaviti ovdje"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ta obavještenja se ne mogu izmijeniti."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ovu grupu obavještenja nije moguće konfigurirati ovdje"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Obavještenje preko proksi servera"</string>
@@ -991,25 +989,7 @@
<string name="device_services" msgid="1549944177856658705">"Usluge uređaja"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Dodirnite da ponovo pokrenete ovu aplikaciju i aktivirate prikaz preko cijelog ekrana."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Postavke za oblačiće aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Preklapanje"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Dodaj nazad u grupu"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Upravljaj"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> od aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"Obavještenje <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Pomjeri"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Pomjeri gore lijevo"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pomjerite gore desno"</string>
- <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="1314082410868930066">"Odbaci oblačić"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nemoj prikazivati razgovor u oblačićima"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatajte koristeći oblačiće"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi razgovori se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da otvorite oblačić. Prevucite da ga premjestite."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Upravljajte oblačićima u svakom trenutku"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljaj da isključite oblačiće iz ove aplikacije"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Razumijem"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Postavke aplikacije <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1100,8 +1080,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uparite novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj verzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj verzije je kopiran u međumemoriju."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Došlo je do problema prilikom očitavanja mjerača stanja baterije"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings_tv.xml b/packages/SystemUI/res/values-bs/strings_tv.xml
index acd93d657bac..7507746b4e65 100644
--- a/packages/SystemUI/res/values-bs/strings_tv.xml
+++ b/packages/SystemUI/res/values-bs/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon je aktivan"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacija %1$s je pristupila vašem mikrofonu"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN je povezan"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Veza s VPN-om je prekinuta"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Putem: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 0ed3ac1d306e..ca6316252588 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -33,10 +33,10 @@
<string name="invalid_charger_title" msgid="938685362320735167">"No es pot carregar per USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Fes servir el carregador original del dispositiu"</string>
<string name="battery_low_why" msgid="2056750982959359863">"Configuració"</string>
- <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vols activar l\'estalvi de bateria?"</string>
+ <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vols activar la funció Estalvi de bateria?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Sobre la funció Estalvi de bateria"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Activa"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Activa l\'estalvi de bateria"</string>
+ <string name="battery_saver_start_action" msgid="4553256017945469937">"Activa la funció Estalvi de bateria"</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"Configuració"</string>
<string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Gira pantalla automàticament"</string>
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Prova de tornar a fer una captura de pantalla"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"La captura de pantalla no es pot desar perquè no hi ha prou espai d\'emmagatzematge"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'aplicació o la teva organització no permeten fer captures de pantalla"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Edita la captura de pantalla"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ignora la captura de pantalla"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Edita"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Edita la captura de pantalla"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Desplaça"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Captura de pantalla lliscant"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignora la captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Previsualització de la captura de pantalla"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravació de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processant gravació de pantalla"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Bateria: dues barres."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Bateria: tres barres."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria carregada."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Es desconeix el percentatge de bateria."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"No hi ha senyal de telèfon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Senyal de telèfon: una barra"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Senyal de telèfon: dues barres."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificació omesa."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"La bombolla s\'ha ignorat."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Àrea de notificacions"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuració ràpida"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueig"</string>
@@ -502,7 +503,7 @@
<string name="user_remove_user_remove" msgid="8387386066949061256">"Suprimeix"</string>
<string name="battery_saver_notification_title" msgid="8419266546034372562">"S\'ha activat l\'estalvi de bateria"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"Redueix el rendiment i l\'ús de les dades en segon pla."</string>
- <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactiva l\'estalvi de bateria"</string>
+ <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactiva la funció Estalvi de bateria"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tindrà accés a tota la informació que es veu en pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio."</string>
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servei que ofereix aquesta funció tindrà accés a tota la informació visible a la teva pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio que reprodueixis."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vols començar a gravar o emetre contingut?"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Vols continuar rebent notificacions d\'aquesta aplicació?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silenci"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Predeterminat"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bombolla"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automàtic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sense so ni vibració"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sense so ni vibració i es mostra més avall a la secció de converses"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuració"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritat"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet les funcions de converses"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hi ha bombolles recents"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bombolles recents i les ignorades es mostraran aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aquestes notificacions no es poden modificar."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Aquest grup de notificacions no es pot configurar aquí"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notificació mitjançant aplicació intermediària"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Serveis per a dispositius"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sense títol"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toca per reiniciar l\'aplicació i passar a pantalla completa."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configuració de les bombolles: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menú addicional"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Torna a afegir a la pila"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Gestiona"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>) i <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> més"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Mou"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Mou a dalt a l\'esquerra"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mou a dalt a la dreta"</string>
- <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="1314082410868930066">"Ignora la bombolla"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostris la conversa com a bombolla"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Xateja amb bombolles"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Les converses noves es mostren com a icones flotants o bombolles. Toca per obrir una bombolla. Arrossega-la per moure-la."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controla les bombolles en qualsevol moment"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toca Gestiona per desactivar les bombolles d\'aquesta aplicació"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Entesos"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Configuració de l\'aplicació <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincula un dispositiu nou"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilació"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"El número de compilació s\'ha copiat al porta-retalls."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Hi ha hagut un problema en llegir el mesurador de la bateria"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca per obtenir més informació"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings_tv.xml b/packages/SystemUI/res/values-ca/strings_tv.xml
index c41d5714e60e..14bc9472f260 100644
--- a/packages/SystemUI/res/values-ca/strings_tv.xml
+++ b/packages/SystemUI/res/values-ca/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Micròfon actiu"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ha accedit al teu micròfon"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"La VPN està connectada"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"La VPN està desconnectada"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Mitjançant <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 156b65d41dea..aa6459e76548 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Zkuste snímek pořídit znovu"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Snímek obrazovky kvůli nedostatku místa v úložišti nelze uložit"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikace nebo organizace zakazuje pořizování snímků obrazovky"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Upravit snímek obrazovky"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Zavřít snímek obrazovky"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Upravit"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Upravit snímek obrazovky"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Posunout"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Posunout snímek obrazovky"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zavřít snímek obrazovky"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Náhled snímku obrazovky"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Záznam obrazovky se zpracovává"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dvě čárky baterie."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Tři čárky baterie."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterie je nabitá."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procento baterie není známé."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Žádná telefonní síť."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Jedna čárka signálu telefonní sítě."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dvě čárky signálu telefonní sítě."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Oznámení je zavřeno."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bublina byla zavřena."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel oznámení."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Rychlé nastavení."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Obrazovka uzamčení"</string>
@@ -720,7 +721,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Mají se oznámení z této aplikace nadále zobrazovat?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Ticho"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Výchozí"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bublina"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaticky"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Žádný zvuk ani vibrace"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Žádný zvuk ani vibrace a zobrazovat níže v sekci konverzací"</string>
@@ -732,8 +732,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavení"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> funkce konverzace nepodporuje"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Žádné nedávné bubliny"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Zde se budou zobrazovat nedávné bubliny a zavřené bubliny"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tato oznámení nelze upravit."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Tuto skupinu oznámení tady nelze nakonfigurovat"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Zprostředkované oznámení"</string>
@@ -996,25 +994,7 @@
<string name="device_services" msgid="1549944177856658705">"Služby zařízení"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Klepnutím aplikaci restartujete a přejdete na režim celé obrazovky"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Nastavení bublin aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Rozbalovací nabídka"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Přidat zpět do sady"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Spravovat"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"Oznámení <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikace <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikace <xliff:g id="APP_NAME">%2$s</xliff:g> a dalších (<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>)"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Přesunout"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Přesunout vlevo nahoru"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Přesunout vpravo nahoru"</string>
- <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="1314082410868930066">"Zavřít bublinu"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nezobrazovat konverzaci v bublinách"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatujte pomocí bublin"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nové konverzace se zobrazují jako plovoucí ikony, neboli bubliny. Klepnutím bublinu otevřete. Přetažením ji posunete."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Nastavení bublin můžete kdykoli upravit"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bubliny pro tuto aplikaci můžete vypnout klepnutím na Spravovat"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Rozumím"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Nastavení <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1106,8 +1086,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovat nové zařízení"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo sestavení"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo sestavení bylo zkopírováno do schránky."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problém s načtením měřiče baterie"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím zobrazíte další informace"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings_tv.xml b/packages/SystemUI/res/values-cs/strings_tv.xml
index 2d95d46a078f..ad869b1399fa 100644
--- a/packages/SystemUI/res/values-cs/strings_tv.xml
+++ b/packages/SystemUI/res/values-cs/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon je aktivní"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Aplikace %1$s použila mikrofon"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"Síť VPN je připojena"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Síť VPN je odpojena"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prostřednictvím aplikace <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index d4761d504dfe..d20fc0cf0d5c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Prøv at tage et screenshot igen"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Screenshottet kan ikke gemmes, fordi der er begrænset lagerplads"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Appen eller din organisation tillader ikke, at du tager screenshots"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Rediger dit screenshot"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Luk screenshot"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Rediger"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Rediger screenshot"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Rul"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Rul screenshot"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Luk screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Forhåndsvisning af screenshot"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skærmoptagelse"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skærmoptagelse"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batteri to bjælker."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batteri tre bjælker."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batteri fuldt."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriniveauet er ukendt."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ingen telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon en bjælke."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon to bjælker."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notifikationen er annulleret."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Boblen blev lukket."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notifikationspanel."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Kvikmenu."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låseskærm."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Vil du fortsætte med at se notifikationer fra denne app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Lydløs"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standard"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Boble"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisk"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ingen lyd eller vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ingen lyd eller vibration, og den vises længere nede i samtalesektionen"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Indstillinger"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke samtalefunktioner"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ingen seneste bobler"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nye bobler og afviste bobler vises her"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse notifikationer kan ikke redigeres."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Du kan ikke konfigurere denne gruppe notifikationer her"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Proxyforbundet notifikation"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Enhedstjenester"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tryk for at genstarte denne app, og gå til fuld skærm."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Indstillinger for <xliff:g id="APP_NAME">%1$s</xliff:g>-bobler"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overløb"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Føj til stak igen"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Administrer"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> andre"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Flyt"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Flyt op til venstre"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flyt op til højre"</string>
- <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="1314082410868930066">"Afvis boble"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Vis ikke samtaler i bobler"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat ved hjælp af bobler"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som svævende ikoner eller bobler. Tryk for at åbne boblen. Træk for at flytte den."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Styr bobler når som helst"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tryk på Administrer for at deaktivere bobler fra denne app"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Indstillinger for <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Par ny enhed"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildnummeret blev kopieret til udklipsholderen."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Der er problemer med at aflæse dit batteriniveau"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tryk for at få flere oplysninger"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings_tv.xml b/packages/SystemUI/res/values-da/strings_tv.xml
index f70427d90cd0..84926e0c64f2 100644
--- a/packages/SystemUI/res/values-da/strings_tv.xml
+++ b/packages/SystemUI/res/values-da/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofonen er slået til"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s fik adgang til din mikrofon"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN er tilsluttet"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN er afbrudt"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 3aff4c89c162..dcd6a5351489 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Versuche noch einmal, den Screenshot zu erstellen"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Speichern des Screenshots aufgrund von zu wenig Speicher nicht möglich"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Die App oder deine Organisation lässt das Erstellen von Screenshots nicht zu"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Screenshot bearbeiten"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Screenshot schließen"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Bearbeiten"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Screenshot bearbeiten"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scrollen"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Screenshot scrollen"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Screenshot schließen"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshotvorschau"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Bildschirmaufzeichnung"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Bildschirmaufzeichnung…"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Akku - zwei Balken"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Akku - drei Balken"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Akku voll"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akkustand unbekannt."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Kein Telefon"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefonsignal - ein Balken"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefonsignal - zwei Balken"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Benachrichtigung geschlossen"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubble verworfen."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Benachrichtigungsleiste"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Schnelleinstellungen"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Sperrbildschirm"</string>
@@ -522,8 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil wird eventuell überwacht."</string>
<string name="vpn_footer" msgid="3457155078010607471">"Das Netzwerk wird eventuell überwacht."</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Das Netzwerk wird eventuell überwacht"</string>
- <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
- <skip />
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Dieses Gerät wird von deinen Eltern verwaltet"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Deine Organisation verwaltet dieses Gerät und kann den Netzwerkverkehr überwachen"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ist der Eigentümer dieses Geräts und kann den Netzwerkverkehr überwachen"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Dieses Gerät gehört deiner Organisation und ist mit <xliff:g id="VPN_APP">%1$s</xliff:g> verbunden"</string>
@@ -548,8 +548,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN deaktivieren"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN-Verbindung trennen"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Richtlinien ansehen"</string>
- <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
- <skip />
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Jugendschutzeinstellungen"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Dieses Gerät gehört <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nDein IT-Administrator kann Einstellungen, Zugriffsrechte im Unternehmen, Apps, mit diesem Gerät verknüpfte Daten und die Standortdaten deines Geräts sehen und verwalten.\n\nWeitere Informationen erhältst du von deinem IT-Administrator."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Dieses Gerät gehört deiner Organisation.\n\nDein IT-Administrator kann Einstellungen, Zugriffsrechte im Unternehmen, Apps, mit diesem Gerät verknüpfte Daten und die Standortdaten deines Geräts sehen und verwalten.\n\nWeitere Informationen erhältst du von deinem IT-Administrator."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Deine Organisation hat ein Zertifikat einer Zertifizierungsstelle auf deinem Gerät installiert. Eventuell wird dein sicherer Netzwerkverkehr überwacht oder bearbeitet."</string>
@@ -573,8 +572,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Dein Administrator hat die Netzwerkprotokollierung aktiviert. Damit wird der Verkehr auf deinem Gerät erfasst.\n\nWeitere Informationen erhältst du von deinem Administrator."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Du hast einer App gestattet, eine VPN-Verbindung einzurichten.\n\nDiese App kann dein Gerät und deine Netzwerkaktivitäten überwachen, einschließlich E-Mails, Apps und Websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet.\n\nDein Administrator kann deine Netzwerkaktivitäten einschließlich E-Mails, Apps und Websites überwachen.\n\nWeitere Informationen erhältst du von deinem Administrator.\n\nAußerdem bist du mit einem VPN verbunden, das deine Netzwerkaktivitäten erfassen kann."</string>
- <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
- <skip />
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Dieses Gerät wird von deinen Eltern verwaltet. Sie können unter anderem Informationen über deine genutzten Apps, deinen Standort und deine Gerätenutzungsdauer einsehen und verwalten."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Du bist mit <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine Netzwerkaktivitäten überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Du bist mit der App <xliff:g id="APPLICATION">%1$s</xliff:g> verbunden, die deine persönliche Netzwerkaktivität überwachen kann, einschließlich E-Mails, Apps und Websites."</string>
@@ -717,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Benachrichtigungen dieser App weiterhin anzeigen?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Lautlos"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standard"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisch"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Kein Ton und keine Vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Kein Ton und keine Vibration, erscheint weiter unten im Bereich \"Unterhaltungen\""</string>
@@ -729,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Einstellungen"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorität"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine Funktionen für Unterhaltungen"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Keine kürzlich geschlossenen Bubbles"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Hier werden aktuelle und geschlossene Bubbles angezeigt"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Diese Benachrichtigungen können nicht geändert werden."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Die Benachrichtigungsgruppe kann hier nicht konfiguriert werden"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Weitergeleitete Benachrichtigung"</string>
@@ -989,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Gerätedienste"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Kein Titel"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tippe, um die App im Vollbildmodus neu zu starten."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Einstellungen für <xliff:g id="APP_NAME">%1$s</xliff:g>-Bubbles"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Mehr anzeigen"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Wieder dem Stapel hinzufügen"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Verwalten"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> von <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> aus <xliff:g id="APP_NAME">%2$s</xliff:g> und <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> weiteren"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Verschieben"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Nach oben links verschieben"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Nach rechts oben verschieben"</string>
- <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="1314082410868930066">"Bubble schließen"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Unterhaltung nicht als Bubble anzeigen"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bubbles zum Chatten verwenden"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Neue Unterhaltungen erscheinen als unverankerte Symbole, \"Bubbles\" genannt. Wenn du die Bubble öffnen möchtest, tippe sie an. Wenn du sie verschieben möchtest, zieh an ihr."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Bubble-Einstellungen festlegen"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tippe auf \"Verwalten\", um Bubbles für diese App zu deaktivieren"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Einstellungen für <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1097,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Neues Gerät koppeln"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-Nummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build-Nummer in Zwischenablage kopiert."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem beim Lesen des Akkustands"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Für weitere Informationen tippen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings_tv.xml b/packages/SystemUI/res/values-de/strings_tv.xml
index b947b2ce1336..34fc6aadcd41 100644
--- a/packages/SystemUI/res/values-de/strings_tv.xml
+++ b/packages/SystemUI/res/values-de/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon aktiv"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s hat auf dein Mikrofon zugegriffen"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ist verbunden"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ist nicht verbunden"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Über <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 1a6998e52d23..197cd17de1f3 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Δοκιμάστε να κάνετε ξανά λήψη του στιγμιότυπου οθόνης"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Αδύνατη η αποθήκευση του στιγμιότυπου οθόνης λόγω περιορισμένου αποθηκευτικού χώρου"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Η λήψη στιγμιότυπων οθόνης δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Επεξεργασία στιγμιότυπου οθόνης"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Παράβλεψη στιγμιότυπου οθόνης"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Επεξεργασία"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Επεξεργασία στιγμιότυπου οθόνης"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Κύλιση"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Στιγμιότυπο κύλισης"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Παράβλεψη στιγμιότυπου οθόνης"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Προεπισκόπηση στιγμιότυπου οθόνης"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Εγγραφή οθόνης"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Επεξεργασία εγγραφής οθόνης"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Δύο γραμμές μπαταρίας."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Τρεις γραμμές μπαταρίας."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Πλήρης μπαταρία."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Άγνωστο ποσοστό μπαταρίας."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Δεν υπάρχει τηλέφωνο."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Μία γραμμή τηλεφώνου."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Δύο γραμμές τηλεφώνου."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Η ειδοποίηση έχει απορριφθεί."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Το συννεφάκι παραβλέφθηκε."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Πλαίσιο σκίασης ειδοποιήσεων."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Γρήγορες ρυθμίσεις."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Οθόνη κλειδώματος"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Να συνεχίσουν να εμφανίζονται ειδοποιήσεις από αυτήν την εφαρμογή;"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Σίγαση"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Προεπιλογή"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Συννεφάκι"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Αυτόματο"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Χωρίς ήχο ή δόνηση"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Χωρίς ήχο ή δόνηση και εμφανίζεται χαμηλά στην ενότητα συζητήσεων"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ρυθμίσεις"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Προτεραιότητα"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει τις λειτουργίες συζήτησης"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Δεν υπάρχουν πρόσφατα συννεφάκια"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Τα πρόσφατα συννεφάκια και τα συννεφάκια που παραβλέψατε θα εμφανίζονται εδώ."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Δεν είναι δυνατή η τροποποίηση αυτών των ειδοποιήσεων"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Δεν είναι δυνατή η διαμόρφωση αυτής της ομάδας ειδοποιήσεων εδώ"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Ειδοποίηση μέσω διακομιστή μεσολάβησης"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Υπηρεσίες συσκευής"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Χωρίς τίτλο"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Πατήστε για επανεκκίνηση αυτής της εφαρμογής και ενεργοποίηση πλήρους οθόνης."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Ρυθμίσεις για συννεφάκια <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Υπερχείλιση"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Προσθήκη ξανά στη στοίβα"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Διαχείριση"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> από <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> από την εφαρμογή <xliff:g id="APP_NAME">%2$s</xliff:g> και <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ακόμη"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Μετακίνηση"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Μετακίνηση επάνω αριστερά"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Μετακίνηση επάνω δεξιά"</string>
- <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="1314082410868930066">"Παράβλ. για συννεφ."</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Να μην γίνει προβολή της συζήτησης σε συννεφάκια."</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Συζητήστε χρησιμοποιώντας συννεφάκια."</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Οι νέες συζητήσεις εμφανίζονται ως κινούμενα εικονίδια ή συννεφάκια. Πατήστε για να ανοίξετε το συννεφάκι. Σύρετε για να το μετακινήσετε."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Ελέγξτε τα συννεφάκια ανά πάσα στιγμή."</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Πατήστε Διαχείριση για να απενεργοποιήσετε τα συννεφάκια από αυτήν την εφαρμογή."</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Το κατάλαβα."</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Ρυθμίσεις <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Σύζευξη νέας συσκευής"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Αριθμός έκδοσης"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Ο αριθμός έκδοσης αντιγράφηκε στο πρόχειρο."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Υπάρχει κάποιο πρόβλημα με την ανάγνωση του μετρητή μπαταρίας"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Πατήστε για περισσότερες πληροφορίες."</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings_tv.xml b/packages/SystemUI/res/values-el/strings_tv.xml
index d03961366a2c..21badf740bf0 100644
--- a/packages/SystemUI/res/values-el/strings_tv.xml
+++ b/packages/SystemUI/res/values-el/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Ενεργό μικρόφωνο"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Πραγματοποιήθηκε πρόσβαση στο μικρόφωνό σας από το %1$s"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"Το VPN συνδέθηκε"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Το VPN αποσυνδέθηκε"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Μέσω <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index fe1d8419274b..85d6276b3885 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Try taking screenshot again"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Can\'t save screenshot due to limited storage space"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Edit screenshot"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scroll"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Scroll screenshot"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
@@ -256,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification dismissed."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubble dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Quick settings."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
@@ -713,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Keep showing notifications from this app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silent"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Default"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string>
@@ -725,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Proxied notification"</string>
@@ -985,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tap to restart this app and go full screen."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflow"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Add back to stack"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Manage"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Move"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Move top left"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
- <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
- <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
- <string name="bubble_dismiss_text" msgid="1314082410868930066">"Dismiss bubble"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control bubbles at any time"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tap Manage to turn off bubbles from this app"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings_tv.xml b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
index f81611fba4a5..ab370b14a326 100644
--- a/packages/SystemUI/res/values-en-rAU/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Microphone active"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accessed your microphone"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN is connected"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN is disconnected"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index a2307e73790d..5db104ccaa02 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Try taking screenshot again"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Can\'t save screenshot due to limited storage space"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Edit screenshot"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scroll"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Scroll screenshot"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
@@ -256,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification dismissed."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubble dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Quick settings."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
@@ -713,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Keep showing notifications from this app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silent"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Default"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string>
@@ -725,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Proxied notification"</string>
@@ -985,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tap to restart this app and go full screen."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflow"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Add back to stack"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Manage"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Move"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Move top left"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
- <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
- <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
- <string name="bubble_dismiss_text" msgid="1314082410868930066">"Dismiss bubble"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control bubbles at any time"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tap Manage to turn off bubbles from this app"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings_tv.xml b/packages/SystemUI/res/values-en-rCA/strings_tv.xml
index f81611fba4a5..ab370b14a326 100644
--- a/packages/SystemUI/res/values-en-rCA/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Microphone active"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accessed your microphone"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN is connected"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN is disconnected"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 50288b2d5879..85d6276b3885 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Try taking screenshot again"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Can\'t save screenshot due to limited storage space"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Edit screenshot"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scroll"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Scroll screenshot"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Battery two bars."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Battery three bars."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Battery full."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"No phone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Phone one bar."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Phone two bars."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification dismissed."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubble dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Quick settings."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Keep showing notifications from this app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silent"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Default"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Proxied notification"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tap to restart this app and go full screen."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflow"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Add back to stack"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Manage"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Move"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Move top left"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
- <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
- <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
- <string name="bubble_dismiss_text" msgid="1314082410868930066">"Dismiss bubble"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control bubbles at any time"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tap Manage to turn off bubbles from this app"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings_tv.xml b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
index f81611fba4a5..ab370b14a326 100644
--- a/packages/SystemUI/res/values-en-rGB/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Microphone active"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accessed your microphone"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN is connected"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN is disconnected"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 50288b2d5879..85d6276b3885 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Try taking screenshot again"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Can\'t save screenshot due to limited storage space"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Taking screenshots isn\'t allowed by the app or your organisation"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Edit screenshot"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dismiss screenshot"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Edit screenshot"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scroll"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Scroll screenshot"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dismiss screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Screenshot preview"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Screen Recorder"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Battery two bars."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Battery three bars."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Battery full."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Battery percentage unknown."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"No phone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Phone one bar."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Phone two bars."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification dismissed."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubble dismissed."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Quick settings."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Keep showing notifications from this app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silent"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Default"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Proxied notification"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tap to restart this app and go full screen."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Settings for <xliff:g id="APP_NAME">%1$s</xliff:g> bubbles"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflow"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Add back to stack"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Manage"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> more"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Move"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Move top left"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
- <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
- <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
- <string name="bubble_dismiss_text" msgid="1314082410868930066">"Dismiss bubble"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Control bubbles at any time"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tap Manage to turn off bubbles from this app"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"System navigation updated. To make changes, go to Settings."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Go to Settings to update system navigation"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Pair new device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build number"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build number copied to clipboard."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem reading your battery meter"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tap for more information"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings_tv.xml b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
index f81611fba4a5..ab370b14a326 100644
--- a/packages/SystemUI/res/values-en-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Microphone active"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accessed your microphone"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN is connected"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN is disconnected"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index fe7f4e05138b..3719aa7a10e0 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎Try taking screenshot again‎‏‎‎‏‎"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‎‏‎Can\'t save screenshot due to limited storage space‎‏‎‎‏‎"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‎‎‎‏‎‎‏‏‎‏‎‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‏‏‎Taking screenshots isn\'t allowed by the app or your organization‎‏‎‎‏‎"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‏‏‎Edit screenshot‎‏‎‎‏‎"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎Dismiss screenshot‎‏‎‎‏‎"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‎‎Edit‎‏‎‎‏‎"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‎‏‎‏‎‏‎‎Edit screenshot‎‏‎‎‏‎"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‎‎‏‏‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‏‎Scroll‎‏‎‎‏‎"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎Scroll screenshot‎‏‎‎‏‎"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎Dismiss screenshot‎‏‎‎‏‎"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‎‏‏‎‎‎‎‎‎‎‏‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‎‎Screenshot preview‎‏‎‎‏‎"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‎‎‎Screen Recorder‎‏‎‎‏‎"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‎Processing screen recording‎‏‎‎‏‎"</string>
@@ -256,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎‎‎‎Notification dismissed.‎‏‎‎‏‎"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‏‎Bubble dismissed.‎‏‎‎‏‎"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‎Notification shade.‎‏‎‎‏‎"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‎‏‎‏‏‎Quick settings.‎‏‎‎‏‎"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‎‏‎‎‎‎‏‏‏‎Lock screen.‎‏‎‎‏‎"</string>
@@ -713,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎Keep showing notifications from this app?‎‏‎‎‏‎"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎Silent‎‏‎‎‏‎"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‎‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎Default‎‏‎‎‏‎"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎Bubble‎‏‎‎‏‎"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎Automatic‎‏‎‎‏‎"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‏‎‏‏‎‎No sound or vibration‎‏‎‎‏‎"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‎‎‏‎No sound or vibration and appears lower in conversation section‎‏‎‎‏‎"</string>
@@ -725,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‏‎Settings‎‏‎‎‏‎"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎Priority‎‏‎‎‏‎"</string>
<string name="no_shortcut" msgid="8257177117568230126">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ doesn’t support conversation features‎‏‎‎‏‎"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎No recent bubbles‎‏‎‎‏‎"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‏‎‏‎Recent bubbles and dismissed bubbles will appear here‎‏‎‎‏‎"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎These notifications can\'t be modified.‎‏‎‎‏‎"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‏‎‎‏‎‎‏‏‎This group of notifications cannot be configured here‎‏‎‎‏‎"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‎‎‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎Proxied notification‎‏‎‎‏‎"</string>
@@ -985,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎Device Services‎‏‎‎‏‎"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎No title‎‏‎‎‏‎"</string>
<string name="restart_button_description" msgid="6916116576177456480">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‎‎‎‎Tap to restart this app and go full screen.‎‏‎‎‏‎"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‎‏‎Settings for ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ bubbles‎‏‎‎‏‎"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‏‏‏‏‎‎Overflow‎‏‎‎‏‎"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‎Add back to stack‎‏‎‎‏‎"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‎‏‏‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎Manage‎‏‎‎‏‎"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‏‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ from ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ from ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>‎‏‎‎‏‏‏‎ more‎‏‎‎‏‎"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‎‏‎‎Move‎‏‎‎‏‎"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‎‎‎Move top left‎‏‎‎‏‎"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎Move top right‎‏‎‎‏‎"</string>
- <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‎Move bottom left‎‏‎‎‏‎"</string>
- <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‎‎Move bottom right‎‏‎‎‏‎"</string>
- <string name="bubble_dismiss_text" msgid="1314082410868930066">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎Dismiss bubble‎‏‎‎‏‎"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‎Don’t bubble conversation‎‏‎‎‏‎"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎‏‎‏‎Chat using bubbles‎‏‎‎‏‎"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‎‏‏‎New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it.‎‏‎‎‏‎"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎Control bubbles anytime‎‏‎‎‏‎"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎Tap Manage to turn off bubbles from this app‎‏‎‎‏‎"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‏‏‎Got it‎‏‎‎‏‎"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ settings‎‏‎‎‏‎"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‎‏‏‎‏‎‎‎‎‎‎‎‎‎System navigation updated. To make changes, go to Settings.‎‏‎‎‏‎"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎Go to Settings to update system navigation‎‏‎‎‏‎"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎Standby‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings_tv.xml b/packages/SystemUI/res/values-en-rXC/strings_tv.xml
index 88c5843b7c96..9fb261012dca 100644
--- a/packages/SystemUI/res/values-en-rXC/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‎‎‎‎‎Microphone Active‎‏‎‎‏‎"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‏‎‏‎‏‎‏‎‎‎‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‎%1$s accessed your microphone‎‏‎‎‏‎"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎VPN is connected‎‏‎‎‏‎"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‎‏‏‎VPN is disconnected‎‏‎‎‏‎"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎Via ‎‏‎‎‏‏‎<xliff:g id="VPN_APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index d6c5e15f7eb7..bd649506b6f5 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Vuelve a hacer una captura de pantalla"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"No se puede guardar la captura de pantalla debido a que no hay suficiente espacio de almacenamiento"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"La app o tu organización no permiten las capturas de pantalla"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Editar captura de pantalla"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Descartar captura de pantalla"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de pantalla"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Desplazar"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Desplazar captura de pantalla"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Descartar captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa de la captura de pantalla"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Grabadora de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación pantalla"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dos barras de batería"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Tres barras de batería"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batería completa"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Se desconoce el porcentaje de la batería."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sin teléfono"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Una barra de teléfono"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dos barras de teléfono"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificación ignorada"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Se descartó el cuadro."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pantalla de notificaciones"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuración rápida"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo"</string>
@@ -522,8 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Es posible que se supervise el perfil."</string>
<string name="vpn_footer" msgid="3457155078010607471">"Es posible que la red esté supervisada."</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Es posible que la red esté supervisada"</string>
- <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
- <skip />
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Tu padre o madre administra este dispositivo"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Tu organización es propietaria de este dispositivo y podría controlar el tráfico de red"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> es la organización propietaria de este dispositivo y podría controlar el tráfico de red"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Este dispositivo pertenece a tu organización y está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -548,8 +548,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Inhabilitar VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Desconectar VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Ver políticas"</string>
- <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
- <skip />
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Controles de vista"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nTu administrador de TI puede controlar y administrar la configuración, el acceso corporativo, las apps, los datos asociados al dispositivo y la información de ubicación.\n\nPara obtener más información, comunícate con el administrador de TI."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Este dispositivo pertenece a tu organización.\n\nTu administrador de TI puede controlar y administrar la configuración, el acceso corporativo, las apps, los datos asociados al dispositivo y la información de ubicación.\n\nPara obtener más información, comunícate con el administrador de TI."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Tu organización instaló una autoridad de certificación en este dispositivo. Es posible que se controle o modifique el tráfico de tu red segura."</string>
@@ -573,8 +572,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Tu administrador activó el registro de red, que controla el tráfico en tu dispositivo.\n\nComunícate con él para obtener más información."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Permitiste que una aplicación configurara una conexión VPN.\n\nEsta aplicación puede supervisar la actividad de la red y del dispositivo, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de trabajo.\n\nTu administrador puede controlar tu actividad en la red, como los correos electrónicos, las apps y los sitios web.\n\nComunícate con él para obtener más información.\n\nTambién estás conectado a una VPN, que puede controlar tu actividad en la red."</string>
- <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
- <skip />
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Tu padre o madre administra este dispositivo. Esa persona puede ver y administrar información, como las apps que usas, tu ubicación y el tiempo de uso."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede controlar la actividad de la red, incluidos los correos electrónicos, las apps y los sitios web."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Tienes conexión a la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g>, que puede supervisar la actividad de la red personal, incluidos los correos electrónicos, las aplicaciones y los sitios web."</string>
@@ -717,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"¿Quieres seguir viendo las notificaciones de esta app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silenciada"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Predeterminada"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Cuadro"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sin sonido ni vibración"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No suena ni vibra, y aparece en la parte inferior de la sección de conversaciones."</string>
@@ -729,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritaria"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hay burbujas recientes"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Las burbujas recientes y las que se descartaron aparecerán aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"No se pueden modificar estas notificaciones."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"No se puede configurar aquí este grupo de notificaciones"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notificación almacenada en proxy"</string>
@@ -989,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Servicios del dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Presiona para reiniciar esta app y acceder al modo de pantalla completa."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configuración para burbujas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menú ampliado"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Volver a agregar a la pila"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Administrar"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> y <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> más"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Mover"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Ubicar arriba a la izquierda"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Ubicar arriba a la derecha"</string>
- <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="1314082410868930066">"Descartar burbuja"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostrar la conversación en burbujas"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat con burbujas"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Las conversaciones nuevas aparecen como elementos flotantes o burbujas. Presiona para abrir la burbuja. Arrástrala para moverla."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controla las burbujas"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Presiona Administrar para desactivar las burbujas de esta app"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Entendido"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Configuración de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1097,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo nuevo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Se copió el número de compilación en el portapapeles."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema al leer el medidor de batería"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Presiona para obtener más información"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings_tv.xml b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
index 8e9e048b06f6..7aa99272e9bd 100644
--- a/packages/SystemUI/res/values-es-rUS/strings_tv.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Micrófono activado"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accedió al micrófono"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"La VPN está conectada."</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"La VPN está desconectada"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 9726134d4158..2ce271896c50 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Vuelve a intentar hacer la captura de pantalla"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"No se puede guardar la captura de pantalla porque no hay espacio de almacenamiento suficiente"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"La aplicación o tu organización no permiten realizar capturas de pantalla"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Editar captura de pantalla"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Cerrar captura de pantalla"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de pantalla"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Pantalla continua"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Hacer captura de pantalla continua"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Cerrar captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa de captura de pantalla"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Grabación de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación de pantalla"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dos barras de batería"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Tres barras de batería"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batería completa"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentaje de batería desconocido."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sin teléfono"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Una barra de cobertura"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dos barras de cobertura"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificación ignorada"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Burbuja cerrada."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pantalla de notificaciones"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ajustes rápidos"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"¿Quieres seguir viendo las notificaciones de esta aplicación?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silencio"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Predeterminado"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Burbuja"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sin sonido ni vibración"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sin sonido ni vibración, y se muestra más abajo en la sección de conversaciones"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ajustes"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string>
<string name="no_shortcut" msgid="8257177117568230126">"No se pueden usar funciones de conversación con <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hay burbujas recientes"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Las burbujas recientes y las cerradas aparecerán aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificaciones no se pueden modificar."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Este grupo de notificaciones no se puede configurar aquí"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notificación mediante proxy"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Servicios del dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toca para reiniciar esta aplicación e ir a la pantalla completa."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Ajustes de las burbujas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menú adicional"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Volver a añadir a la pila"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Gestionar"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> y <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> más"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Mover"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Mover arriba a la izquierda"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover arriba a la derecha"</string>
- <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="1314082410868930066">"Cerrar burbuja"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostrar conversación en burbuja"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatea con burbujas"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Las conversaciones nuevas aparecen como iconos flotantes llamadas \"burbujas\". Toca para abrir la burbuja. Arrastra para moverla."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controla las burbujas"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toca Gestionar para desactivar las burbujas de esta aplicación"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Entendido"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Ajustes de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular nuevo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número de compilación copiado en el portapapeles."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"No se ha podido leer el indicador de batería"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca la pantalla para consultar más información"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings_tv.xml b/packages/SystemUI/res/values-es/strings_tv.xml
index 6a72a3d3a77e..f3bab286fda4 100644
--- a/packages/SystemUI/res/values-es/strings_tv.xml
+++ b/packages/SystemUI/res/values-es/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Micrófono activado"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ha accedido a tu micrófono"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"La VPN está conectada"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"La VPN está desconectada"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index d8ec8be5d922..c11f21ce80ed 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Proovige ekraanipilt uuesti jäädvustada"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Piiratud salvestusruumi tõttu ei saa ekraanipilti salvestada"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Rakendus või teie organisatsioon ei luba ekraanipilte jäädvustada"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Ekraanipildi muutmine"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Sule ekraanipilt"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Muutmine"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Ekraanipildi muutmine"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Kerimine"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Ekraanipildi kerimine"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekraanipildist loobumine"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekraanipildi eelvaade"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekraanisalvesti"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Aku: kaks pulka."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Aku: kolm pulka."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Aku täis."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Aku laetuse protsent on teadmata."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Telefonisignaal puudub"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefonisignaal: üks pulk."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefonisignaal: kaks pulka."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Märguandest on loobutud."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Mullist loobuti."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Märguande vari."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Kiirseaded."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kuva lukustamine."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Kas jätkata selle rakenduse märguannete kuvamist?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Hääletu"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Vaikeseade"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Mull"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaatne"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ilma heli ja vibreerimiseta"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ilma heli ja vibreerimiseta, kuvatakse vestluste jaotises allpool"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Seaded"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteetne"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestlusfunktsioone"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Hiljutisi mulle pole"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Siin kuvatakse hiljutised ja suletud mullid."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Neid märguandeid ei saa muuta."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Seda märguannete rühma ei saa siin seadistada"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Puhvriga märguanne"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Seadme teenused"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Pealkiri puudub"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Puudutage rakenduse taaskäivitamiseks ja täisekraanrežiimi aktiveerimiseks."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> mullide seaded"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Ületäide"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Lisa tagasi virna"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Halda"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> rakendusest <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> rakenduselt <xliff:g id="APP_NAME">%2$s</xliff:g> ja veel <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Teisalda"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Teisalda üles vasakule"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Teisalda üles paremale"</string>
- <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="1314082410868930066">"Sule mull"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ära kuva vestlust mullina"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Vestelge mullide abil"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Uued vestlused kuvatakse hõljuvate ikoonidena ehk mullidena. Puudutage mulli avamiseks. Lohistage mulli, et seda liigutada."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Juhtige mulle igal ajal"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Selle rakenduse puhul mullide väljalülitamiseks puudutage valikut Halda"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Selge"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Rakenduse <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> seaded"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Uue seadme sidumine"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Järgunumber"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Järgunumber kopeeriti lõikelauale."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probleem akumõõdiku lugemisel"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Puudutage lisateabe saamiseks"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings_tv.xml b/packages/SystemUI/res/values-et/strings_tv.xml
index 61c14356809b..c59b5bcc4e29 100644
--- a/packages/SystemUI/res/values-et/strings_tv.xml
+++ b/packages/SystemUI/res/values-et/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon on aktiivne"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s pääses teie mikrofonile juurde"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN on ühendatud"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN-i ühendus on katkestatud"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"VPN-i <xliff:g id="VPN_APP">%1$s</xliff:g> kaudu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 8aa247f64591..835449f9939e 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Saiatu berriro pantaila-argazkia ateratzen"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Ezin da gorde pantaila-argazkia ez delako gelditzen tokirik"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikazioak edo erakundeak ez du onartzen pantaila-argazkiak ateratzea"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Editatu pantaila-argazkia"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Baztertu pantaila-argazkia"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Editatu"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Editatu pantaila-argazkia"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Egin gora eta behera"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Pantaila-argazki etengabea"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Baztertu pantaila-argazkia"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pantaila-argazkiaren aurrebista"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Pantaila-grabagailua"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pantaila-grabaketa prozesatzen"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Bateriak bi barra ditu."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Bateriak hiru barra ditu."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria beteta dago."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Bateriaren ehunekoa ezezaguna da."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ez dago telefono-zenbakirik."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefono-seinaleak barra bat du."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefono-seinaleak bi barra ditu."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Jakinarazpena baztertu da."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Baztertu da globoa."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Jakinarazpenen panela."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ezarpen bizkorrak."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantaila blokeatzeko aukera."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Aplikazio honen jakinarazpenak erakusten jarraitzea nahi duzu?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Isila"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Balio lehenetsia"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Burbuila"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatikoa"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ez du tonurik jotzen edo dar-dar egiten"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ez du tonurik jotzen edo dar-dar egiten, eta elkarrizketaren atalaren behealdean agertzen da"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ezarpenak"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Lehentasuna"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez ditu onartzen elkarrizketetarako eginbideak"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ez dago azkenaldiko burbuilarik"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Azken burbuilak eta baztertutakoak agertuko dira hemen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Jakinarazpen horiek ezin dira aldatu."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Jakinarazpen talde hau ezin da konfiguratu hemen"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Proxy bidezko jakinarazpena"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Gailuetarako zerbitzuak"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ez du izenik"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Berrabiarazi aplikazio hau eta ezarri pantaila osoko modua."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren ezarpenen burbuilak"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Gainezkatzea"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Gehitu berriro errenkadan"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Kudeatu"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioaren \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" jakinarazpena, eta beste <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Eraman"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Eraman goialdera, ezkerretara"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Eraman goialdera, eskuinetara"</string>
- <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="1314082410868930066">"Baztertu burbuila"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ez erakutsi elkarrizketak burbuila gisa"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Txateatu burbuilen bidez"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Elkarrizketa berriak ikono gainerakor edo burbuila gisa agertzen dira. Sakatu burbuila irekitzeko. Arrasta ezazu mugitzeko."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrolatu burbuilak edonoiz"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Aplikazioaren burbuilak desaktibatzeko, sakatu Kudeatu"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Ados"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> aplikazioaren ezarpenak"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parekatu beste gailu batekin"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Konpilazio-zenbakia"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Kopiatu da konpilazio-zenbakia arbelean."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Arazo bat gertatu da bateria-neurgailua irakurtzean"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Informazio gehiago lortzeko, sakatu hau"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings_tv.xml b/packages/SystemUI/res/values-eu/strings_tv.xml
index e77de5015fa1..67cb078b8788 100644
--- a/packages/SystemUI/res/values-eu/strings_tv.xml
+++ b/packages/SystemUI/res/values-eu/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofonoa aktibatuta dago"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s aplikazioak mikrofonoa atzitu du"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN sarera konektatuta dago"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ez dago sarera konektatuta"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> bidez"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d4f62520cfe8..55ca0f30c63f 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"دوباره نماگرفت بگیرید"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"به دلیل محدود بودن فضای ذخیره‌سازی نمی‌توان نماگرفت را ذخیره کرد"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"برنامه یا سازمان شما اجازه نمی‌دهند نماگرفت بگیرید."</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"ویرایش نماگرفت"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"رد کردن نماگرفت"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"ویرایش"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"ویرایش نماگرفت"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"پیمایش"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"نماگرفت پیمایشی"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"رد کردن نماگرفت"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"پیش‌نمایش نماگرفت"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ضبط‌کننده صفحه‌نمایش"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"درحال پردازش ضبط صفحه‌نمایش"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"دو نوار برای باتری."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"سه نوار برای باتری."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"باتری پر است."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"درصد شارژ باتری مشخص نیست."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"بدون تلفن."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"یک نوار برای تلفن."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"دو نوار برای تلفن."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"اعلان ردشد."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"حبابک رد شد."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"مجموعه اعلان."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"تنظیمات سریع."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"صفحه قفل."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"نمایش اعلان از این برنامه ادامه یابد؟"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"بی‌صدا"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"پیش‌فرض"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"حباب"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"خودکار"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"بدون صدا یا لرزش"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"بدون صدا و لرزش در پایین بخش مکالمه نشان داده می‌شود"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"تنظیمات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"اولویت"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ویژگی‌های مکالمه پشتیبانی نمی‌کند"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"هیچ حبابک جدیدی وجود ندارد"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"حبابک‌ها اخیر و حبابک‌ها ردشده اینجا ظاهر خواهند شد"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"این اعلان‌ها قابل اصلاح نیستند."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"نمی‌توانید این گروه اعلان‌ها را در اینجا پیکربندی کنید"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"اعلان‌های دارای پراکسی"</string>
@@ -800,8 +798,8 @@
<string name="keyboard_key_media_previous" msgid="5637875709190955351">"قبلی"</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">"صفحه بعدی"</string>
- <string name="keyboard_key_page_down" msgid="9035902490071829731">"صفحه قبلی"</string>
+ <string name="keyboard_key_page_up" msgid="173914303254199845">"صفحه بعد"</string>
+ <string name="keyboard_key_page_down" msgid="9035902490071829731">"صفحه قبل"</string>
<string name="keyboard_key_forward_del" msgid="5325501825762733459">"حذف"</string>
<string name="keyboard_key_move_home" msgid="3496502501803911971">"ابتدا"</string>
<string name="keyboard_key_move_end" msgid="99190401463834854">"انتها"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"سرویس‌های دستگاه"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"بدون عنوان"</string>
<string name="restart_button_description" msgid="6916116576177456480">"برای بازراه‌اندازی این برنامه و تغییر به حالت تمام‌صفحه، ضربه بزنید."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"تنظیمات برای حبابک‌های <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"لبریزشده"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"افزودن برگشت به پشته"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"مدیریت"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g> و <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> مورد بیشتر"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"انتقال"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"انتقال به بالا سمت راست"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"انتقال به بالا سمت چپ"</string>
- <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="1314082410868930066">"رد کردن حبابک"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"مکالمه در حباب نشان داده نشود"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"گپ بااستفاده از حبابک‌ها"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"مکالمه‌های جدید به‌صورت نمادهای شناور یا حبابک‌ها نشان داده می‌شوند. برای باز کردن حبابک‌ها ضربه بزنید. برای جابه‌جایی، آن را بکشید."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"کنترل حبابک‌ها در هرزمانی"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"برای خاموش کردن «حبابک‌ها» از این برنامه، روی «مدیریت» ضربه بزنید"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"متوجه‌ام"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"تنظیمات <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"مرتبط کردن دستگاه جدید"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"شماره ساخت"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"شماره ساخت در بریده‌دان کپی شد."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"مشکلی در خواندن میزان باتری وجود دارد"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"برای اطلاعات بیشتر ضربه بزنید"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
index bf3987d6e10d..37aaa6408d76 100644
--- a/packages/SystemUI/res/values-fa/strings_tv.xml
+++ b/packages/SystemUI/res/values-fa/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"میکروفون فعال است"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"‏%1$s به میکروفون شما دسترسی پیدا کرد"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"‏VPN متصل است"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"‏VPN قطع است"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ازطریق <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 0ed15093096e..f5441a28d65e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Yritä ottaa kuvakaappaus uudelleen."</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Kuvakaappauksen tallennus epäonnistui, sillä tallennustilaa ei ole riittävästi"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Sovellus tai organisaatio ei salli kuvakaappauksien tallentamista."</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Muokkaa kuvakaappausta"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Hylkää kuvakaappaus"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Muuta"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Muokkaa kuvakaappausta"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Vieritä"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Vieritä kuvakaappausta"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Hylkää kuvakaappaus"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Kuvakaappauksen esikatselu"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Näytön tallentaja"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Näytön tallennusta käsitellään"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Akun virta - kaksi palkkia."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Akun virta - kolme palkkia."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Akku täynnä."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akun varaustaso ei tiedossa."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ei puhelinverkkoyhteyttä."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Puhelinverkkosignaali - yksi palkki."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Puhelinverkkosignaali - kaksi palkkia."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Ilmoitus hylätty."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Kupla ohitettu."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Ilmoitusalue."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Pika-asetukset."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lukitse näyttö."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Jatketaanko ilmoitusten näyttämistä tästä sovelluksesta?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Äänetön"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Oletus"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Kupla"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaattinen"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ei ääntä tai värinää"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ei ääntä tai värinää ja näkyy alempana keskusteluosiossa"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Asetukset"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Tärkeä"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskusteluominaisuuksia"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ei viimeaikaisia kuplia"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Viimeaikaiset ja äskettäin ohitetut kuplat näkyvät täällä"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Näitä ilmoituksia ei voi muokata"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Tätä ilmoitusryhmää ei voi määrittää tässä"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Välitetty ilmoitus"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Laitepalvelut"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ei nimeä"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Napauta, niin sovellus käynnistyy uudelleen ja siirtyy koko näytön tilaan."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Kuplien asetukset: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Ylivuoto"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Lisää takaisin pinoon"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Ylläpidä"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>: <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>) ja <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> muuta"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Siirrä"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Siirrä vasempaan yläreunaan"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Siirrä oikeaan yläreunaan"</string>
- <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="1314082410868930066">"Ohita kupla"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Älä näytä kuplia keskusteluista"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chattaile kuplien avulla"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Uudet keskustelut näkyvät kelluvina kuvakkeina tai kuplina. Avaa kupla napauttamalla. Siirrä sitä vetämällä."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Muuta kuplien asetuksia milloin tahansa"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Valitse Ylläpidä, jos haluat poistaa kuplat käytöstä tästä sovelluksesta"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Selvä"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: asetukset"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Muodosta uusi laitepari"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Koontiversion numero"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Koontiversion numero kopioitu leikepöydälle"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ongelma akkumittarin lukemisessa"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Saat lisätietoja napauttamalla"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings_tv.xml b/packages/SystemUI/res/values-fi/strings_tv.xml
index 0b1f02f4cad4..295780b7abdb 100644
--- a/packages/SystemUI/res/values-fi/strings_tv.xml
+++ b/packages/SystemUI/res/values-fi/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofoni aktiivinen"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s sai pääsyn mikrofoniisi"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN on yhdistetty"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ei ole yhdistettynä"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Palvelun <xliff:g id="VPN_APP">%1$s</xliff:g> kautta"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index c7e827fbce21..332b4402c63a 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Essayez de faire une autre capture d\'écran"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Impossible d\'enregistrer la capture d\'écran, car l\'espace de stockage est limité"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'application ou votre organisation n\'autorise pas les saisies d\'écran"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Modifier la capture d\'écran"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Fermer la capture d\'écran"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Modifier"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Modifier la capture d\'écran"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Faire défiler"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Faire défiler la capture d\'écran"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Fermer la capture d\'écran"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Aperçu de la capture d\'écran"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Trait. de l\'enregist. d\'écran…"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Niveau de batterie : moyen"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Niveau de batterie : bon"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batterie pleine"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la pile inconnu."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Aucun signal"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Signal : faible"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Signal : moyen"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification masquée"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bulle ignorée."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Volet des notifications"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Paramètres rapides"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Écran de verrouillage"</string>
@@ -522,7 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"le profil peut être contrôlé"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Le réseau peut être surveillé"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Le réseau peut être surveillé"</string>
- <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Cet appareil est géré par votre parent"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Cet appareil est géré par ton parent"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Votre organisation possède cet appareil et peut contrôler le trafic réseau"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> possède cet appareil et peut contrôler le trafic réseau"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Cet appareil appartient à votre organisation et est connecté à <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Continuer à afficher les notifications de cette application?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Mode silencieux"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Par défaut"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bulle"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatique"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Aucun son ni vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Aucun son ni vibration, et s\'affiche plus bas dans la section des conversations"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorité"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne prend pas en charge les fonctionnalités de conversation"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Aucune bulle récente"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bulles récentes et les bulles ignorées s\'afficheront ici"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ces notifications ne peuvent pas être modifiées"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ce groupe de notifications ne peut pas être configuré ici"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notification par mandataire"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Services de l\'appareil"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Touchez pour redémarrer cette application et passer en plein écran."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Paramètres pour les bulles de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menu déroulant"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Replacer sur la pile"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Gérer"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> et <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> autres"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Déplacer"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Déplacer dans coin sup. gauche"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Déplacer dans coin sup. droit"</string>
- <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="1314082410868930066">"Ignorer la bulle"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne pas afficher les conversations dans des bulles"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Clavarder en utilisant des bulles"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes (de bulles). Touchez une bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Paramètres des bulles"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toucher Gérer pour désactiver les bulles de cette application"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Paramètres <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un autre appareil"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de version"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Le numéro de version a été copié dans le presse-papiers."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu lors de la lecture du niveau de charge de la pile"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Touchez pour en savoir plus"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
index 23dd656c431f..696e95980dbf 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Microphone actif"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s a accédé à votre microphone"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"RPV connecté"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"RPV déconnecté"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Par <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 781a43cefce1..62e653c6f5dc 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Essayez de nouveau de faire une capture d\'écran"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Impossible d\'enregistrer la capture d\'écran, car l\'espace de stockage est limité"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Les captures d\'écran ne sont pas autorisées par l\'application ni par votre organisation"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Modifier la capture d\'écran"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Fermer la capture d\'écran"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Modifier"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Modifier la capture d\'écran"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Faire défiler"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Faire défiler la capture d\'écran"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Fermer la capture d\'écran"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Aperçu de la capture d\'écran"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Enregistreur d\'écran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Enregistrement de l\'écran…"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Niveau de batterie : moyen"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Niveau de batterie : bon"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batterie pleine"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pourcentage de la batterie inconnu."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Aucun signal"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Signal : faible"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Signal : moyen"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notification masquée"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bulle fermée."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Volet des notifications"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Paramètres rapides"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Écran de verrouillage"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Continuer d\'afficher les notifications de cette application ?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silencieux"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Par défaut"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bulle"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatique"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Aucun son ni vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Aucun son ni vibration, s\'affiche plus bas dans la section des conversations"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec les fonctionnalités de conversation"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Aucune bulle récente"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bulles récentes et ignorées s\'afficheront ici"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossible de modifier ces notifications."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Vous ne pouvez pas configurer ce groupe de notifications ici"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notification de proxy"</string>
@@ -869,7 +867,7 @@
<string name="right_icon" msgid="1103955040645237425">"Icône droite"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Sélectionnez et faites glisser les icônes pour les ajouter"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Sélectionnez et faites glisser les icônes pour réorganiser"</string>
- <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Faites glisser les tuiles ici pour les supprimer."</string>
+ <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Faites glisser les icônes ici pour les supprimer."</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Au minimum <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> tuiles sont nécessaires"</string>
<string name="qs_edit" msgid="5583565172803472437">"Modifier"</string>
<string name="tuner_time" msgid="2450785840990529997">"Heure"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Services pour l\'appareil"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Appuyez pour redémarrer cette application et activer le mode plein écran."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Paramètres des bulles de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Dépassement"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Ajouter à nouveau l\'élément à la pile"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Gérer"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de l\'application <xliff:g id="APP_NAME">%2$s</xliff:g> et <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> autres"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Déplacer"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Déplacer en haut à gauche"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Déplacer en haut à droite"</string>
- <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="1314082410868930066">"Fermer la bulle"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne pas afficher la conversation dans une bulle"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatter en utilisant des bulles"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes ou bulles. Appuyez sur la bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Contrôler les paramètres des bulles"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Appuyez sur \"Gérer\" pour désactiver les bulles de cette application"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Paramètres <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Associer un nouvel appareil"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numéro de build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numéro de build copié dans le presse-papiers."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Un problème est survenu au niveau de la lecture de votre outil de mesure de batterie"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Appuyer pour en savoir plus"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings_tv.xml b/packages/SystemUI/res/values-fr/strings_tv.xml
index 4ab6a24b1aca..f2c5d976dd21 100644
--- a/packages/SystemUI/res/values-fr/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Micro actif"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s a accédé à votre micro"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN connecté"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN déconnecté"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 80fb4027a6a5..6cf18b8beed6 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Volve tentar crear unha captura de pantalla"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Non se puido gardar a captura de pantalla porque o espazo de almacenamento é limitado"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"A aplicación ou a túa organización non permite realizar capturas de pantalla"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Edita a captura de pantalla"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ignora a captura de pantalla"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar a captura de pantalla"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Desprazarse"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Realizar unha captura de pantalla continua"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignorar a captura de pantalla"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Vista previa da captura de pantalla"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravadora da pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando gravación pantalla"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dúas barras de batería"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Tres barras de batería"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batería cargada"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Descoñécese a porcentaxe da batería."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sen teléfono"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Unha barra de cobertura"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dúas barras de cobertura"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificación rexeitada"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Ignorouse a burbulla."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel despregable"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configuración rápida"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Pantalla de bloqueo."</string>
@@ -522,8 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"O perfil pódese supervisar"</string>
<string name="vpn_footer" msgid="3457155078010607471">"É posible que se supervise a rede"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"É posible que se supervise a rede"</string>
- <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
- <skip />
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"O teu pai ou nai xestiona este dispositivo"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"A túa organización é propietaria deste dispositivo e pode controlar o tráfico de rede"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> é a organización propietaria deste dispositivo e pode controlar o tráfico de rede"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Este dispositivo pertence á túa organización e está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -548,8 +548,7 @@
<string name="disable_vpn" msgid="482685974985502922">"Desactivar VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Desconectar VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Ver políticas"</string>
- <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
- <skip />
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Ver controis"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"Este dispositivo pertence a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nO teu administrador de TI pode supervisar e xestionar a configuración, o acceso corporativo, as aplicacións, os datos asociados co teu dispositivo e a información de localización deste último.\n\nPara obter máis información, contacta co teu administrador de TI."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"Este dispositivo pertence á túa organización.\n\nO teu administrador de TI pode supervisar e xestionar a configuración, o acceso corporativo, as aplicacións, os datos asociados co teu dispositivo e a información de localización deste último.\n\nPara obter máis información, contacta co teu administrador de TI."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"A túa organización instalou unha autoridade de certificación neste dispositivo. É posible que se controle ou se modifique o teu tráfico de rede segura."</string>
@@ -573,8 +572,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"O administrador activou o rexistro na rede, que controla o tráfico do teu dispositivo.\n\nPara obter máis información, contacta co administrador."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Outorgaches permiso a unha aplicación para configurar unha conexión VPN.\n\nEsta aplicación pode supervisar a túa actividade na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> xestiona o teu perfil de traballo.\n\nO administrador pode controlar a túa actividade na rede, mesmo os correos electrónicos, as aplicacións e os sitios web.\n\nPara obter máis información, ponte en contacto co administrador.\n\nTamén estás conectado a unha VPN, que pode controlar a túa actividade na rede."</string>
- <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
- <skip />
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"O teu pai ou nai xestiona este dispositivo. O teu pai ou nai pode ver e xestionar información como as aplicacións que usas, a túa localización e o tempo diante da pantalla."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode controlar a túa actividade na rede, mesmo os correos electrónicos, as aplicacións e os sitios web."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Estás conectado a <xliff:g id="APPLICATION">%1$s</xliff:g>, que pode supervisar a túa actividade persoal na rede, incluídos os correos electrónicos, as aplicacións e os sitios web."</string>
@@ -717,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Queres seguir mostrando as notificacións desta aplicación?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silenciosas"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Configuración predeterminada"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Burbulla"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sen son nin vibración"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sen son nin vibración, e aparecen máis abaixo na sección de conversas"</string>
@@ -729,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite funcións de conversa"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Non hai burbullas recentes"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"As burbullas recentes e ignoradas aparecerán aquí."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificacións non se poden modificar."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Aquí non se pode configurar este grupo de notificacións"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notificación mediante proxy"</string>
@@ -989,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Servizos do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sen título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toca o botón para reiniciar esta aplicación e abrila en pantalla completa."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configuración das burbullas de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Mostrar menú adicional"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Engadir de novo á pilla"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Xestionar"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> e <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> máis"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Mover"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Mover á parte super. esquerda"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover á parte superior dereita"</string>
- <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="1314082410868930066">"Ignorar burbulla"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Non mostrar a conversa como burbulla"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatear usando burbullas"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"As conversas novas aparecen como iconas flotantes ou burbullas. Toca para abrir a burbulla e arrastra para movela."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controla as burbullas"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Para desactivar as burbullas nesta aplicación, toca Xestionar"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Entendido"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Configuración de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1097,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Vincular dispositivo novo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número de compilación"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Copiouse o número de compilación no portapapeis."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Produciuse un problema ao ler o medidor da batería"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toca para obter máis información"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings_tv.xml b/packages/SystemUI/res/values-gl/strings_tv.xml
index 123a86ef8322..095386be9f71 100644
--- a/packages/SystemUI/res/values-gl/strings_tv.xml
+++ b/packages/SystemUI/res/values-gl/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Micrófono activo"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s accedeu ao teu micrófono"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"A VPN está conectada"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"A VPN está desconectada"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A través de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 85a084d10389..35d4e1a36fbe 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ફરીથી સ્ક્રીનશૉટ લેવાનો પ્રયાસ કરો"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"મર્યાદિત સ્ટોરેજ સ્પેસને કારણે સ્ક્રીનશૉટ સાચવી શકાતો નથી"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ઍપ્લિકેશન કે તમારી સંસ્થા દ્વારા સ્ક્રીનશૉટ લેવાની મંજૂરી નથી"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"સ્ક્રીનશૉટમાં ફેરફાર કરો"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"સ્ક્રીનશૉટ છોડી દો"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"ફેરફાર કરો"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"સ્ક્રીનશૉટમાં ફેરફાર કરો"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"સ્ક્રોલ કરો"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"સ્ક્રીનશૉટ પર સ્ક્રોલ કરો"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"સ્ક્રીનશૉટ છોડી દો"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"સ્ક્રીનશૉટનો પ્રીવ્યૂ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"સ્ક્રીન રેકૉર્ડર"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"સ્ક્રીન રેકૉર્ડિંગ ચાલુ છે"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"બૅટરી બે બાર."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"બૅટરી ત્રણ બાર."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"બૅટરી પૂર્ણ."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"બૅટરીની ટકાવારી અજાણ છે."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"કોઈ ફોન નથી."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ફોન એક બાર."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ફોન બે બાર."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"સૂચના કાઢી નાખી."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"બબલ છોડી દેવાયો."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"નોટિફિકેશન શેડ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ઝડપી સેટિંગ્સ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"લૉક સ્ક્રીન."</string>
@@ -522,8 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"પ્રોફાઇલ મૉનિટર કરી શકાય છે"</string>
<string name="vpn_footer" msgid="3457155078010607471">"નેટવર્ક મૉનિટર કરી શકાય છે"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"નેટવર્ક મૉનિટર કરવામાં આવી શકે છે"</string>
- <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
- <skip />
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"આ ડિવાઇસ તમારા માતાપિતા દ્વારા મેનેજ કરવામાં આવે છે"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"તમારી સંસ્થા આ ડિવાઇસની માલિકી ધરાવે છે અને નેટવર્ક ટ્રાફિકનું નિરીક્ષણ કરી શકે છે"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"આ ડિવાઇસ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ની માલિકીનું છે અને નેટવર્ક ટ્રાફિકનું નિરીક્ષણ કરી શકે છે"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"આ ડિવાઇસ તમારી સંસ્થાની માલિકીનું છે અને <xliff:g id="VPN_APP">%1$s</xliff:g>થી કનેક્ટ કરેલું છે"</string>
@@ -548,8 +548,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN અક્ષમ કરો"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN ડિસ્કનેક્ટ કરો"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"નીતિઓ જુઓ"</string>
- <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
- <skip />
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"નિયંત્રણો જુઓ"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"આ ડિવાઇસ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ની માલિકીનું છે.\n\nતમારા IT વ્યવસ્થાપક સેટિંગ, કૉર્પોરેટ ઍક્સેસ, ઍપ, તમારા ડિવાઇસ સાથે સંકળાયેલો ડેટા અને તમારા ડિવાઇસની સ્થાન માહિતીનું નિરીક્ષણ તેમજ તેને મેનેજ કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા IT વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"આ ડિવાઇસ તમારી સંસ્થાની માલિકીનું છે.\n\nતમારા IT વ્યવસ્થાપક સેટિંગ, કૉર્પોરેટ ઍક્સેસ, ઍપ, તમારા ડિવાઇસ સાથે સંકળાયેલો ડેટા અને તમારા ડિવાઇસની સ્થાન માહિતીનું નિરીક્ષણ તેમજ તેને મેનેજ કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા IT વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"તમારી સંસ્થાએ આ ઉપકરણ પર પ્રમાણપત્ર સત્તાધિકારી ઇન્સ્ટૉલ કર્યું છે. તમારા સુરક્ષિત નેટવર્ક ટ્રાફિકનું નિયમન થઈ શકે છે અથવા તેમાં ફેરફાર કરવામાં આવી શકે છે."</string>
@@ -560,7 +559,7 @@
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"તમે <xliff:g id="VPN_APP_0">%1$s</xliff:g> અને <xliff:g id="VPN_APP_1">%2$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટ સહિત તમારી નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરી શકે છે."</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
<string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"તમારી વ્યક્તિગત પ્રોફાઇલ <xliff:g id="VPN_APP">%1$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
- <string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"તમારું ઉપકરણ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે."</string>
+ <string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"તમારું ડિવાઇસ <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> દ્વારા મેનેજ થાય છે."</string>
<string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>, તમારા ઉપકરણનું સંચાલન કરવા માટે <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> નો ઉપયોગ કરે છે."</string>
<string name="monitoring_description_do_body" msgid="7700878065625769970">"વ્યવસ્થાપક સેટિંગ્સ, કૉર્પોરેટ ઍક્સેસ, ઍપ્સ, તમારા ઉપકરણ સંબંદ્ધ ડેટા અને ઉપકરણની સ્થાન માહિતીનું નિરીક્ષણ અને સંચાલન કરી શકે છે."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string>
@@ -573,14 +572,13 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"તમારા વ્યવસ્થાપકે નેટવર્ક લૉગિંગ ચાલુ કર્યુ છે, જે તમારા ઉપકરણ પર ટ્રાફિકનું નિરીક્ષણ કરે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"તમે VPN કનેક્શન સેટ કરવા માટે ઍપ્લિકેશન પરવાનગી આપી.\n\nઆ ઍપ્લિકેશન ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારા ઉપકરણ અને નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"તમારી કાર્ય પ્રોફાઇલનું સંચાલન <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા કરવામાં આવે છે.\n\n તમારા વ્યવસ્થાપક ઇમેઇલ, ઍપ્લિકેશનો, અને વેબસાઇટો સહિતની તમારી કાર્ય નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરવામાં સક્ષમ છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો.\n\nતમે VPN સાથે પણ કનેક્ટ કરેલ છે, જે તમારી નેટવર્ક પ્રવૃત્તિનું નિરીક્ષણ કરી શકે છે."</string>
- <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
- <skip />
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"આ ડિવાઇસ તમારા માતાપિતા દ્વારા મેનેજ કરવામાં આવે છે. તમે જેનો ઉપયોગ કરો છો તે ઍપ, તમારું સ્થાન અને તમારા સ્ક્રીન સમય જેવી માહિતીને તમારા માતાપિતા જોઈ અને મેનેજ કરી શકે છે."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયા છો, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિતની તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
<string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
- <string name="monitoring_description_app_work" msgid="3713084153786663662">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. આ પ્રોફાઇલ <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિત તમારા કાર્યાલયના નેટવર્કની પ્રવૃત્તિનું નિયમન કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
- <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="monitoring_description_app_work" msgid="3713084153786663662">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા મેનેજ થાય છે. આ પ્રોફાઇલ <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ થયેલ છે, જે ઇમેઇલ, ઍપ અને વેબસાઇટ સહિત તમારા કાર્યાલયના નેટવર્કની પ્રવૃત્તિનું નિયમન કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
+ <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>
@@ -717,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"આ ઍપમાંથી નોટિફિકેશન બતાવવાનું ચાલુ રાખીએ?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"સાઇલન્ટ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ડિફૉલ્ટ"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"બબલ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ઑટોમૅટિક રીતે"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"કોઈપણ સાઉન્ડ અથવા વાઇબ્રેશન નથી"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"કોઈપણ સાઉન્ડ અથવા વાઇબ્રેશન નથી અને વાતચીત વિભાગમાં તે વધુ નીચેની દિશાએ દેખાય છે"</string>
@@ -729,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"સેટિંગ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"પ્રાધાન્યતા"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીતની સુવિધાઓને સપોર્ટ આપતી નથી"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"તાજેતરના કોઈ બબલ નથી"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"એકદમ નવા બબલ અને છોડી દીધેલા બબલ અહીં દેખાશે"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"આ નોટિફિકેશનમાં કોઈ ફેરફાર થઈ શકશે નહીં."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"નોટિફિકેશનના આ ગ્રૂપની ગોઠવણી અહીં કરી શકાશે નહીં"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"પ્રૉક્સી નોટિફિકેશન"</string>
@@ -989,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"ડિવાઇસ સેવાઓ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"કોઈ શીર્ષક નથી"</string>
<string name="restart_button_description" msgid="6916116576177456480">"આ ઍપ ફરીથી ચાલુ કરવા માટે ટૅપ કરીને પૂર્ણ સ્ક્રીન કરો."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> બબલ માટેનાં સેટિંગ"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ઓવરફ્લો"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"સ્ટૅકમાં ફરી ઉમેરો"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"મેનેજ કરો"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> તરફથી <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> અને વધુ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> તરફથી <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"ખસેડો"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ઉપર ડાબે ખસેડો"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ઉપર જમણે ખસેડો"</string>
- <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="1314082410868930066">"બબલને છોડી દો"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"વાતચીતને બબલ કરશો નહીં"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"બબલનો ઉપયોગ કરીને ચેટ કરો"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"નવી વાતચીત ફ્લોટિંગ આઇકન અથવા બબલ જેવી દેખાશે. બબલને ખોલવા માટે ટૅપ કરો. તેને ખસેડવા માટે ખેંચો."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"બબલને કોઈપણ સમયે નિયંત્રિત કરો"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"આ ઍપમાંથી બબલને બંધ કરવા માટે મેનેજ કરો પર ટૅપ કરો"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"સમજાઈ ગયું"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> સેટિંગ"</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>
@@ -1097,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"બિલ્ડ નંબર"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"બિલ્ડ નંબર ક્લિપબૉર્ડ પર કૉપિ કર્યો."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"તમારું બૅટરી મીટર વાંચવામાં સમસ્યા આવી"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"વધુ માહિતી માટે ટૅપ કરો"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings_tv.xml b/packages/SystemUI/res/values-gu/strings_tv.xml
index 72a6803aa202..297b6e1a5511 100644
--- a/packages/SystemUI/res/values-gu/strings_tv.xml
+++ b/packages/SystemUI/res/values-gu/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"માઇક્રોફોન સક્રિય છે"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$sએ તમારો માઇક્રોફોન ઍક્સેસ કર્યો હતો"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN કનેક્ટ કરેલું છે"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ડિસ્કનેક્ટ કરેલું છે"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> મારફતે"</string>
</resources>
diff --git a/packages/SystemUI/res/values-h740dp-port/dimens.xml b/packages/SystemUI/res/values-h740dp-port/dimens.xml
index 966066ffe56b..4a23ee637e2d 100644
--- a/packages/SystemUI/res/values-h740dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-h740dp-port/dimens.xml
@@ -19,9 +19,9 @@
<dimen name="qs_tile_margin_vertical">24dp</dimen>
<!-- The height of the qs customize header. Should be
- (qs_panel_padding_top (48dp) + brightness_mirror_height (48dp) + qs_tile_margin_top (18dp)) -
+ (qs_panel_padding_top (48dp) + brightness_mirror_height (56dp) + qs_tile_margin_top (18dp)) -
(Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (12dp))
-->
- <dimen name="qs_customize_header_min_height">46dp</dimen>
+ <dimen name="qs_customize_header_min_height">54dp</dimen>
<dimen name="qs_tile_margin_top">18dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 9eeba1724393..1d02fd0b5e3a 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"स्क्रीनशॉट दोबारा लेने की कोशिश करें"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"मेमोरी कम होने की वजह से स्क्रीनशॉट सेव नहीं किया जा सका"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ऐप्लिकेशन या आपका संगठन स्क्रीनशॉट लेने की अनुमति नहीं देता"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"स्क्रीनशॉट में बदलाव करें"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"स्क्रीनशॉट खारिज करें"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"बदलाव करें"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"स्क्रीनशॉट में बदलाव करें"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"स्क्रोल करें"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रीनशॉट को स्क्रोल करें"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रीनशॉट को खारिज करें"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉट की झलक"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रिकॉर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रिकॉर्डिंग को प्रोसेस किया जा रहा है"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"बैटरी दो बार."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"बैटरी तीन बार."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"बैटरी पूरी है."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"इस बारे में जानकारी नहीं है कि अभी बैटरी कितने प्रतिशत चार्ज है."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"कोई फ़ोन नहीं."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"फ़ोन एक बार."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"फ़ोन दो बार."</string>
@@ -259,7 +261,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"सूचना खारिज की गई."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"बबल खारिज किया गया."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"त्वरित सेटिंग."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string>
@@ -573,7 +574,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"आपके एडमिन ने नेटवर्क लॉग करना चालू कर दिया है, जो आपके डिवाइस पर ट्रैफ़िक की निगरानी करता है.\n\nज़्यादा जानकारी के लिए अपने एडमिन से संपर्क करें."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"आपने किसी ऐप को VPN कनेक्‍शन सेट करने की अनुमति दी है.\n\nयह ऐप ईमेल, ऐप्‍स और सुरक्षित वेबसाइटों सहित आपके डिवाइस और नेटवर्क की गतिविधि की निगरानी कर सकता है."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> आपकी वर्क प्रोफ़ाइल को प्रबंधित करता है.\n\n आपका एडमिन ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nऔर जानकारी के लिए अपने एडमिन से संपर्क करें.\n\nआप ऐसे VPN से भी कनेक्‍ट हैं, जो आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
- <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"इस डिवाइस का प्रबंधन आपके अभिभावक करते हैं. अभिभावक आपके डिवाइस से जुड़ी जानकारी देख सकते हैं और उस जानकारी को प्रबंधित कर सकते हैं. इनमें, आपके इस्तेमाल किए गए ऐप्लिकेशन की जानकारी, आपकी जगह की जानकारी, और डिवाइस के इस्तेमाल में बिताए गए समय जैसी जानकारी शामिल हैं."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"इस डिवाइस का प्रबंधन आपके अभिभावक करते हैं. अभिभावक आपके डिवाइस से जुड़ी जानकारी देख सकते हैं और उसे प्रबंधित कर सकते हैं. इनमें, आपके इस्तेमाल किए गए ऐप्लिकेशन, जगह की जानकारी, और डिवाइस के इस्तेमाल में बिताए गए समय जैसी जानकारी शामिल है."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"वीपीएन"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्‍ट हैं, जो ईमेल, ऐप्‍स और वेबसाइटों सहित आपकी व्‍यक्‍तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
@@ -716,7 +717,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"इस ऐप्लिकेशन से जुड़ी सूचनाएं दिखाना जारी रखें?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"आवाज़ के बिना सूचनाएं दिखाएं"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"डिफ़ॉल्ट"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"बबल"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"अपने-आप"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"किसी तरह की आवाज़ या वाइब्रेशन न हो"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"इससे किसी तरह की आवाज़ या वाइब्रेशन नहीं होता और बातचीत, सेक्शन में सबसे नीचे दिखती है"</string>
@@ -728,8 +728,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिंग"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर बातचीत की सुविधाएं काम नहीं करतीं"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"हाल ही के बबल्स मौजूद नहीं हैं"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"हाल ही के बबल्स और हटाए गए बबल्स यहां दिखेंगे"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ये सूचनाएं नहीं बदली जा सकती हैं."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"सूचनाओं के इस समूह को यहां कॉन्फ़िगर नहीं किया जा सकता"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"प्रॉक्सी सूचना"</string>
@@ -988,25 +986,7 @@
<string name="device_services" msgid="1549944177856658705">"डिवाइस सेवाएं"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"कोई शीर्षक नहीं"</string>
<string name="restart_button_description" msgid="6916116576177456480">"इस ऐप्लिकेशन को रीस्टार्ट करने और फ़ुल स्क्रीन चालू करने के लिए टैप करें."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> बबल्स की सेटिंग"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ओवरफ़्लो"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"स्टैक में वापस जोड़ें"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"प्रबंधित करें"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> से <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> और <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> अन्य ऐप्लिकेशन से <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"ले जाएं"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"सबसे ऊपर बाईं ओर ले जाएं"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"सबसे ऊपर दाईं ओर ले जाएं"</string>
- <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="1314082410868930066">"बबल खारिज करें"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"बातचीत को बबल न करें"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"बबल्स का इस्तेमाल करके चैट करें"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"नई बातचीत फ़्लोटिंग आइकॉन या बबल्स की तरह दिखेंगी. बबल को खोलने के लिए टैप करें. इसे एक जगह से दूसरी जगह ले जाने के लिए खींचें और छोड़ें."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"जब चाहें, बबल्स को कंट्रोल करें"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"इस ऐप्लिकेशन पर बबल्स को बंद करने के लिए \'प्रबंधित करें\' पर टैप करें"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ठीक है"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> की सेटिंग"</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>
@@ -1096,8 +1076,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नया डिवाइस जोड़ें"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर को क्लिपबोर्ड पर कॉपी किया गया."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"आपके डिवाइस के बैटरी मीटर की रीडिंग लेने में समस्या आ रही है"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ज़्यादा जानकारी के लिए टैप करें"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings_tv.xml b/packages/SystemUI/res/values-hi/strings_tv.xml
index 9282c3c4b861..d2ce7a9a23f8 100644
--- a/packages/SystemUI/res/values-hi/strings_tv.xml
+++ b/packages/SystemUI/res/values-hi/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"माइक्रोफ़ोन चालू है"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ने आपका माइक्रोफ़ोन ऐक्सेस किया था"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"वीपीएन कनेक्ट हो गया है"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"वीपीएन डिसकनेक्ट हो गया है"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> के ज़रिए"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 86523ece41c2..9c4939cd5383 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Pokušajte ponovo napraviti snimku zaslona"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Zaslon nije snimljen zbog ograničenog prostora za pohranu"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikacija ili vaša organizacija ne dopuštaju snimanje zaslona"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Uređivanje snimke zaslona"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Odbacivanje snimke zaslona"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Uredi"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Uređivanje snimke zaslona"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Pomakni"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Pomicanje snimke zaslona"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Odbacivanje snimke zaslona"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pregled snimke zaslona"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snimač zaslona"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrada snimanja zaslona"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterija dva stupca."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterija tri stupca."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterija je puna."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Postotak baterije nije poznat."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nema telefona."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefonski signal jedan stupac."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefonski signal dva stupca."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Obavijest je odbačena."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Oblačić odbačen."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Zaslon obavijesti."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Brze postavke."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaključavanje zaslona."</string>
@@ -525,7 +526,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil se možda nadzire"</string>
<string name="vpn_footer" msgid="3457155078010607471">"Mreža se možda nadzire"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"Mreža se možda nadzire"</string>
- <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Ovim uređajem upravlja vaš roditelj"</string>
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Ovim uređajem upravlja tvoj roditelj"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Vaša je organizacija vlasnik ovog uređaja i može nadzirati mrežni promet"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"Organizacija <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> vlasnik je ovog uređaja i može nadzirati mrežni promet"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"Ovaj uređaj pripada vašoj organizaciji i povezan je s mrežom <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -574,7 +575,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Administrator je uključio mrežni zapisnik koji prati promet na vašem uređaju.\n\nViše informacija možete saznati od administratora."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Dali ste dopuštenje aplikaciji za postavljanje VPN veze.\n\nTa aplikacija može nadzirati vašu aktivnost na uređaju i mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Vašim radnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nVaš administrator može nadzirati vašu mrežnu aktivnost, uključujući e-poštu, aplikacije i web-lokacije.\n\nViše informacija možete saznati od administratora.\n\nPovezani ste i s VPN-om koji može nadzirati vašu mrežnu aktivnost."</string>
- <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Ovim uređajem upravlja vaš roditelj. Vaš roditelj može vidjeti podatke, kao što su aplikacije koje koristite, lokacija i vrijeme upotrebe te upravljati njima."</string>
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Ovim uređajem upravlja tvoj roditelj. Tvoj roditelj može vidjeti podatke kao što su aplikacije kojima se koristiš, lokaciju i vrijeme upotrebe te upravljati njima."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu aktivnost na mreži, uključujući e-poruke, aplikacije i web-lokacije."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"Povezani ste s aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g> koja može nadzirati vašu osobnu aktivnost na mreži, uključujući e-poštu, aplikacije i web-lokacije."</string>
@@ -717,7 +718,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Želite li da se obavijesti te aplikacije nastave prikazivati?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Bešumno"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Zadano"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Oblačić"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatski"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez zvuka ili vibracije"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Bez zvuka ili vibracije i prikazuje se pri dnu odjeljka razgovora"</string>
@@ -729,8 +729,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Postavke"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava značajke razgovora"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nema nedavnih oblačića"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Ovdje će se prikazivati nedavni i odbačeni oblačići"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Te se obavijesti ne mogu izmijeniti."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ta se grupa obavijesti ne može konfigurirati ovdje"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Obavijest poslana putem proxyja"</string>
@@ -991,25 +989,7 @@
<string name="device_services" msgid="1549944177856658705">"Usluge uređaja"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Dodirnite da biste ponovo pokrenuli tu aplikaciju i prikazali je na cijelom zaslonu."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Postavke za oblačiće za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Dodatno"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Dodajte natrag u nizove"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Upravljanje"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Premjesti"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Premjesti u gornji lijevi kut"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premjesti u gornji desni kut"</string>
- <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="1314082410868930066">"Odbaci oblačić"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Zaustavi razgovor u oblačićima"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Oblačići u chatu"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi razgovori pojavljuju se kao pomične ikone ili oblačići. Dodirnite za otvaranje oblačića. Povucite da biste ga premjestili."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Upravljanje oblačićima u svakom trenutku"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljanje da biste isključili oblačiće iz ove aplikacije"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Shvaćam"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Postavke za <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1100,8 +1080,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Upari novi uređaj"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Broj međuverzije"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Broj međuverzije kopiran je u međuspremnik."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem s očitavanjem mjerača baterije"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dodirnite za više informacija"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings_tv.xml b/packages/SystemUI/res/values-hr/strings_tv.xml
index 59dcd0ceadbb..ee29a6c1ee70 100644
--- a/packages/SystemUI/res/values-hr/strings_tv.xml
+++ b/packages/SystemUI/res/values-hr/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon aktivan"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacija %1$s pristupila je mikrofonu"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN je spojen"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN je isključen"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Putem mreže <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 32ca37d1a321..2feb1b258370 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Próbálja meg újra elkészíteni a képernyőképet"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Nem menthet képernyőképet, mert kevés a tárhely"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Az alkalmazás vagy az Ön szervezete nem engedélyezi képernyőkép készítését"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Képernyőkép szerkesztése"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Képernyőkép elvetése"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Szerkesztés"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Képernyőkép szerkesztése"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Görgetés"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Görgethető képernyőkép"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Képernyőkép elvetése"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Képernyőkép előnézete"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Képernyőrögzítő"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Képernyőrögzítés feldolgozása"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Akkumulátor két sáv."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Akkumulátor három sáv."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Akkumulátor feltöltve."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Az akkumulátor töltöttségi szintje ismeretlen."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nincs telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon egy sáv."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon két sáv."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Értesítés elvetve."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Buborék elvetve."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Értesítési felület."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Gyorsbeállítások."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lezárási képernyő."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Továbbra is megjelenjenek az alkalmazás értesítései?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Néma"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Alapértelmezett"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Buborék"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatikus"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Nincs hang és rezgés"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nincs hang és rezgés, továbbá lejjebb jelenik meg a beszélgetések szakaszában"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Beállítások"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritás"</string>
<string name="no_shortcut" msgid="8257177117568230126">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> nem támogatja a beszélgetési funkciókat"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nincsenek buborékok a közelmúltból"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"A legutóbbi és az elvetett buborékok itt jelennek majd meg"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ezeket az értesítéseket nem lehet módosítani."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Az értesítések jelen csoportját itt nem lehet beállítani"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Továbbított értesítés"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Eszközszolgáltatások"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nincs cím"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Koppintson az alkalmazás újraindításához és a teljes képernyős mód elindításához."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g>-buborékok beállításai"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"További elemeket tartalmazó menü"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Visszaküldés a verembe"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Kezelés"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> a(z) <xliff:g id="APP_NAME">%2$s</xliff:g> alkalmazásból és <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> további"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Áthelyezés"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Áthelyezés fel és balra"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Áthelyezés fel és jobbra"</string>
- <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="1314082410868930066">"Buborék elvetése"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne jelenjen meg a beszélgetés buborékban"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Buborékokat használó csevegés"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Az új beszélgetések lebegő ikonként, vagyis buborékként jelennek meg. A buborék megnyitásához koppintson rá. Áthelyezéshez húzza a kívánt helyre."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Buborékok vezérlése bármikor"</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="bubbles_user_education_got_it" msgid="8282812431953161143">"Értem"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> beállításai"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Új eszköz párosítása"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Buildszám"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Buildszám a vágólapra másolva."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probléma merült fel az akkumulátor-töltésmérő olvasásakor"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Koppintással további információkat érhet el."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings_tv.xml b/packages/SystemUI/res/values-hu/strings_tv.xml
index 548207244ad0..cbbebb0710d6 100644
--- a/packages/SystemUI/res/values-hu/strings_tv.xml
+++ b/packages/SystemUI/res/values-hu/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"A mikrofon aktív"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"A(z) %1$s hozzáfért a mikrofonhoz"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"A VPN-kapcsolat létrejött"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"A VPN-kapcsolat megszakadt"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A következő szolgáltatás használatával: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 15fbf706f9c1..0258e44ee64b 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Փորձեք նորից"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Չհաջողվեց պահել սքրինշոթը անբավարար հիշողության պատճառով"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Հավելվածը կամ ձեր կազմակերպությունը չի թույլատրում սքրինշոթի ստացումը"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Փոփոխել սքրինշոթը"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Փակել սքրինշոթը"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Փոփոխել"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Փոփոխել սքրինշոթը"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Ոլորել"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Ոլորել սքրինշոթը"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Փակել սքրինշոթը"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Սքրինշոթի նախադիտում"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Էկրանի տեսագրիչ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Էկրանի տեսագրության մշակում"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Մարտկոցի երկու գիծ:"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Մարտկոցի երեք գիծ:"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Մարտկոցը լիքն է:"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Մարտկոցի լիցքի մակարդակն անհայտ է։"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Հեռախոս չկա:"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Հեռախոսի մեկ գիծ:"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Հեռախոսի երկու գիծ:"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Ծանուցումը անտեսվեց:"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Ամպիկը փակվեց։"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Ծանուցումների վահանակ:"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Արագ կարգավորումներ:"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Էկրանի կողպում:"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Ցուցադրե՞լ ծանուցումներ այս հավելվածից։"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Անձայն"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Կանխադրված"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Պղպջակ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Ավտոմատ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Առանց ձայնի կամ թրթռոցի"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Հայտնվում է զրույցների ցանկի ներքևում, առանց ձայնի և թրթռոցի"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Կարգավորումներ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Կարևոր"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը զրույցի գործառույթներ չի աջակցում"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ամպիկներ չկան"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Այստեղ կցուցադրվեն վերջերս օգտագործված և փակված ամպիկները, որոնք կկարողանաք հեշտությամբ վերաբացել"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Այս ծանուցումները չեն կարող փոփոխվել:"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ծանուցումների տվյալ խումբը հնարավոր չէ կարգավորել այստեղ"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Ծանուցումն ուղարկվել է պրոքսի սերվերի միջոցով"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Սարքի ծառայություններ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Անանուն"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Հպեք՝ հավելվածը վերագործարկելու և լիաէկրան ռեժիմին անցնելու համար։"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ի ամպիկների կարգավորումներ"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Լրացուցիչ ընտրացանկ"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Նորից ավելացնել զտիչներում"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Կառավարել"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>՝ <xliff:g id="APP_NAME">%2$s</xliff:g>-ից"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>` <xliff:g id="APP_NAME">%2$s</xliff:g>-ից ու ևս <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ամպիկ"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Տեղափոխել"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Տեղափոխել վերև՝ ձախ"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Տեղափոխել վերև՝ աջ"</string>
- <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="1314082410868930066">"Փակել ամպիկը"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Զրույցը չցուցադրել ամպիկի տեսքով"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Զրույցի ամպիկներ"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Նոր զրույցները կհայտնվեն լողացող պատկերակների կամ ամպիկների տեսքով։ Հպեք՝ ամպիկը բացելու համար։ Քաշեք՝ այն տեղափոխելու համար։"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Ամպիկների կարգավորումներ"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Հպեք «Կառավարել» կոճակին՝ այս հավելվածի ամպիկներն անջատելու համար։"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Եղավ"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – կարգավորումներ"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Նոր սարքի զուգակցում"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Կառուցման համարը"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Կառուցման համարը պատճենվեց սեղմատախտակին։"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Մարտկոցի ցուցիչի ցուցմունքը կարդալու հետ կապված խնդիր կա"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Հպեք՝ ավելին իմանալու համար"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings_tv.xml b/packages/SystemUI/res/values-hy/strings_tv.xml
index 4009335ec7d5..58c514931cc6 100644
--- a/packages/SystemUI/res/values-hy/strings_tv.xml
+++ b/packages/SystemUI/res/values-hy/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Խոսափողն ակտիվացված է"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s հավելվածն օգտագործել է ձեր խոսափողը"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN-ը միացված է"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN-ն անջատված է"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-ի միջոցով"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index cf6a20dd7ba1..bea37ae65dba 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Coba ambil screenshot lagi"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Tidak dapat menyimpan screenshot karena ruang penyimpanan terbatas"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Mengambil screenshot tidak diizinkan oleh aplikasi atau organisasi"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Edit screenshot"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Menutup screenshot"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Mengedit screenshot"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scroll"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Men-scroll screenshot"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Menutup screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pratinjau screenshot"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Perekam Layar"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses perekaman layar"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterai dua batang."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterai tiga batang."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterai penuh."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Persentase baterai tidak diketahui."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Tidak dapat melakukan panggilan."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Ponsel satu batang."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Ponsel dua batang."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notifikasi disingkirkan."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balon ditutup."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bayangan pemberitahuan."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Setelan cepat."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Layar kunci."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Terus tampilkan notifikasi dari aplikasi ini?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Senyap"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Default"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Balon"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatis"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Tidak ada suara atau getaran"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Tidak ada suara atau getaran dan ditampilkan lebih rendah di bagian percakapan"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Setelan"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritas"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung fitur percakapan"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Tidak ada balon baru-baru ini"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Balon yang baru dipakai dan balon yang telah ditutup akan muncul di sini"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Notifikasi ini tidak dapat diubah."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Grup notifikasi ini tidak dapat dikonfigurasi di sini"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notifikasi proxy"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Layanan Perangkat"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Tanpa judul"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Ketuk untuk memulai ulang aplikasi ini dan membuka layar penuh."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Setelan untuk balon <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Tambahan"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Tambahkan kembali ke stack"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Kelola"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> dari <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> dari <xliff:g id="APP_NAME">%2$s</xliff:g> dan <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> lainnya"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Pindahkan"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Pindahkan ke kiri atas"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pindahkan ke kanan atas"</string>
- <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pindahkan ke kiri bawah"</string>
- <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pindahkan ke kanan bawah"</string>
- <string name="bubble_dismiss_text" msgid="1314082410868930066">"Tutup balon"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Jangan gunakan percakapan balon"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat dalam tampilan balon"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Percakapan baru muncul sebagai ikon mengambang, atau balon. Ketuk untuk membuka balon. Tarik untuk memindahkannya."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrol balon kapan saja"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Ketuk Kelola untuk menonaktifkan balon dari aplikasi ini"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Oke"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Setelan <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigasi sistem diupdate. Untuk melakukan perubahan, buka Setelan."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Buka Setelan untuk mengupdate navigasi sistem"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Siaga"</string>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sambungkan perangkat baru"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nomor versi"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nomor versi disalin ke papan klip."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Terjadi masalah saat membaca indikator baterai"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ketuk untuk informasi selengkapnya"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
index 670f8125582a..bdd6742c39cf 100644
--- a/packages/SystemUI/res/values-in/strings_tv.xml
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon Aktif"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s mengakses mikrofon"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN tersambung"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN terputus"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Melalui <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index ca40b6f63cf5..7c7902faad2e 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Prófaðu að taka skjámynd aftur"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Ekki tókst að vista skjámynd vegna takmarkaðs geymslupláss"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Forritið eða fyrirtækið þitt leyfir ekki skjámyndatöku"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Breyta skjámynd"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Loka skjámynd"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Breyta"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Breyta skjámynd"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Fletta"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Flettiskjáskot"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Loka skjámynd"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Forskoðun skjámyndar"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skjáupptaka"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Vinnur úr skjáupptöku"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Tvö strik á rafhlöðu."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Þrjú strik á rafhlöðu."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Rafhlaða fullhlaðin."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Staða rafhlöðu óþekkt."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ekkert símasamband."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Styrkur símasambands er eitt strik."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Styrkur símasambands er tvö strik."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Tilkynningu lokað."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Blöðru lokað."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Tilkynningasvæði."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Flýtistillingar."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lásskjár."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Sýna áfram tilkynningar frá þessu forriti?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Hljóðlaust"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Sjálfgefið"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Blaðra"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Sjálfvirk"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ekkert hljóð eða titringur"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ekkert hljóð eða titringur og birtist neðar í samtalshluta"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Áfram"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Forgangur"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki samtalseiginleika"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Engar nýlegar blöðrur"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nýlegar blöðrur og blöðrur sem þú hefur lokað birtast hér"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ekki er hægt að breyta þessum tilkynningum."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ekki er hægt að stilla þessar tilkynningar hér"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Staðgengilstilkynning"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Tækjaþjónusta"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Enginn titill"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Ýttu til að endurræsa forritið og sýna það á öllum skjánum."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Stillingar fyrir blöðrur frá <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Yfirflæði"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Bæta aftur í stafla"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Stjórna"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> frá <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ frá <xliff:g id="APP_NAME">%2$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> í viðbót"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Færa"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Færa efst til vinstri"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Færa efst til hægri"</string>
- <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="1314082410868930066">"Loka blöðru"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ekki setja samtal í blöðru"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Spjalla með blöðrum"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Ný samtöl birtast sem fljótandi tákn eða blöðrur. Ýttu til að opna blöðru. Dragðu hana til að færa."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Hægt er að stjórna blöðrum hvenær sem er"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Ýttu á „Stjórna“ til að slökkva á blöðrum frá þessu forriti"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Ég skil"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Stillingar <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Para nýtt tæki"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Útgáfunúmer smíðar"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Útgáfunúmer smíðar afritað á klippiborð."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Vandamál við að lesa stöðu rafhlöðu"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ýttu til að fá frekari upplýsingar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings_tv.xml b/packages/SystemUI/res/values-is/strings_tv.xml
index 27334af093f5..88a43159c064 100644
--- a/packages/SystemUI/res/values-is/strings_tv.xml
+++ b/packages/SystemUI/res/values-is/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Hljóðnemi virkur"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s fékk aðgang að hljóðnemanum þínum"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN er tengt"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN er ekki tengt"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Í gegnum <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index f3436e97b3e7..026b5a98a682 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Riprova ad acquisire lo screenshot"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Impossibile salvare lo screenshot a causa dello spazio di archiviazione limitato"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"L\'acquisizione di screenshot non è consentita dall\'app o dall\'organizzazione"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Modifica screenshot"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ignora screenshot"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Modifica"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Modifica screenshot"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scorri"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Scorri screenshot"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignora screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Anteprima screenshot"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Registrazione dello schermo"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Elaboraz. registraz. schermo"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batteria: due barre."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batteria: tre barre."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batteria carica."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percentuale della batteria sconosciuta."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nessun telefono."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefono: una barra."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefono: due barre."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notifica eliminata."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Fumetto ignorato."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Area notifiche."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Impostazioni rapide."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Schermata di blocco."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Continuare a ricevere notifiche da questa app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Modalità silenziosa"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Modalità predefinita"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Fumetto"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatico"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Nessun suono o vibrazione"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nessun suono o vibrazione e appare più in basso nella sezione delle conversazioni"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Impostazioni"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorità"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le funzionalità delle conversazioni"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nessuna bolla recente"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Le bolle recenti e ignorate appariranno qui"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossibile modificare queste notifiche."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Qui non è possibile configurare questo gruppo di notifiche"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notifica inviata al proxy"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Servizi del dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Senza titolo"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tocca per riavviare l\'app e passare a schermo intero."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Impostazioni per bolle <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Altre"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Aggiungi di nuovo all\'elenco"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Gestisci"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g> e altre <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Sposta"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Sposta in alto a sinistra"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sposta in alto a destra"</string>
- <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="1314082410868930066">"Ignora bolla"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Non mettere la conversazione nella bolla"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatta utilizzando le bolle"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Le nuove conversazioni vengono visualizzate come icone mobili o bolle. Tocca per aprire la bolla. Trascinala per spostarla."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controlla le bolle quando vuoi"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tocca Gestisci per disattivare le bolle dall\'app"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Impostazioni <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Accoppia nuovo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numero build copiato negli appunti."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema durante la lettura dell\'indicatore di livello della batteria"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tocca per ulteriori informazioni"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings_tv.xml b/packages/SystemUI/res/values-it/strings_tv.xml
index e0fce871895a..97badc1e2180 100644
--- a/packages/SystemUI/res/values-it/strings_tv.xml
+++ b/packages/SystemUI/res/values-it/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Microfono attivo"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ha avuto accesso al tuo microfono"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN connessa"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN disconnessa"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Tramite <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index fc915a13ffbb..b4df62b5207e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"יש לנסות שוב לבצע צילום מסך"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"לא היה מספיק מקום לשמור את צילום המסך"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"האפליקציה או הארגון שלך אינם מתירים ליצור צילומי מסך"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"עריכת צילום מסך"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"סגירת צילום מסך"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"עריכה"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"עריכת צילום מסך"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"גלילה"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"צילום מסך נגלל"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"סגירת צילום מסך"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"תצוגה מקדימה של צילום מסך"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"מקליט המסך"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"מתבצע עיבוד של הקלטת מסך"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"שני פסים של סוללה."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"שלושה פסים של סוללה."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"סוללה מלאה."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"אחוז טעינת הסוללה לא ידוע."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"אין טלפון."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"פס אחד של טלפון."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"שני פסים של טלפון."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"התראה נדחתה."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"הבועה נסגרה."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"לוח התראות."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"הגדרות מהירות."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"מסך נעילה."</string>
@@ -720,7 +721,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"שנמשיך להציג לך התראות מהאפליקציה הזאת?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"שקט"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ברירת מחדל"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"בועה"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"באופן אוטומטי"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ללא צליל או רטט"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ללא צליל או רטט ומופיעה למטה בקטע התראות השיחה"</string>
@@ -732,8 +732,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"הגדרות"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"עדיפות"</string>
<string name="no_shortcut" msgid="8257177117568230126">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בתכונות השיחה"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"אין בועות מהזמן האחרון"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"בועות אחרונות ובועות שנסגרו יופיעו כאן"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"לא ניתן לשנות את ההתראות האלה."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"לא ניתן להגדיר כאן את קבוצת ההתראות הזו"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"‏התראה דרך שרת proxy"</string>
@@ -996,25 +994,7 @@
<string name="device_services" msgid="1549944177856658705">"שירותים למכשיר"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ללא שם"</string>
<string name="restart_button_description" msgid="6916116576177456480">"צריך להקיש כדי להפעיל מחדש את האפליקציה הזו ולעבור למסך מלא."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"הגדרות בשביל בועות של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"גלישה"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"הוספה בחזרה לערימה"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"ניהול"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מהאפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מ-<xliff:g id="APP_NAME">%2$s</xliff:g> ועוד <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"העברה"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"העברה לפינה השמאלית העליונה"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"העברה לפינה הימנית העליונה"</string>
- <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="1314082410868930066">"סגירת בועה"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"אין להציג בועות לשיחה"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"לדבר בבועות"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"שיחות חדשות מופיעות כסמלים צפים, או בועות. יש להקיש כדי לפתוח בועה. יש לגרור כדי להזיז אותה."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"שליטה בבועות, בכל זמן"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"יש להקיש על \'ניהול\' כדי להשבית את הבועות מהאפליקציה הזו"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"הבנתי"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"הגדרות <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1106,8 +1086,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"התאמה של מכשיר חדש"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"‏מספר Build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"‏מספר ה-Build הועתק ללוח."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"בעיה בקריאת מדדי הסוללה"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"יש להקיש כדי להציג מידע נוסף"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings_tv.xml b/packages/SystemUI/res/values-iw/strings_tv.xml
index 2bd86efa02a4..45d744ab8a57 100644
--- a/packages/SystemUI/res/values-iw/strings_tv.xml
+++ b/packages/SystemUI/res/values-iw/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"המיקרופון פעיל"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"‏%1$s קיבלה גישה למיקרופון שלך"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"‏VPN מחובר"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"‏VPN מנותק"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"באמצעות <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 74fd16afe655..be6f491b8356 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"スクリーンショットを撮り直してください"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"空き容量が足りないため、スクリーンショットを保存できません"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"スクリーンショットの作成はアプリまたは組織で許可されていません"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"スクリーンショットの編集"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"スクリーンショットを閉じます"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"編集"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"スクリーンショットを編集します"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"スクロール"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"スクリーンショットをスクロールします"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"スクリーンショットを閉じます"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"スクリーンショットのプレビュー"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"スクリーン レコーダー"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"画面の録画を処理しています"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"電池残量:レベル2"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"電池残量:レベル3"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"電池残量:満"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"電池残量は不明です。"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"電波状態:なし"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"電波状態:レベル1"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"電波状態:レベル2"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"通知が削除されました。"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ふきだしが非表示になっています。"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知シェード"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"クイック設定"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ロック画面"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"このアプリからの通知を今後も表示しますか?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"サイレント"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"デフォルト"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"バブル"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"自動"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"着信音もバイブレーションも無効です"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"着信音もバイブレーションも無効になり会話セクションの下に表示されます"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> は会話機能に対応していません"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近閉じたバブルはありません"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近表示されたバブルや閉じたバブルが、ここに表示されます"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"これらの通知は変更できません。"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"このグループの通知はここでは設定できません"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"代理通知"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"デバイス サービス"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"タイトルなし"</string>
<string name="restart_button_description" msgid="6916116576177456480">"タップしてこのアプリを再起動すると、全画面表示になります。"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> のバブルの設定"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"オーバーフロー"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"スタックに戻す"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"管理"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)、他 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 件"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"移動"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"左上に移動"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"右上に移動"</string>
- <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="1314082410868930066">"バブルを閉じる"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"会話をバブルで表示しない"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"チャットでバブルを使う"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"新しい会話はフローティング アイコン(バブル)として表示されます。タップするとバブルが開きます。ドラッグしてバブルを移動できます。"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"いつでもバブルを管理"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"このアプリからのバブルを OFF にするには、[管理] をタップしてください"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> の設定"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"新しいデバイスとのペア設定"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ビルド番号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ビルド番号をクリップボードにコピーしました。"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"電池残量の読み込み中に問題が発生しました"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"タップすると詳細が表示されます"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings_tv.xml b/packages/SystemUI/res/values-ja/strings_tv.xml
index 1e7d05bb3713..9d7a36a20f76 100644
--- a/packages/SystemUI/res/values-ja/strings_tv.xml
+++ b/packages/SystemUI/res/values-ja/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"マイク: 有効"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s がマイクにアクセスしました"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN に接続しました"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN に接続していません"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> 経由"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index b32937ef7c8a..6fdb8b89918f 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ხელახლა ცადეთ ეკრანის ანაბეჭდის გაკეთება"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"ეკრანის ანაბეჭდის შენახვა ვერ მოხერხდა შეზღუდული მეხსიერების გამო"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ეკრანის ანაბეჭდების შექმნა არ არის ნებადართული აპის ან თქვენი ორგანიზაციის მიერ"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"ეკრანის ანაბეჭდის რედაქტირება"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ეკრანის ანაბეჭდის დახურვა"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"რედაქტირება"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"ეკრანის ანაბეჭდის რედაქტირება"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"გრაგნილი"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"ეკრანის ანაბეჭდში გადაადგილება"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ეკრანის ანაბეჭდის დახურვა"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ეკრანის ანაბეჭდის გადახედვა"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ეკრანის ჩამწერი"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ეკრანის ჩანაწერი მუშავდება"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ბატარეა ორ ზოლზე."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ბატარეა სამ ზოლზე."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ბატარეა სავსეა."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ბატარეის პროცენტული მაჩვენებელი უცნობია."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"ტელეფონი არ არის."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ტელეფონის სიგნალი ერთ ზოლზეა."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ტელეფონის სიგნალი ორ ზოლზეა."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"შეტყობინება წაიშალა."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ბუშტი დაიხურა."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"შეტყობინებების ფარდა"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"სწრაფი პარამეტრები"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ეკრანის დაბლოკვა."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"გაგრძელდეს შეტყობინებათა ჩვენება ამ აპიდან?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ჩუმი"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ნაგულისხმევი"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"ბუშტი"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ავტომატური"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ხმისა და ვიბრაციის გარეშე"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ხმისა და ვიბრაციის გარეშე, ჩნდება მიმოწერების სექციის ქვედა ნაწილში"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"პარამეტრები"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"პრიორიტეტი"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს არ აქვს მიმოწერის ფუნქციების მხარდაჭერა"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ბოლო დროს გამოყენებული ბუშტები არ არის"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"აქ გამოჩნდება ბოლოდროინდელი ბუშტები და უარყოფილი ბუშტები"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ამ შეტყობინებების შეცვლა შეუძლებელია."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"შეტყობინებების ამ ჯგუფის კონფიგურირება აქ შეუძლებელია"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"პროქსირებული შეტყობინება"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"მოწყობილობის სერვისები"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"უსათაურო"</string>
<string name="restart_button_description" msgid="6916116576177456480">"შეეხეთ ამ აპის გადასატვირთად და გადადით სრულ ეკრანზე."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"პარამეტრები <xliff:g id="APP_NAME">%1$s</xliff:g> ბუშტებისთვის"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"გადავსება"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ისევ დამატება დასტაზე"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"მართვა"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g>-ისგან"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g>-დან და კიდევ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"გადატანა"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ზევით და მარცხნივ გადატანა"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"გადაანაცვლეთ ზევით და მარჯვნივ"</string>
- <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="1314082410868930066">"ბუშტის დახურვა"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"აიკრძალოს საუბრის ბუშტები"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"ჩეთი ბუშტების გამოყენებით"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"ახალი საუბრები გამოჩნდება როგორც მოტივტივე ხატულები ან ბუშტები. შეეხეთ ბუშტის გასახსნელად. გადაიტანეთ ჩავლებით."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ბუშტების ნებისმიერ დროს გაკონტროლება"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ამ აპის ბუშტების გამოსართავად შეეხეთ „მართვას“"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"გასაგებია"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-ის პარამეტრები"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ახალი მოწყობილობის დაწყვილება"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ანაწყობის ნომერი"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ანაწყობის ნომერი დაკოპირებულია გაცვლის ბუფერში."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"თქვენი ბატარეის მზომის წაკითხვასთან დაკავშირებით პრობლემა დაფიქსირდა"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"შეეხეთ მეტი ინფორმაციისთვის"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings_tv.xml b/packages/SystemUI/res/values-ka/strings_tv.xml
index 476658d816f2..0dc1e10cdc9f 100644
--- a/packages/SystemUI/res/values-ka/strings_tv.xml
+++ b/packages/SystemUI/res/values-ka/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"მიკროფონი აქტიურია"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s-მა გამოიყენა თქვენი მიკროფონი"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN დაკავშირებულია"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN გათიშულია"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-ის მიერ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index c01af11d24bc..160e05d3dbc7 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Қайта скриншот жасап көріңіз"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Жадтағы шектеулі бос орынға байланысты скриншот сақталмайды"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Қолданба немесе ұйым скриншоттар түсіруге рұқсат етпейді"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Скриншотты өзгерту"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Скриншотты жабу"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Өзгерту"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Скриншотты өзгерту"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Айналдыру"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Скриншотты айналдыру"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Скриншотты жабу"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Скриншотты алдын ала қарау"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Экран жазғыш"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экран жазғыш бейнесін өңдеу"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Батарея екі баған."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Батарея үш баған."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батарея толы."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарея зарядының мөлшері белгісіз."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Телефон жоқ."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Телефон бір баған."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Телефон екі баған."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Хабар алынып тасталды."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Қалқымалы анықтама өшірілді."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Хабарландыру тақтасы"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Жылдам параметрлер."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Бекіту экраны."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Осы қолданбаның хабарландырулары көрсетілсін бе?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Дыбыссыз"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Әдепкі"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Көпіршік"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматты"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Дыбыс не діріл қолданылмайды"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Дыбыс не діріл қолданылмайды, әңгімелер бөлімінің төмен жағында шығады"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Параметрлер"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маңызды"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгімелесу функцияларын қолдамайды."</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Жақындағы қалқыма хабарлар жоқ"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Соңғы және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Мұндай хабарландырулар бұл жерде конфигурацияланбайды."</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Прокси-сервер арқылы жіберілген хабарландыру"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Құрылғы қызметтері"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Атауы жоқ"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Бұл қолданбаны қайта қосып, толық экранға өту үшін түртіңіз."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> қалқыма хабарларының параметрлері"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Қосымша мәзір"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Стекке қайта енгізу"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Басқару"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> жіберген хабарландыру: <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасы жіберген <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> және тағы <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Жылжыту"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Жоғарғы сол жаққа жылжыту"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Жоғары оң жаққа жылжыту"</string>
- <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="1314082410868930066">"Қалқымалы хабарды жабу"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Әңгіменің қалқыма хабары көрсетілмесін"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Қалқыма хабарлар арқылы сөйлесу"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңа әңгімелер қалқыма белгішелер немесе хабарлар түрінде көрсетіледі. Қалқыма хабарды ашу үшін түртіңіз. Жылжыту үшін сүйреңіз."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Қалқыма хабарларды реттеу"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бұл қолданбадан қалқыма хабарларды өшіру үшін \"Басқару\" түймесін түртіңіз."</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Түсінікті"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> параметрлері"</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>
@@ -1091,11 +1071,9 @@
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> құрылғы таңдалды."</string>
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ажыратылған)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Қосылмады. Қайта қосылып көріңіз."</string>
- <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңа құрылғыны жұптау"</string>
+ <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңа құрылғымен жұптау"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Құрама нөмірі"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Құрама нөмірі буферге көшірілді."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батарея зарядының дерегі алынбай жатыр"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Толығырақ ақпарат алу үшін түртіңіз."</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings_tv.xml b/packages/SystemUI/res/values-kk/strings_tv.xml
index d4b3c73f8308..cc15978b5076 100644
--- a/packages/SystemUI/res/values-kk/strings_tv.xml
+++ b/packages/SystemUI/res/values-kk/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Микрофон қосулы"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s микрофоныңызды пайдаланды."</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN қосылған"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ажыратылған"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> арқылы жалғанған"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 652bf25b54bf..e559c1951c50 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"សាកល្បង​ថតរូបថត​អេក្រង់​ម្តងទៀត"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"មិនអាច​រក្សាទុក​រូបថតអេក្រង់​បានទេ ​ដោយសារ​ទំហំផ្ទុក​មានកម្រិតទាប"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ការថត​រូបអេក្រង់​មិនត្រូវ​បាន​អនុញ្ញាត​ដោយ​កម្មវិធី​នេះ ឬ​ស្ថាប័ន​របស់អ្នក"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"កែ​រូបថត​អេក្រង់"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ច្រានចោល​រូបថត​អេក្រង់"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"កែ"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"កែ​រូបថត​អេក្រង់"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"រំកិល"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"មុខងារ​ថតរូបថត​អេក្រង់​រំកិល"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ច្រានចោល​រូបថត​អេក្រង់"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ការមើល​រូបថត​អេក្រង់​សាកល្បង"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"មុខងារថត​អេក្រង់"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"កំពុង​ដំណើរការ​ការថតអេក្រង់"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ថ្ម​ពីរ​កាំ។"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ថ្ម​ទាំង​បី​​កាំ​។"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ថ្ម​ពេញ​ហើយ។"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"មិនដឹងអំពី​ភាគរយថ្មទេ។"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"គ្មាន​ទូរស័ព្ទ។"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"សេវា​ទូរស័ព្ទ​មួយ​កាំ។"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"សេវា​ទូរស័ព្ទ​ពីរ​កាំ។"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"បាន​បដិសេធ​ការ​ជូនដំណឹង"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"បានច្រានចោល​សារលេចឡើង។"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ពណ៌​ការ​ជូន​ដំណឹង"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ការ​កំណត់​រហ័ស។"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ចាក់​សោ​អេក្រង់។"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"បន្ត​បង្ហាញ​ការជូនដំណឹង​ពីកម្មវិធីនេះ?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ស្ងាត់"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"លំនាំដើម"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"ពពុះ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ស្វ័យប្រវត្តិ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"គ្មាន​សំឡេង ឬការញ័រទេ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"គ្មានសំឡេង ឬការញ័រ និងការបង្ហាញ​កម្រិតទាបជាង​នេះនៅក្នុង​ផ្នែកសន្ទនាទេ"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ការកំណត់"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"អាទិភាព"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើ​មុខងារ​សន្ទនា​បានទេ"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"មិនមាន​ពពុះ​ថ្មីៗ​ទេ"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ពពុះថ្មីៗ​ និង​ពពុះដែលបានបិទ​​នឹង​បង្ហាញ​នៅទីនេះ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"មិនអាច​កែប្រែ​ការជូនដំណឹង​ទាំងនេះ​បានទេ។"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"មិនអាច​កំណត់​រចនាសម្ព័ន្ធ​ក្រុមការជូនដំណឹងនេះ​នៅទីនេះ​បានទេ"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ការជូនដំណឹង​ជា​ប្រូកស៊ី"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"សេវាកម្មឧបករណ៍"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"គ្មាន​ចំណងជើង"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ចុចដើម្បី​ចាប់ផ្ដើម​កម្មវិធី​នេះឡើងវិញ រួចចូលប្រើ​ពេញអេក្រង់។"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"ការកំណត់​សម្រាប់​ពពុះ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ម៉ឺនុយបន្ថែម"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"បញ្ចូល​ទៅក្នុង​គំនរវិញ"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"គ្រប់គ្រង"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g> និង <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ទៀត"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"ផ្លាស់ទី"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ផ្លាស់ទីទៅផ្នែកខាងលើខាងឆ្វេង"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ផ្លាស់ទីទៅផ្នែកខាងលើខាងស្ដាំ"</string>
- <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="1314082410868930066">"ច្រានចោល​ពពុះ"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"កុំបង្ហាញ​ការសន្ទនា​ជាពពុះ"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"ជជែក​ដោយប្រើ​ពពុះ"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"ការសន្ទនាថ្មីៗ​បង្ហាញជា​​ពពុះ ឬរូបអណ្ដែត។ ចុច ដើម្បីបើក​ពពុះ។ អូស ដើម្បី​ផ្លាស់ទី​ពពុះនេះ។"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"គ្រប់គ្រង​​ពពុះ​បានគ្រប់ពេល"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ចុច \"គ្រប់គ្រង\" ដើម្បីបិទ​ពពុះពីកម្មវិធីនេះ"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"យល់ហើយ"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"ការកំណត់ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ផ្គូផ្គង​ឧបករណ៍ថ្មី"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"លេខ​កំណែបង្កើត"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"បានចម្លងលេខ​កំណែបង្កើតទៅឃ្លីបបត។"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"មានបញ្ហាក្នុង​ការអាន​ឧបករណ៍រង្វាស់កម្រិតថ្មរបស់អ្នក"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ចុចដើម្បីទទួលបាន​ព័ត៌មានបន្ថែម"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings_tv.xml b/packages/SystemUI/res/values-km/strings_tv.xml
index 685a5e482e89..f415a66658de 100644
--- a/packages/SystemUI/res/values-km/strings_tv.xml
+++ b/packages/SystemUI/res/values-km/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"មីក្រូហ្វូន​កំពុង​ដំណើរការ"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s បានចូលប្រើ​មីក្រូហ្វូន​របស់អ្នក"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ត្រូវបានភ្ជាប់"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ត្រូវបានផ្ដាច់"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"តាម​រយៈ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index aa6c34ed4806..f1210804841e 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಅನ್ನು ಪುನಃ ತೆಗೆದುಕೊಳ್ಳಲು ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"ಪರಿಮಿತ ಸಂಗ್ರಹಣೆ ಸ್ಥಳದ ಕಾರಣದಿಂದಾಗಿ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ಅಪ್ಲಿಕೇಶನ್ ಅಥವಾ ಸಂಸ್ಥೆಯು ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ಗಳನ್ನು ತೆಗೆಯುವುದನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಅನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಅನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"ಎಡಿಟ್ ಮಾಡಿ"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ಅನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"ಸ್ಕ್ರಾಲ್ ಮಾಡಿ"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಸ್ಕ್ರಾಲ್ ಮಾಡಿ"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಅನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ಸ್ಕ್ರೀನ್‍ಶಾಟ್‍ನ ಪೂರ್ವವೀಕ್ಷಣೆ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡರ್"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ಬ್ಯಾಟರಿ ಎರಡು ಪಟ್ಟಿಗಳು."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ಬ್ಯಾಟರಿ ಮೂರು ಪಟ್ಟಿಗಳು."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ಬ್ಯಾಟರಿ ಭರ್ತಿಯಾಗಿದೆ."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ಬ್ಯಾಟರಿ ಶೇಕಡಾವಾರು ತಿಳಿದಿಲ್ಲ."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"ಯಾವುದೇ ಫೋನ್ ಇಲ್ಲ."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ಪೋನ್ ಒಂದು ಪಟ್ಟಿ."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ಫೋನ್ ಎರಡು ಪಟ್ಟಿಗಳು."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ಅಧಿಸೂಚನೆ ವಜಾಗೊಂಡಿದೆ."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ಬಬಲ್ ವಜಾಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ಅಧಿಸೂಚನೆಯ ಛಾಯೆ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳು."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ಲಾಕ್‌ ಪರದೆ."</string>
@@ -522,8 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ಪ್ರೊಫೈಲ್ ಅನ್ನು ಪರಿವೀಕ್ಷಿಸಬಹುದಾಗಿದೆ"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದಾಗಿ"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ನೆಟ್‌ವರ್ಕ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದಾಗಿರುತ್ತದೆ"</string>
- <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
- <skip />
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ಈ ಸಾಧನವನ್ನು ನಿಮ್ಮ ಪೋಷಕರು ನಿರ್ವಹಿಸುತ್ತಿದ್ದಾರೆ"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಸಾಧನದ ಮಾಲೀಕತ್ವವನ್ನು ಹೊಂದಿದೆ ಮತ್ತು ಅದು ನೆಟ್‌ವರ್ಕ್ ಟ್ರಾಫಿಕ್‌ನ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ಈ ಸಾಧನದ ಮಾಲೀಕತ್ವವನ್ನು ಹೊಂದಿದೆ ಮತ್ತು ಅದು ನೆಟ್‌ವರ್ಕ್ ಟ್ರಾಫಿಕ್‌ನ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ಈ ಸಾಧನವು ನಿಮ್ಮ ಸಂಸ್ಥೆಗೆ ಸೇರಿದೆ ಮತ್ತು <xliff:g id="VPN_APP">%1$s</xliff:g> ಗೆ ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
@@ -548,8 +548,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN ಸಂಪರ್ಕಕಡಿತಗೊಳಿಸಿ"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"ಕಾರ್ಯನೀತಿಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
- <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
- <skip />
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"ನಿಯಂತ್ರಣಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"ಈ ಸಾಧನವು <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ಗೆ ಸೇರಿದೆ.\n\nಸೆಟ್ಟಿಂಗ್‌ಗಳು, ಕಾರ್ಪೊರೇಟ್ ಪ್ರವೇಶ, ಆ್ಯಪ್‌ಗಳು, ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಡೇಟಾ ಮತ್ತು ನಿಮ್ಮ ಸಾಧನದ ಸ್ಥಳದ ಮಾಹಿತಿಯನ್ನು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು ಮತ್ತು ನಿರ್ವಹಿಸಬಹುದು.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ಈ ಸಾಧನವು ನಿಮ್ಮ ಸಂಸ್ಥೆಗೆ ಸೇರಿದೆ.\n\nಸೆಟ್ಟಿಂಗ್‌ಗಳು, ಕಾರ್ಪೊರೇಟ್ ಪ್ರವೇಶ, ಆ್ಯಪ್‌ಗಳು, ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಡೇಟಾ ಮತ್ತು ನಿಮ್ಮ ಸಾಧನದ ಸ್ಥಳದ ಮಾಹಿತಿಯನ್ನು ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು ಮತ್ತು ನಿರ್ವಹಿಸಬಹುದು.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ ನಿಮ್ಮ IT ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಸಾಧನದಲ್ಲಿ ಪ್ರಮಾಣಪತ್ರ ಅಂಗೀಕಾರವನ್ನು ಸ್ಥಾಪಿಸಿದೆ. ನಿಮ್ಮ ಸುರಕ್ಷಿತ ನೆಟ್‌ವರ್ಕ್ ಟ್ರಾಫಿಕ್ ಅನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು ಅಥವಾ ಮಾರ್ಪಡಿಸಬಹುದು."</string>
@@ -573,8 +572,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ನೆಟ್‌ವರ್ಕ್ ಲಾಗಿಂಗ್ ಆನ್ ಮಾಡಿದ್ದಾರೆ. ಇದು ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಟ್ರಾಫಿಕ್ ಮೇಲೆ ನಿಗಾ ಇರಿಸುತ್ತದೆ.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗೆ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"ನೀವು VPN ಸಂಪರ್ಕ ಹೊಂದಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿ ನೀಡಿರುವಿರಿ.\n\nಈ ಅಪ್ಲಿಕೇಶನ್ ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಒಳಗೊಂಡಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ನಿರ್ವಹಿಸುತ್ತಿದೆ.\n\nಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳೂ ಸೇರಿದಂತೆ ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್‌ ಚಟುವಟಿಕೆಯ ಮೇಲೆ ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಗಾ ಇರಿಸಬಲ್ಲರು.\n\nಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ, ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.\n\nಅಲ್ಲದೇ, ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್‌ ಚಟುವಟಿಕೆಯ ನಿಗಾ ವಹಿಸುವ VPN ಗೂ ಸಹ ನೀವು ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
- <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
- <skip />
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ಈ ಸಾಧನವನ್ನು ನಿಮ್ಮ ಪೋಷಕರು ನಿರ್ವಹಿಸುತ್ತಿದ್ದಾರೆ. ನೀವು ಬಳಸುವ ಆ್ಯಪ್‌ಗಳು, ನಿಮ್ಮ ಸ್ಥಳ ಮತ್ತು ನಿಮ್ಮ ವೀಕ್ಷಣಾ ಅವಧಿಯಂತಹ ಮಾಹಿತಿಯನ್ನು ನಿಮ್ಮ ಪೋಷಕರು ನೋಡಬಹುದು ಮತ್ತು ನಿರ್ವಹಿಸಬಹುದು."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"ನೀವು <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ. ಇದು ನಿಮ್ಮ ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳೂ ಸೇರಿದಂತೆ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"ನೀವು ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯ ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದಾದ <xliff:g id="APPLICATION">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಿರಿ."</string>
@@ -717,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"ಈ ಅಪ್ಲಿಕೇಶನ್‌ನಿಂದ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸುತ್ತಲೇ ಇರಬೇಕೆ?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ನಿಶ್ಶಬ್ದ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ಡೀಫಾಲ್ಟ್"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"ಬಬಲ್"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ಸ್ವಯಂಚಾಲಿತ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ಯಾವುದೇ ಧ್ವನಿ ಅಥವಾ ವೈಬ್ರೇಷನ್‌ ಆಗುವುದಿಲ್ಲ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ಯಾವುದೇ ಧ್ವನಿ ಅಥವಾ ವೈಬ್ರೇಷನ್‌ ಆಗುವುದಿಲ್ಲ, ಸಂಭಾಷಣೆ ವಿಭಾಗದ ಕೆಳಭಾಗದಲ್ಲಿ ಗೋಚರಿಸುತ್ತದೆ"</string>
@@ -729,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ಆದ್ಯತೆ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"ಸಂವಾದ ಫೀಚರ್‌ಗಳನ್ನು <xliff:g id="APP_NAME">%1$s</xliff:g> ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಇಲ್ಲ"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಮತ್ತು ವಜಾಗೊಳಿಸಿದ ಬಬಲ್ಸ್ ಇಲ್ಲಿ ಗೋಚರಿಸುತ್ತವೆ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"ಈ ಗುಂಪಿನ ಅಧಿಸೂಚನೆಗಳನ್ನು ಇಲ್ಲಿ ಕಾನ್ಫಿಗರ್‌ ಮಾಡಲಾಗಿರುವುದಿಲ್ಲ"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ಪ್ರಾಕ್ಸಿ ಮಾಡಿದ ಅಧಿಸೂಚನೆಗಳು"</string>
@@ -989,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"ಸಾಧನ ಸೇವೆಗಳು"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ಯಾವುದೇ ಶೀರ್ಷಿಕೆಯಿಲ್ಲ"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಲು ಮತ್ತು ಪೂರ್ಣ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ನೋಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಬಬಲ್ಸ್‌ಗಾಗಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ಓವರ್‌ಫ್ಲೋ"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ಸ್ಟ್ಯಾಕ್‌ಗೆ ಪುನಃ ಸೇರಿಸಿ"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"ನಿರ್ವಹಿಸಿ"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> ಆ್ಯಪ್‌ನ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> ಮತ್ತು <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ಹೆಚ್ಚಿನವುಗಳ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"ಸರಿಸಿ"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ಎಡ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ಬಲ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
- <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="1314082410868930066">"ಬಬಲ್ ವಜಾಗೊಳಿಸಿ"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ಸಂಭಾಷಣೆಯನ್ನು ಬಬಲ್ ಮಾಡಬೇಡಿ"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"ಬಬಲ್ಸ್ ಬಳಸಿ ಚಾಟ್ ಮಾಡಿ"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"ಹೊಸ ಸಂಭಾಷಣೆಗಳು ತೇಲುವ ಐಕಾನ್‌ಗಳು ಅಥವಾ ಬಬಲ್ಸ್ ಆಗಿ ಗೋಚರಿಸುತ್ತವೆ. ಬಬಲ್ ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಅದನ್ನು ಡ್ರ್ಯಾಗ್ ಮಾಡಲು ಎಳೆಯಿರಿ."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಬಬಲ್ಸ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ಈ ಆ್ಯಪ್‌ನಿಂದ ಬಬಲ್ಸ್ ಅನ್ನು ಆಫ್ ಮಾಡಲು ನಿರ್ವಹಿಸಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ಅರ್ಥವಾಯಿತು"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</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>
@@ -1097,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ಬಿಲ್ಡ್ ಸಂಖ್ಯೆಯನ್ನು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ನಲ್ಲಿ ನಕಲಿಸಲಾಗಿದೆ."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ನಿಮ್ಮ ಬ್ಯಾಟರಿ ಮೀಟರ್ ಓದುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings_tv.xml b/packages/SystemUI/res/values-kn/strings_tv.xml
index 7db0c7080919..a9359639f573 100644
--- a/packages/SystemUI/res/values-kn/strings_tv.xml
+++ b/packages/SystemUI/res/values-kn/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"ಮೈಕ್ರೋಫೋನ್‌ ಸಕ್ರಿಯವಾಗಿದೆ"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ನಿಮ್ಮ ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ಪ್ರವೇಶಿಸಿದೆ"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ಕನೆಕ್ಷನ್ ಕಡಿತಗೊಂಡಿದೆ"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ಮೂಲಕ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 38648d0f5198..6db40c192aea 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"스크린샷을 다시 찍어 보세요."</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"저장용량이 부족하여 스크린샷을 저장할 수 없습니다"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"앱이나 조직에서 스크린샷 촬영을 허용하지 않습니다."</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"스크린샷 수정"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"스크린샷 닫기"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"수정"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"스크린샷 수정"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"스크롤"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"스크롤 스크린샷"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"스크린샷 닫기"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"스크린샷 미리보기"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"화면 녹화"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"화면 녹화 처리 중"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"배터리 막대가 두 개입니다."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"배터리 막대가 세 개입니다."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"배터리 충전이 완료되었습니다."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"배터리 잔량을 알 수 없습니다."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"휴대전화의 신호가 없습니다."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"휴대전화 신호 막대가 하나입니다."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"휴대전화 신호 막대가 두 개입니다."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"알림이 제거되었습니다."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"대화창을 닫았습니다."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"알림 세부정보"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"빠른 설정"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"화면을 잠급니다."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"이 앱의 알림을 계속 표시하시겠습니까?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"무음"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"기본값"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"버블"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"자동"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"소리 또는 진동 없음"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"소리나 진동이 울리지 않으며 대화 섹션 하단에 표시됨"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"설정"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"우선순위"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 대화 기능을 지원하지 않습니다."</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"최근 대화창 없음"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"최근 대화창과 내가 닫은 대화창이 여기에 표시됩니다."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"이 알림 그룹은 여기에서 설정할 수 없습니다."</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"프록시를 통한 알림"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"기기 서비스"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"제목 없음"</string>
<string name="restart_button_description" msgid="6916116576177456480">"탭하여 이 앱을 다시 시작하고 전체 화면으로 이동합니다."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> 대화창 설정"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"더보기"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"스택에 다시 추가"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"관리"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> 외 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>개의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"이동"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"왼쪽 상단으로 이동"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"오른쪽 상단으로 이동"</string>
- <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="1314082410868930066">"대화창 닫기"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"대화를 대화창으로 표시하지 않기"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"대화창으로 채팅하기"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"새로운 대화가 플로팅 아이콘인 대화창으로 표시됩니다. 대화창을 열려면 탭하세요. 드래그하여 이동할 수 있습니다."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"언제든지 대화창을 제어하세요"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"이 앱에서 대화창을 사용 중지하려면 관리를 탭하세요."</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"확인"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> 설정"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"새 기기와 페어링"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"빌드 번호"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"빌드 번호가 클립보드에 복사되었습니다."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"배터리 수준을 읽는 중에 문제가 발생함"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"탭하여 자세한 정보를 확인하세요."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings_tv.xml b/packages/SystemUI/res/values-ko/strings_tv.xml
index 10889705ddc3..8c3a8ea65de2 100644
--- a/packages/SystemUI/res/values-ko/strings_tv.xml
+++ b/packages/SystemUI/res/values-ko/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"마이크 사용 중"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s에서 내 마이크에 액세스했습니다."</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN에 연결됨"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN 연결이 해제됨"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>에 연결됨"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 2a4e077046f7..8a06ed67e2f8 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Скриншотту кайра тартып көрүңүз"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Сактагычта бош орун аз болгондуктан, скриншот сакталбай жатат"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Скриншот тартууга колдонмо же ишканаңыз тыюу салган."</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Скриншотту түзөтүү"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Скриншотту четке кагуу"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Түзөтүү"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Скриншотту түзөтүү"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Сыдыруу"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Скриншотту сыдырып кароо"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Скриншотту четке кагуу"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Скриншотту алдын ала көрүү"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"экрандан видео жаздырып алуу"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экрандан жаздырылып алынган видео иштетилүүдө"</string>
@@ -182,6 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Эки таякча батарея."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Үч таякча батарея."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батарея толук."</string>
+ <!-- String.format failed for translation -->
<!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
<skip />
<string name="accessibility_no_phone" msgid="8828412144430247025">"Телефон сигналы жок."</string>
@@ -257,7 +261,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Эскертме өчүрүлдү."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Калкып чыкма билдирме жабылды."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Билдирмелер тактасы."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Тез тууралоолор."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Кулпуланган экран."</string>
@@ -714,7 +717,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Бул колдонмонун билдирмелери көрсөтүлө берсинби?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Үнсүз"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Демейки"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Көбүк"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматтык"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Үнү чыкпайт жана дирилдебейт"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Үнү чыгып же дирилдебейт жана жазышуу бөлүмүнүн ылдый жагында көрүнөт"</string>
@@ -726,8 +728,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Жөндөөлөр"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маанилүүлүгү"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> жазышуу функцияларын колдоого албайт"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Азырынча эч нерсе жок"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Акыркы жана жабылган калкып чыкма билдирмелер ушул жерде көрүнөт"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бул билдирмелерди өзгөртүүгө болбойт."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Бул билдирмелердин тобун бул жерде конфигурациялоого болбойт"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Прокси билдирмеси"</string>
@@ -986,25 +986,7 @@
<string name="device_services" msgid="1549944177856658705">"Түзмөк кызматтары"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Аталышы жок"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Бул колдонмону өчүрүп күйгүзүп, толук экранга өтүү үчүн, таптап коюңуз."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> калкып чыкма билдирмелер жөндөөлөрү"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Кошумча меню"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Кайра топтомго кошуу"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Башкаруу"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> колдонмосунан <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> жана дагы <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> колдонмодон <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Жылдыруу"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Жогорку сол жакка жылдыруу"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Жогорку оң жакка жылдырыңыз"</string>
- <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="1314082410868930066">"Калкып чыкма билдирмени жабуу"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Жазышууда калкып чыкма билдирмелер көрүнбөсүн"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Калкып чыкма билдирмелер аркылуу маектешүү"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңы жазышуулар калкыма сүрөтчөлөр же калкып чыкма билдирмелер түрүндө көрүнөт. Калкып чыкма билдирмелерди ачуу үчүн таптап коюңуз. Жылдыруу үчүн сүйрөңүз."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Калкып чыкма билдирмелерди каалаган убакта көзөмөлдөңүз"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бул колдонмодогу калкып чыкма билдирмелерди өчүрүү үчүн, \"Башкарууну\" басыңыз"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Түшүндүм"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> жөндөөлөрү"</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>
@@ -1094,8 +1076,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Жаңы түзмөктү жупташтыруу"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Курама номери"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Курама номери алмашуу буферине көчүрүлдү."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Батареяңыздын кубаты аныкталбай жатат"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Кеңири маалымат алуу үчүн таптап коюңуз"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings_tv.xml b/packages/SystemUI/res/values-ky/strings_tv.xml
index b69b1c6e26b5..3be657c78b2c 100644
--- a/packages/SystemUI/res/values-ky/strings_tv.xml
+++ b/packages/SystemUI/res/values-ky/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Микрофон күйүк"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s микрофонуңузду колдонууда"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN туташтырылды"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ажыратылды"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> аркылуу"</string>
</resources>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index 2f7fbaff4ed2..46ec23c8cf2e 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -20,6 +20,9 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
+ <!-- The maximum number of tiles in the QuickQSPanel -->
+ <integer name="quick_qs_panel_max_columns">6</integer>
+
<!-- The maximum number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">2</integer>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index b584dfee1e60..51d7b8eff5fc 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -22,8 +22,6 @@
<dimen name="docked_divider_handle_width">2dp</dimen>
<dimen name="docked_divider_handle_height">16dp</dimen>
- <dimen name="brightness_mirror_height">40dp</dimen>
-
<dimen name="qs_tile_margin_top">8dp</dimen>
<dimen name="qs_tile_margin_vertical">0dp</dimen>
@@ -36,10 +34,6 @@
<dimen name="volume_tool_tip_right_margin">136dp</dimen>
<dimen name="volume_tool_tip_top_margin">12dp</dimen>
- <!-- Padding between status bar and bubbles when displayed in expanded state, smaller
- value in landscape since we have limited vertical space-->
- <dimen name="bubble_padding_top">4dp</dimen>
-
<dimen name="controls_activity_view_top_offset">25dp</dimen>
<dimen name="biometric_dialog_button_negative_max_width">140dp</dimen>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 93ecff09d6c4..b92c2c17e7f9 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ກະລຸນາລອງຖ່າຍຮູບໜ້າຈໍອີກຄັ້ງ"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"ບໍ່ສາມາດຖ່າຍຮູບໜ້າຈໍໄດ້ເນື່ອງຈາກພື້ນທີ່ຈັດເກັບຂໍ້ມູນມີຈຳກັດ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ແອັບ ຫຼື ອົງກອນຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ຖ່າຍຮູບໜ້າຈໍ"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"ແກ້ໄຂຮູບໜ້າຈໍ"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ປິດຮູບໜ້າຈໍ"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"ແກ້ໄຂ"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"ແກ້ໄຂຮູບໜ້າຈໍ"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"ເລື່ອນ"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"ເລື່ອນຮູບໜ້າຈໍ"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ປິດຮູບໜ້າຈໍ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ຕົວຢ່າງຮູບໜ້າຈໍ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ໂປຣແກຣມບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ກຳລັງປະມວນຜົນການບັນທຶກໜ້າຈໍ"</string>
@@ -256,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ປິດການແຈ້ງເຕືອນແລ້ວ."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ປິດ Bubble ໄສ້ແລ້ວ."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ໜ້າຈໍແຈ້ງເຕືອນ."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ການຕັ້ງຄ່າດ່ວນ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ລັອກ​ໜ້າ​ຈໍ."</string>
@@ -713,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"ສະແດງການແຈ້ງເຕືອນຈາກແອັບນີ້ຕໍ່ໄປບໍ?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ປິດສຽງ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ຄ່າເລີ່ມຕົ້ນ"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"ຟອງ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ອັດຕະໂນມັດ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ບໍ່ມີສຽງ ຫຼື ການສັ່ນເຕືອນ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ບໍ່ມີສຽງ ຫຼື ການສັ່ນເຕືອນ ແລະ ປາກົດຢູ່ທາງລຸ່ມຂອງພາກສ່ວນການສົນທະນາ"</string>
@@ -725,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ຕັ້ງຄ່າ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ສຳຄັນ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບຄຸນສົມບັດການສົນທະນາ"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ບໍ່ມີຟອງຫຼ້າສຸດ"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ຟອງຫຼ້າສຸດ ແລະ ຟອງທີ່ປິດໄປຈະປາກົດຢູ່ບ່ອນນີ້"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນເຫຼົ່ານີ້ໄດ້."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"ບໍ່ສາມາດຕັ້ງຄ່າກຸ່ມການແຈ້ງເຕືອນນີ້ຢູ່ບ່ອນນີ້ໄດ້"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ການແຈ້ງເຕືອນແບບພຣັອກຊີ"</string>
@@ -985,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"ບໍລິການອຸປະກອນ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ບໍ່ມີຊື່"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ແຕະເພື່ອຣີສະຕາດແອັບນີ້ ແລະ ໃຊ້ແບບເຕັມຈໍ."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"ການຕັ້ງຄ່າສຳລັບຟອງ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ລົ້ນ"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ເພີ່ມກັບໄປຫາການວາງຊ້ອນກັນ"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"ຈັດການ"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g> ແລະ ອີກ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"ຍ້າຍ"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ຍ້າຍຊ້າຍເທິງ"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ຍ້າຍຂວາເທິງ"</string>
- <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="1314082410868930066">"ປິດຟອງໄວ້"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ຢ່າໃຊ້ຟອງໃນການສົນທະນາ"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"ສົນທະນາໂດຍໃຊ້ຟອງ"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"ການສົນທະນາໃໝ່ຈະປາກົດເປັນໄອຄອນ ຫຼື ຟອງແບບລອຍ. ແຕະເພື່ອເປີດຟອງ. ລາກເພື່ອຍ້າຍມັນ."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ຄວບຄຸມຟອງຕອນໃດກໍໄດ້"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ແຕະຈັດການ ເພື່ອປິດຟອງຈາກແອັບນີ້"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ເຂົ້າໃຈແລ້ວ"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"ການຕັ້ງຄ່າ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
diff --git a/packages/SystemUI/res/values-lo/strings_tv.xml b/packages/SystemUI/res/values-lo/strings_tv.xml
index 056612eb49e9..445e56229bf9 100644
--- a/packages/SystemUI/res/values-lo/strings_tv.xml
+++ b/packages/SystemUI/res/values-lo/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"ໄມໂຄຣໂຟນເປີດໃຊ້ຢູ່"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ເຂົ້າເຖິງໄມໂຄຣໂຟນຂອງທ່ານແລ້ວ"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"ເຊື່ອມຕໍ່ VPN ແລ້ວ"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"ຕັດການເຊື່ອມຕໍ່ VPN ແລ້ວ"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ຜ່ານ <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index ec102b7cec3f..cac9cf1dbc92 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Pabandykite padaryti ekrano kopiją dar kartą"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Negalima išsaugoti ekrano kopijos dėl ribotos saugyklos vietos"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Jūsų organizacijoje arba naudojant šią programą neleidžiama daryti ekrano kopijų"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Redaguoti ekrano kopiją"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Praleisti ekrano kopiją"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Redaguoti"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Redaguoti ekrano kopiją"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Slinkti"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Viso puslapio ekrano kopija"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Praleisti ekrano kopiją"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekrano kopijos peržiūra"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrano vaizdo įrašytuvas"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Apdorojam. ekrano vaizdo įraš."</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dvi akumuliatoriaus juostos."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Trys akumuliatoriaus juostos."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Akumuliatorius įkrautas."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akumuliatoriaus energija procentais nežinoma."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nėra telefono."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Viena telefono juosta."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dvi telefono juostos."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Pranešimo atsisakyta."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Debesėlio atsisakyta."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Pranešimų gaubtas."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Spartieji nustatymai."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Užrakinimo ekranas."</string>
@@ -720,7 +721,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Toliau rodyti iš šios programos gautus pranešimus?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Tylūs"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Numatytasis"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Debesėlis"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatinis"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Neskamba ir nevibruoja"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Neskamba, nevibruoja ir rodoma apatinėje pokalbių skilties dalyje"</string>
@@ -732,8 +732,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nustatymai"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetiniai"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko pokalbių funkcijų"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nėra naujausių burbulų"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Naujausi ir atsisakyti burbulai bus rodomi čia"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šių pranešimų keisti negalima."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Šios grupės pranešimai čia nekonfigūruojami"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Per tarpinį serverį gautas pranešimas"</string>
@@ -996,25 +994,7 @@
<string name="device_services" msgid="1549944177856658705">"Įrenginio paslaugos"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nėra pavadinimo"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Palieskite, kad paleistumėte iš naujo šią programą arba įjungtumėte viso ekrano režimą."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ burbulų nustatymai"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Perpildymas"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Pridėti atgal į krūvą"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Tvarkyti"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“ ir dar <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Perkelti"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Perkelti į viršų kairėje"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Perkelti į viršų dešinėje"</string>
- <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="1314082410868930066">"Atsisakyti burbulo"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nerodyti pokalbio burbule"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Pokalbis naudojant burbulus"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nauji pokalbiai rodomi kaip slankiosios piktogramos arba burbulai. Palieskite, kad atidarytumėte burbulą. Vilkite, kad perkeltumėte."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Bet kada valdyti burbulus"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Palieskite „Tvarkyti“, kad išjungtumėte burbulus šioje programoje"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Supratau"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ nustatymai"</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>
@@ -1106,8 +1086,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Naujo įrenginio susiejimas"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijos numeris"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijos numeris nukopijuotas į iškarpinę."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nuskaitant akumuliatoriaus skaitiklį iškilo problema"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Palieskite, kad sužinotumėte daugiau informacijos"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings_tv.xml b/packages/SystemUI/res/values-lt/strings_tv.xml
index 7739680c82b3..c749cdfbe22c 100644
--- a/packages/SystemUI/res/values-lt/strings_tv.xml
+++ b/packages/SystemUI/res/values-lt/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofonas aktyvus"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"„%1$s“ pasiekė jūsų mikrofoną"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN prijungtas"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN atjungtas"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Per „<xliff:g id="VPN_APP">%1$s</xliff:g>“"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 9c12665f7f3b..da8adb46000b 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Mēģiniet izveidot jaunu ekrānuzņēmumu."</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Nevar saglabāt ekrānuzņēmumu, jo krātuvē nepietiek vietas."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Lietotne vai jūsu organizācija neatļauj veikt ekrānuzņēmumus."</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Rediģēt ekrānuzņēmumu"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Nerādīt ekrānuzņēmumu"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Rediģēt"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Rediģēt ekrānuzņēmumu"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Ritināt"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Ritināt ekrānuzņēmumu"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Nerādīt ekrānuzņēmumu"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekrānuzņēmuma priekšskatījums"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrāna ierakstītājs"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekrāna ieraksta apstrāde"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Akumulators: divas joslas."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Akumulators: trīs joslas."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Akumulators ir pilnīgi uzlādēts."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Akumulatora uzlādes līmenis procentos nav zināms."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nav tālruņa."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Tālrunis: viena josla."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Tālrunis: divas joslas."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Paziņojums netiek rādīts."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Burbulis ir noraidīts."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Paziņojumu panelis"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Ātrie iestatījumi"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Bloķēšanas ekrāns."</string>
@@ -717,7 +718,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Vai turpināt rādīt paziņojumus no šīs lietotnes?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Klusums"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Noklusējums"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Burbulis"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automātiski"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Nav skaņas signāla vai vibrācijas"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nav skaņas signāla vai vibrācijas, kā arī atrodas tālāk sarunu sadaļā"</string>
@@ -729,8 +729,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Iestatījumi"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritārs"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstītas sarunu funkcijas."</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nav nesen aizvērtu burbuļu"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Šeit būs redzami nesen rādītie burbuļi un aizvērtie burbuļi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šos paziņojumus nevar modificēt."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Šeit nevar konfigurēt šo paziņojumu grupu."</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Starpniekservera paziņojums"</string>
@@ -991,25 +989,7 @@
<string name="device_services" msgid="1549944177856658705">"Ierīces pakalpojumi"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nav nosaukuma"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Pieskarieties, lai restartētu šo lietotni un pārietu pilnekrāna režīmā."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> burbuļu iestatījumi"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Pārpilde"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Pievienot atpakaļ kopai"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Pārvaldīt"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> no: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> no lietotnes “<xliff:g id="APP_NAME">%2$s</xliff:g>” un vēl <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Pārvietot"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Pārvietot augšpusē pa kreisi"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pārvietot augšpusē pa labi"</string>
- <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="1314082410868930066">"Nerādīt burbuli"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nerādīt sarunu burbuļos"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Tērzēšana, izmantojot burbuļus"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Jaunas sarunas tiek rādītas kā peldošas ikonas vai burbuļi. Pieskarieties, lai atvērtu burbuli. Velciet, lai to pārvietotu."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Allaž pārvaldīt burbuļus"</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="bubbles_user_education_got_it" msgid="8282812431953161143">"Labi"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Lietotnes <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iestatījumi"</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>
@@ -1100,8 +1080,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Savienošana pārī ar jaunu ierīci"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versijas numurs"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versijas numurs ir kopēts starpliktuvē."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nevar iegūt informāciju par akumulatora uzlādes līmeni."</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Pieskarieties, lai iegūtu plašāku informāciju."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings_tv.xml b/packages/SystemUI/res/values-lv/strings_tv.xml
index 6b841d2c244b..f752439165b4 100644
--- a/packages/SystemUI/res/values-lv/strings_tv.xml
+++ b/packages/SystemUI/res/values-lv/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofons ir aktīvs"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Lietotne %1$s piekļuva jūsu mikrofonam"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"Savienojums ar VPN ir izveidots."</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Savienojums ar VPN ir pārtraukts."</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Izmantojot: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index a67e3b55af1e..c2803b479689 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Повторно обидете се да направите слика од екранот"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Сликата од екранот не може да се зачува поради ограничена меморија"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Апликацијата или вашата организација не дозволува снимање слики од екранот"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Изменете ја сликата од екранот"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Отфрлете ја сликата од екранот"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Измени"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Изменете ја сликата од екранот"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Континуирана слика"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Континуирана слика од екранот"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Отфрлете ја сликата од екранот"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Преглед на слика од екранот"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Снимач на екран"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Се обработува снимка од екран"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Батерија две цртички."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Батерија три цртички."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батеријата е полна."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Процентот на батеријата е непознат."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Нема сигнал."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Телефон една цртичка.."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Телефон две цртички."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Известувањето е отфрлено."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Балончето е отфрлено."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панел за известување"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Брзи поставки."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заклучи екран."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Дали да продолжат да се прикажуваат известувања од апликацијава?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Безгласно"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Стандардно"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Балонче"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматски"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звук или вибрации"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звук или вибрации и се појавува подолу во делот со разговори"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Поставки"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритетно"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддржува функции за разговор"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нема неодамнешни балончиња"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Неодамнешните и отфрлените балончиња ќе се појавуваат тука"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Овие известувања не може да се изменат"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Оваа група известувања не може да се конфигурира тука"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Известување преку прокси"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Услуги за уредот"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслов"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Допрете за да ја рестартирате апликацијава и да ја отворите на цел екран."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Поставки за балончињата за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Прелевање"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Додајте назад во stack"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Управувајте"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g> и уште <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Премести"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Премести горе лево"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Премести горе десно"</string>
- <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="1314082410868930066">"Отфрли балонче"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не прикажувај го разговорот во балончиња"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Разговор во балончиња"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новите разговори ќе се појавуваат како лебдечки икони или балончиња. Допрете за отворање на балончето. Повлечете за да го преместите."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Контролирајте ги балончињата во секое време"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Допрете „Управувајте“ за да ги исклучите балончињата од апликацијава"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Сфатив"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Поставки за <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Спарете нов уред"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број на верзија"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Бројот на верзијата е копиран во привремената меморија."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем при читањето на мерачот на батеријата"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Допрете за повеќе информации"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings_tv.xml b/packages/SystemUI/res/values-mk/strings_tv.xml
index a935cc47b6cf..947281341e30 100644
--- a/packages/SystemUI/res/values-mk/strings_tv.xml
+++ b/packages/SystemUI/res/values-mk/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Микрофонот е активен"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s пристапи до вашиот микрофон"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN е поврзана"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN е исклучена"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Преку <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 3b6c616182f1..4d77fcd4054f 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"സ്‌ക്രീൻഷോട്ട് എടുക്കാൻ വീണ്ടും ശ്രമിക്കുക"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"സ്‌റ്റോറേജ് ഇടം പരിമിതമായതിനാൽ സ്‌ക്രീൻഷോട്ട് സംരക്ഷിക്കാനാകുന്നില്ല"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"സ്ക്രീൻഷോട്ടുകൾ എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"സ്ക്രീൻഷോട്ട് എഡിറ്റ് ചെയ്യുക"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"സ്ക്രീൻഷോട്ട് ഡിസ്‌മിസ് ചെയ്യുക"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"എഡിറ്റ് ചെയ്യുക"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"സ്ക്രീൻഷോട്ട് എഡിറ്റ് ചെയ്യുക"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"സ്‌ക്രോൾ ചെയ്യുക"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"സ്ക്രീൻഷോട്ട് സ്ക്രോൾ ചെയ്യുക"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"സ്ക്രീൻഷോട്ട് ഡിസ്‌മിസ് ചെയ്യുക"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"സ്‌ക്രീൻഷോട്ട് പ്രിവ്യു"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"സ്ക്രീൻ റെക്കോർഡർ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"സ്ക്രീൻ റെക്കോർഡിംഗ് പ്രോസസുചെയ്യുന്നു"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ബാറ്ററി രണ്ട് ബാർ."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ബാറ്ററി മൂന്ന് ബാർ."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ബാറ്ററി നിറഞ്ഞു."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ബാറ്ററി ശതമാനം അജ്ഞാതമാണ്."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"ഫോൺ സിഗ്‌നൽ ഒന്നുമില്ല."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ഫോണിൽ ഒരു ബാർ."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ഫോണിൽ രണ്ട് ബാർ."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"അറിയിപ്പ് നിരസിച്ചു."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ബബ്ൾ ഡിസ്മിസ് ചെയ്തു."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"അറിയിപ്പ് ഷെയ്‌ഡ്."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ദ്രുത ക്രമീകരണങ്ങൾ."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ലോക്ക് സ്‌ക്രീൻ."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"ഈ ആപ്പിൽ നിന്നുള്ള അറിയിപ്പുകൾ തുടർന്നും കാണിക്കണോ?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"നിശബ്‌ദം"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ഡിഫോൾട്ട്"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"ബബ്ൾ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"സ്വയമേവ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ശബ്ദമോ വൈബ്രേഷനോ ഇല്ല"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ശബ്‌ദമോ വൈബ്രേഷനോ ഇല്ല, സംഭാഷണ വിഭാഗത്തിന് താഴെയായി ദൃശ്യമാകും"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ക്രമീകരണം"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> സംഭാഷണ സവിശേഷതകളെ പിന്തുണയ്‌ക്കുന്നില്ല"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"അടുത്തിടെയുള്ള ബബിളുകൾ ഒന്നുമില്ല"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"അടുത്തിടെയുള്ള ബബിളുകൾ, ഡിസ്മിസ് ചെയ്ത ബബിളുകൾ എന്നിവ ഇവിടെ ദൃശ്യമാവും"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"അറിയിപ്പുകളുടെ ഈ ഗ്രൂപ്പ് ഇവിടെ കോണ്‍ഫിഗര്‍ ചെയ്യാൻ കഴിയില്ല"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"പ്രോക്‌സി അറിയിപ്പ്"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"ഉപകരണ സേവനങ്ങള്‍"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"പേരില്ല"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ഈ ആപ്പ് റീസ്‌റ്റാർട്ട് ചെയ്യാനും പൂർണ്ണ സ്‌ക്രീനാവാനും ടാപ്പ് ചെയ്യുക."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ബബിളുകളുടെ ക്രമീകരണം"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ഓവർഫ്ലോ"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"അടുക്കുകളിലേക്ക് തിരിച്ച് ചേർക്കുക"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"മാനേജ് ചെയ്യുക"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>-ൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> കൂടുതലും"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"നീക്കുക"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"മുകളിൽ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
- <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="1314082410868930066">"ബബിൾ ഡിസ്മിസ് ചെയ്യൂ"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"സംഭാഷണം ബബിൾ ചെയ്യരുത്"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"ബബിളുകൾ ഉപയോഗിച്ച് ചാറ്റ് ചെയ്യുക"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"പുതിയ സംഭാഷണങ്ങൾ ഫ്ലോട്ടിംഗ് ഐക്കണുകളോ ബബിളുകളോ ആയി ദൃശ്യമാവുന്നു. ബബിൾ തുറക്കാൻ ടാപ്പ് ചെയ്യൂ. ഇത് നീക്കാൻ വലിച്ചിടുക."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ബബിളുകൾ ഏതുസമയത്തും നിയന്ത്രിക്കുക"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ഈ ആപ്പിൽ നിന്നുള്ള ബബിളുകൾ ഓഫാക്കാൻ മാനേജ് ചെയ്യുക ടാപ്പ് ചെയ്യുക"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"മനസ്സിലായി"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ക്രമീകരണം"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"പുതിയ ഉപകരണവുമായി ജോടിയാക്കുക"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ബിൽഡ് നമ്പർ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ക്ലിപ്പ്ബോർഡിലേക്ക് ബിൽഡ് നമ്പർ പകർത്തി."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"നിങ്ങളുടെ ബാറ്ററി മീറ്റർ വായിക്കുന്നതിൽ പ്രശ്‌നമുണ്ട്"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"കൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings_tv.xml b/packages/SystemUI/res/values-ml/strings_tv.xml
index 97843376a364..fe7979665edd 100644
--- a/packages/SystemUI/res/values-ml/strings_tv.xml
+++ b/packages/SystemUI/res/values-ml/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"മൈക്രോഫോൺ സജീവമാണ്"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s, നിങ്ങളുടെ മൈക്രോഫോൺ ആക്‌സസ് ചെയ്‌തു"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN കണക്റ്റ് ചെയ്‌തു"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN വിച്ഛേദിച്ചു"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> വഴി"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index ef110e9e2fa3..b841fa95a57f 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -86,14 +86,17 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Дэлгэцийн зургийг дахин дарж үзнэ үү"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Сангийн багтаамж бага байгаа тул дэлгэцээс дарсан зургийг хадгалах боломжгүй байна"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Таны апп, байгууллагад дэлгэцийн зураг авахыг зөвшөөрдөггүй"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Дэлгэцийн агшныг засах"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Дэлгэцийн агшныг хаах"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Засах"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Дэлгэцийн агшныг засах"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Гүйлгэх"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Бүхэлд нь багтаасан дэлгэцийн агшин"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Дэлгэцийн агшныг хаах"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Дэлгэцийн агшныг урьдчилан үзэх"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Дэлгэцийн үйлдэл бичигч"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Дэлгэц бичлэг боловсруулж байна"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Дэлгэц бичих горимын үргэлжилж буй мэдэгдэл"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Бичлэгийг эхлүүлэх үү?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"Бичих үед Андройд систем нь таны дэлгэц дээр харагдах эсвэл төхөөрөмж дээрээ тоглуулсан аливаа эмзэг мэдээллийг авах боломжтой. Үүнд нууц үг, төлбөрийн мэдээлэл, зураг, зурвас болон аудио багтана."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"Бичих үед Андройд систем нь таны дэлгэц дээр харагдах эсвэл төхөөрөмж дээрээ тоглуулсан аливаа эмзэг мэдээллийг авах боломжтой. Үүнд нууц үг, төлбөрийн мэдээлэл, зураг, мессеж болон аудио багтана."</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>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Батерей хоёр баганатай."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Батерей гурван баганатай."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батерей дүүрэн."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Батарейн хувь тодорхойгүй байна."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Утас байхгүй."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Утас нэг баганатай."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Утас хоёр баганатай."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Мэдэгдэл хаагдсан."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Бөмбөлгийг үл хэрэгссэн."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Мэдэгдлийн хураангуй самбар"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Шуурхай тохиргоо."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Дэлгэц түгжих."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Энэ аппаас мэдэгдэл харуулсан хэвээр байх уу?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Чимээгүй"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Өгөгдмөл"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Бөмбөлөг"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автомат"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Дуу эсвэл чичиргээ байхгүй"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Дуу эсвэл чичиргээ байхгүй бөгөөд харилцан ярианы хэсгийн доод талд харагдана"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Тохиргоо"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Ач холбогдол"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь харилцан ярианы онцлогуудыг дэмждэггүй"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Саяхны бөмбөлөг алга байна"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Саяхны бөмбөлгүүд болон үл хэрэгссэн бөмбөлгүүд энд харагдана"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эдгээр мэдэгдлийг өөрчлөх боломжгүй."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Энэ бүлэг мэдэгдлийг энд тохируулах боломжгүй байна"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Прокси хийсэн мэдэгдэл"</string>
@@ -934,7 +932,7 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"Сэрэмжлүүлэг"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"Батарей"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Дэлгэцийн зураг дарах"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"Энгийн зурвас"</string>
+ <string name="notification_channel_general" msgid="4384774889645929705">"Энгийн мессеж"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"Хадгалах сан"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Заавар"</string>
<string name="instant_apps" msgid="8337185853050247304">"Шуурхай апп"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Төхөөрөмжийн үйлчилгээ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Гарчиггүй"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Энэ аппыг дахин эхлүүлж, бүтэн дэлгэцэд орохын тулд товшино уу."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н бөмбөлгүүдийн тохиргоо"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Халих"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Өрөлтөд буцааж нэмэх"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Удирдах"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>-н <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g>-н <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> болон бусад <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Зөөх"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Зүүн дээш зөөх"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Баруун дээш зөөх"</string>
- <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="1314082410868930066">"Бөмбөлгийг хаах"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Харилцан яриаг бүү бөмбөлөг болго"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Бөмбөлөг ашиглан чатлаарай"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Шинэ харилцан яриа нь хөвөгч дүрс тэмдэг эсвэл бөмбөлөг хэлбэрээр харагддаг. Бөмбөлгийг нээхийн тулд товшино уу. Түүнийг зөөхийн тулд чирнэ үү."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Дурын үед бөмбөлгийг хянаарай"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Энэ аппын бөмбөлгүүдийг унтраахын тулд Удирдах дээр товшино уу"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Ойлголоо"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-н тохиргоо"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Шинэ төхөөрөмж хослуулах"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Хийгдсэн дугаар"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Хийгдсэн дугаарыг түр санах ойд хуулсан."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Таны батарей хэмжигчийг уншихад асуудал гарлаа"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нэмэлт мэдээлэл авахын тулд товшино уу"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings_tv.xml b/packages/SystemUI/res/values-mn/strings_tv.xml
index 3a5ff747a01e..9ec66d1bf26f 100644
--- a/packages/SystemUI/res/values-mn/strings_tv.xml
+++ b/packages/SystemUI/res/values-mn/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Микрофон идэвхтэй байна"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s нь таны микрофонд хандcан байна"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN холбогдсон"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN салсан"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g>-р"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 9b3ee7115268..a487a6377ed5 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"स्क्रीनशॉट पुन्हा घेण्याचा प्रयत्न करा"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"मर्यादित स्टोरेज जागेमुळे स्क्रीनशॉट सेव्ह करू शकत नाही"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"अ‍ॅप किंवा आपल्या संस्थेद्वारे स्क्रीनशॉट घेण्याची अनुमती नाही"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"स्क्रीनशॉट संपादित करा"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"स्क्रीनशॉट डिसमिस करा"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"संपादित करा"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"स्क्रीनशॉट संपादित करा"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"स्क्रोल करा"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रीनशॉटवर स्क्रोल करा"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रीनशॉट डिसमिस करा"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रीनशॉटचे पूर्वावलोकन"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रीन रेकॉर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रेकॉर्डिंग प्रोसेस सुरू"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"बॅटरी दोन बार."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"बॅटरी तीन बार."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"बॅटरी पूर्ण भरली."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"बॅटरीच्या चार्जिंगची टक्केवारी माहित नाही."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"कोणताही फोन नाही."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"फोन एक बार."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"फोन दोन बार."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"सूचना डिसमिस केल्या."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"बबल डिसमिस केला."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना शेड."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"द्रुत सेटिंग्ज."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"लॉक स्क्रीन."</string>
@@ -522,8 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"प्रोफाईलचे परीक्षण केले जाऊ शकते"</string>
<string name="vpn_footer" msgid="3457155078010607471">"नेटवर्कचे परीक्षण केले जाऊ शकते"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"नेटवर्कचे परीक्षण केले जाऊ शकते"</string>
- <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
- <skip />
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"हे डिव्हाइस तुमच्या पालकाने व्यवस्थापित केले आहे"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"तुमच्‍या संस्‍थेकडे या डिव्हाइसची मालकी आहे आणि ती नेटवर्क ट्रॅफिकचे परीक्षण करू शकते"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> च्या मालकीचे आहे आणि ती नेटवर्क ट्रॅफिकचे परीक्षण करू शकते"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"हे डिव्हाइस तुमच्या संस्थेचे आहे आणि ते <xliff:g id="VPN_APP">%1$s</xliff:g> ला कनेक्ट केले आहे"</string>
@@ -548,8 +548,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN अक्षम करा"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN डिस्कनेक्ट करा"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"धोरणे पहा"</string>
- <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
- <skip />
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"नियंत्रणे पाहा"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"हे डिव्हाइस <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> चे आहे.\n\nतुमचा आयटी ॲडमिन सेटिंग्ज, कॉर्पोरेट अ‍ॅक्सेस, ॲप्‍स, तुमच्‍या डिव्‍हाइसशी संबंधित डेटा आणि तुमच्‍या डिव्‍हाइसच्‍या स्‍थानाची माहिती यांचे परीक्षण व व्‍यवस्‍थापन करू शकतो.\n\nअधिक माहितीसाठी तुमच्‍या आयटी ॲडमिनशी संपर्क साधा."</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"हे डिव्हाइस तुमच्या संस्थेचे आहे.\n\nतुमचा आयटी ॲडमिन सेटिंग्ज, कॉर्पोरेट अ‍ॅक्सेस, ॲप्‍स, तुमच्‍या डिव्‍हाइसशी संबंधित डेटा आणि तुमच्‍या डिव्‍हाइसच्‍या स्‍थानाची माहिती यांचे परीक्षण व व्‍यवस्‍थापन करू शकतो.\n\nअधिक माहितीसाठी तुमच्‍या आयटी ॲडमिनशी संपर्क साधा."</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"आपल्या संस्थेने या डिव्हाइसवर प्रमाणपत्र अधिकार इंस्टॉल केला आहे. आपल्या सुरक्षित नेटवर्क रहदारीचे परीक्षण केले जाऊ शकते किंवा ती सुधारली जाऊ शकते."</string>
@@ -573,8 +572,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"आपल्या प्रशासकाने नेटवर्क लॉगिंग सुरू केले आहे, जे आपल्या डिव्हाइसवरील रहदारीचे निरीक्षण करते.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"तुम्ही VPN कनेक्शन सेट करण्यासाठी अ‍ॅपला परवानगी दिली.\n\nहा अ‍ॅप ईमेल, अ‍ॅप्स आणि वेबसाइटसह, तुमच्या डिव्हाइस आणि नेटवर्क ॲक्टिव्हिटीचे परीक्षण करू शकतो."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"तुमचे कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते.\n\nतुमचा प्रशासक ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्या नेटवर्क ॲक्टिव्हिटीचे निरीक्षण करण्यास सक्षम आहे.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा.\n\nतुम्ही VPN शी देखील कनेक्ट आहात, जे आपल्या नेटवर्क ॲक्टिव्हिटीचे निरीक्षण करू शकते."</string>
- <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
- <skip />
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"हे डिव्हाइस तुमच्या पालकाने व्यवस्थापित केले आहे. तुम्ही वापरत असलेली ॲप्स, तुमचे स्थान आणि तुमचा स्क्रीन वेळ यांसारखी माहिती तुमचे पालक पाहू आणि व्यवस्‍थापित करू शकतात."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"तुम्ही <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"तुम्ही <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
@@ -717,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"या अ‍ॅपकडील सूचना दाखवणे सुरू ठेवायचे?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"सायलंट"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"डीफॉल्ट"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"बबल"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ऑटोमॅटिक"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"आवाज किंवा व्हायब्रेशन नाही"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"आवाज किंवा व्हायब्रेशन नाही आणि संभाषण विभागात सर्वात तळाशी दिसते"</string>
@@ -729,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिंग्ज"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राधान्य"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे संभाषण वैशिष्ट्यांना सपोर्ट करत नाही"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"अलीकडील कोणतेही बबल नाहीत"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"अलीकडील बबल आणि डिसमिस केलेले बबल येथे दिसतील"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"या सूचनांमध्ये सुधारणा केली जाऊ शकत नाही."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"या सूचनांचा संच येथे कॉंफिगर केला जाऊ शकत नाही"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"प्रॉक्सी केलेल्या सूचना"</string>
@@ -989,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"डिव्हाइस सेवा"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक नाही"</string>
<string name="restart_button_description" msgid="6916116576177456480">"हे अ‍ॅप रीस्टार्ट करण्यासाठी आणि फुल स्क्रीन करण्यासाठी टॅप करा."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> बबलसाठी सेटिंग्ज"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ओव्हरफ्लो"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"स्टॅकमध्ये परत जोडा"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"व्यवस्थापित करा"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> कडून <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> आणि आणखी <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> कडून <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"हलवा"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"वर डावीकडे हलवा"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"वर उजवीकडे हलवा"</string>
- <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="1314082410868930066">"बबल डिसमिस करा"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"संभाषणाला बबल करू नका"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"बबल वापरून चॅट करा"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"नवीन संभाषणे फ्लोटिंग आयकन किंवा बबल म्हणून दिसतात. बबल उघडण्यासाठी टॅप करा. हे हलवण्यासाठी ड्रॅग करा."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"बबल कधीही नियंत्रित करा"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"या अ‍ॅपमधून बबल बंद करण्यासाठी व्यवस्थापित करा वर टॅप करा"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"समजले"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> सेटिंग्ज"</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>
@@ -1097,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नवीन डिव्हाइससोबत पेअर करा"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नंबर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नंबर क्लिपबोर्डवर कॉपी केला."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"तुमचे बॅटरी मीटर वाचताना समस्या आली"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"अधिक माहितीसाठी टॅप करा"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings_tv.xml b/packages/SystemUI/res/values-mr/strings_tv.xml
index 7f58fe779e03..791a4fd0c802 100644
--- a/packages/SystemUI/res/values-mr/strings_tv.xml
+++ b/packages/SystemUI/res/values-mr/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"मायक्रोफोन ॲक्टिव्ह आहे"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s यांनी तुमचा मायक्रोफोन अ‍ॅक्सेस केला आहे"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN कनेक्‍ट केले"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN डिस्कनेक्ट केले"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> द्वारे"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 55f1e3252e5e..8f426ede9b75 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Cuba ambil tangkapan skrin sekali lagi"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Tidak dapat menyimpan tangkapan skrin kerana ruang storan terhad"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Pengambilan tangkapan skrin tidak dibenarkan oleh apl atau organisasi anda"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Edit tangkapan skrin"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ketepikan tangkapan skrin"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Edit"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Edit tangkapan skrin"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Tatal"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Penatalan tangkapan skrin"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ketepikan tangkapan skrin"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pratonton tangkapan skrin"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Perakam Skrin"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses rakaman skrin"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Bateri dua bar."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Bateri tiga bar."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateri penuh."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Peratusan kuasa bateri tidak diketahui."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Tiada telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon satu bar."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon dua bar."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Pemberitahuan diketepikan."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Gelembung diketepikan."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bidai pemberitahuan."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tetapan pantas."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kunci skrin."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Terus tunjukkan pemberitahuan daripada apl ini?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Senyap"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Lalai"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Gelembung"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Tiada bunyi atau getaran"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Tiada bunyi atau getaran dan muncul di sebelah bawah dalam bahagian perbualan"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Tetapan"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Keutamaan"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong ciri perbualan"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Tiada gelembung terbaharu"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Gelembung baharu dan gelembung yang diketepikan akan dipaparkan di sini"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Pemberitahuan ini tidak boleh diubah suai."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Kumpulan pemberitahuan ini tidak boleh dikonfigurasikan di sini"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Pemberitahuan berproksi"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Perkhidmatan Peranti"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Tiada tajuk"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Ketik untuk memulakan semula apl ini dan menggunakan skrin penuh."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Tetapan untuk gelembung <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Limpahan"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Tambah kembali pada tindanan"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Urus"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> daripada <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> daripada <xliff:g id="APP_NAME">%2$s</xliff:g> dan <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> lagi"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Alih"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Alihkan ke atas sebelah kiri"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Alihkan ke atas sebelah kanan"</string>
- <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="1314082410868930066">"Ketepikan gelembung"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Jangan jadikan perbualan dalam bentuk gelembung"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bersembang menggunakan gelembung"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Perbualan baharu muncul sebagai ikon terapung atau gelembung. Ketik untuk membuka gelembung. Seret untuk mengalihkan gelembung tersebut."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kawal gelembung pada bila-bila masa"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Ketik Urus untuk mematikan gelembung daripada apl ini"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Tetapan <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Gandingkan peranti baharu"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nombor binaan"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nombor binaan disalin ke papan keratan."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Masalah membaca meter bateri anda"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Ketik untuk mendapatkan maklumat lanjut"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings_tv.xml b/packages/SystemUI/res/values-ms/strings_tv.xml
index 3c62891c5530..65c8068d0505 100644
--- a/packages/SystemUI/res/values-ms/strings_tv.xml
+++ b/packages/SystemUI/res/values-ms/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon Aktif"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s telah mengakses mikrofon anda"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN telah disambungkan"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN diputuskan sambungan"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Melalui <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 18e804b5a2ff..9d8ffc93fae0 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"မျက်နှာပြင်ပုံကို ထပ်ရိုက်ကြည့်ပါ"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"သိုလှောင်ခန်းနေရာ အကန့်အသတ်ရှိသောကြောင့် ဖန်သားပြင်ဓာတ်ပုံကို သိမ်းဆည်း၍မရပါ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ဖန်သားပြင်ဓာတ်ပုံရိုက်ကူးခြင်းကို ဤအက်ပ် သို့မဟုတ် သင်၏အဖွဲ့အစည်းက ခွင့်မပြုပါ"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"ဖန်သားပြင်ဓာတ်ပုံကို တည်းဖြတ်သည်"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ဖန်သားပြင်ဓာတ်ပုံ ပယ်ရန်"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"တည်းဖြတ်ရန်"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"ဖန်သားပြင်ဓာတ်ပုံကို တည်းဖြတ်သည်"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"လှိမ့်ရန်"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"ဖန်သားပြင်ဓာတ်ပုံကို လှိမ့်ရန်"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ဖန်သားပြင်ဓာတ်ပုံကို ပယ်သည်"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ဖန်သားပြင်ဓာတ်ပုံ အစမ်းကြည့်ရှုခြင်း"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ဖန်သားပြင် ရိုက်ကူးမှု"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ဖန်သားပြင်ရိုက်ကူးနေသည်"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ဘတ္တရီနှစ်ဘား။"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ဘတ္တရီသုံးဘား။"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ဘတ္တရီအပြည့်။"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ဘက်ထရီရာခိုင်နှုန်းကို မသိပါ။"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"ဖုန်းလိုင်းမရှိပါ။"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ဖုန်းလိုင်းတစ်ဘား။"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ဖုန်းလိုင်းနှစ်ဘား။"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"အကြောင်းကြားချက်ကိုဖယ်ရှားပြီး"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ပူဖောင်းကွက် ဖယ်လိုက်သည်။"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"အ​ကြောင်းကြားစာအကွက်"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"အမြန်လုပ် အပြင်အဆင်"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"မျက်နှာပြင် သော့ပိတ်ရန်"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"ဤအက်ပ်ထံမှ အကြောင်းကြားချက်များကို ဆက်ပြလိုပါသလား။"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"အသံတိတ်ရန်"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"မူလ"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"ပူဖောင်းဖောက်သံ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"အလိုအလျောက်"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ၊ စကားဝိုင်းကဏ္ဍ၏ အောက်ပိုင်းတွင် မြင်ရသည်"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ဆက်တင်များ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ဦးစားပေး"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စကားဝိုင်းဝန်ဆောင်မှုများကို မပံ့ပိုးပါ"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"လတ်တလော ပူဖောင်းကွက်များ မရှိပါ"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"လတ်တလော ပူဖောင်းကွက်များနှင့် ပိတ်လိုက်သော ပူဖောင်းကွက်များကို ဤနေရာတွင် မြင်ရပါမည်"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ဤအကြောင်းကြားချက်များကို ပြုပြင်၍ မရပါ။"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"ဤအကြောင်းကြားချက်အုပ်စုကို ဤနေရာတွင် စီစဉ်သတ်မှတ်၍ မရပါ"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ပရောက်စီထည့်ထားသော အကြောင်းကြားချက်"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"စက်ပစ္စည်းဝန်ဆောင်မှုများ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ခေါင်းစဉ် မရှိပါ"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ဤအက်ပ်ကို ပြန်စတင်ပြီး မျက်နှာပြင်အပြည့်လုပ်ရန် တို့ပါ။"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ပူဖောင်းကွက်အတွက် ဆက်တင်များ"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"အပိုများပြရန်"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ပူဖေါင်းတန်းသို့ ပြန်ထည့်ရန်"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"စီမံရန်"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> မှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> နှင့် နောက်ထပ် <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ခုမှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"ရွှေ့ရန်"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ဘယ်ဘက်ထိပ်သို့ ရွှေ့ရန်"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ညာဘက်ထိပ်သို့ ရွှေ့ပါ"</string>
- <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="1314082410868930066">"ပူဖောင်းကွက် ပယ်ရန်"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"စကားဝိုင်းကို ပူဖောင်းကွက် မပြုလုပ်ပါနှင့်"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"ပူဖောင်းကွက် သုံး၍ ချတ်လုပ်ခြင်း"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"စကားဝိုင်းအသစ်များကို မျောနေသည့် သင်္ကေတများ သို့မဟုတ် ပူဖောင်းကွက်များအဖြစ် မြင်ရပါမည်။ ပူဖောင်းကွက်ကိုဖွင့်ရန် တို့ပါ။ ရွှေ့ရန် ၎င်းကို ဖိဆွဲပါ။"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ပူဖောင်းကွက်ကို အချိန်မရွေး ထိန်းချုပ်ရန်"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ဤအက်ပ်မှနေ၍ ပူဖောင်းများကို ပိတ်ရန်အတွက် \'စီမံရန်\' ကို တို့ပါ"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ရပါပြီ"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ဆက်တင်များ"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"စက်အသစ် တွဲချိတ်ရန်"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"တည်ဆောက်မှုနံပါတ်"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"တည်ဆောက်မှုနံပါတ်ကို ကလစ်ဘုတ်သို့ မိတ္တူကူးပြီးပါပြီ။"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"သင်၏ ဘက်ထရီမီတာကို ဖတ်ရာတွင် ပြဿနာရှိနေသည်"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"နောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings_tv.xml b/packages/SystemUI/res/values-my/strings_tv.xml
index 88d7d53d8390..c07b9a596b06 100644
--- a/packages/SystemUI/res/values-my/strings_tv.xml
+++ b/packages/SystemUI/res/values-my/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"မိုက်ခရိုဖုန်း ဖွင့်ထားသည်"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s က သင့်မိုက်ခရိုဖုန်းကို သုံးထားသည်"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ချိတ်ဆက်ထားသည်"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ချိတ်ဆက်မှုမရှိပါ"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> မှတစ်ဆင့်"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 8becc3b81fc4..1d30e2bf89bd 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Prøv å ta skjermdump på nytt"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Kan ikke lagre skjermdumpen på grunn av begrenset lagringsplass"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Appen eller organisasjonen din tillater ikke at du tar skjermdumper"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Rediger skjermdumpen"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Avvis skjermdumpen"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Rediger"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Rediger skjermdumpen"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Rull"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Rull skjermdumpen"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Avvis skjermdumpen"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Forhåndsvisning av skjermdump"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skjermopptaker"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandler skjermopptaket"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batteri – to stolper."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batteri – tre stolper."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batteriet er fullt."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batteriprosenten er ukjent."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ingen telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon – én stolpe."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon – to stolper."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Varselet ble skjult."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Boblen er avvist."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Varselskygge."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hurtiginnstillinger."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låseskjerm."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Vil du fortsette å vise varsler fra denne appen?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Lydløs"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standard"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Boble"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisk"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ingen lyd eller vibrering"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ingen lyd eller vibrering, og vises lavere i samtaledelen"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Innstillinger"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke samtalefunksjoner"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ingen nylige bobler"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nylige bobler og avviste bobler vises her"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse varslene kan ikke endres."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Denne varselgruppen kan ikke konfigureres her"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Omdirigert varsel"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Enhetstjenester"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen tittel"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Trykk for å starte denne appen på nytt og vise den i fullskjerm."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Innstillinger for <xliff:g id="APP_NAME">%1$s</xliff:g>-bobler"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflyt"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Legg tilbake i stabelen"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Administrer"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> flere"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Flytt"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Flytt til øverst til venstre"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flytt til øverst til høyre"</string>
- <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="1314082410868930066">"Lukk boblen"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ikke vis samtaler i bobler"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat med bobler"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som flytende ikoner eller bobler. Trykk for å åpne bobler. Dra for å flytte dem."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrollér bobler når som helst"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Trykk på Administrer for å slå av bobler for denne appen"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Greit"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-innstillinger"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Koble til en ny enhet"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delversjonsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delversjonsnummeret er kopiert til utklippstavlen."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kunne ikke lese batterimåleren"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Trykk for å få mer informasjon"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings_tv.xml b/packages/SystemUI/res/values-nb/strings_tv.xml
index cd558735315f..6346519c3823 100644
--- a/packages/SystemUI/res/values-nb/strings_tv.xml
+++ b/packages/SystemUI/res/values-nb/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofonen er aktiv"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s fikk tilgang til mikrofonen din"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN er tilkoblet"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN er frakoblet"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index eac89c2a31aa..eca79cbd0a28 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"स्क्रिनसट फेरि लिएर हेर्नुहोस्"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"भण्डारण ठाउँ सीमित भएका कारण स्क्रिनसट सुरक्षित गर्न सकिएन"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"उक्त एप वा तपाईंको संगठनले स्क्रिनसटहरू लिन दिँदैन"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"स्क्रिनसट सम्पादन गर्नुहोस्"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"स्क्रिनसट हटाउनुहोस्"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"सम्पादन गर्नुहोस्"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"स्क्रिनसट सम्पादन गर्नुहोस्"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"स्क्रोल गर्नुहोस्"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"स्क्रिनसट स्क्रोल गर्नुहोस्"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"स्क्रिनसट हटाउनुहोस्"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"स्क्रिनसटको पूर्वावलोकन"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"स्क्रिन रेकर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रिन रेकर्डिङको प्रक्रिया अघि बढाइँदै"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ब्याट्रिका दुईवटा पट्टिहरू"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ब्याट्रिका तिनवटा पट्टिहरू"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ब्याट्री पूर्ण छ।"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ब्याट्रीमा कति प्रतिशत चार्ज छ भन्ने कुराको जानाकरी छैन।"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"फोन छैन्।"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"फोन एउटा पट्टि।"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"फोन दुई पट्टि।"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"सूचना खारेज।"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"बबल हटाइयो।"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"सूचना कक्ष।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"द्रुत सेटिङहरू"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"स्क्रीन बन्द गर्नुहोस्।"</string>
@@ -522,8 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"प्रोफाइल अनुगमन हुन सक्छ"</string>
<string name="vpn_footer" msgid="3457155078010607471">"सञ्जाल अनुगमित हुन सक्छ"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"नेटवर्कको अनुगमन गरिने सम्भावना छ"</string>
- <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
- <skip />
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"यो यन्त्र तपाईंका अभिभावक व्यवस्थापन गर्नुहुन्छ"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"यो यन्त्र तपाईंको सङ्गठनको स्वामित्वमा छ र उक्त सङ्गठनले यसको नेटवर्क ट्राफिक अनुगमन गर्न सक्छ"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"यो यन्त्र <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> को स्वामित्वमा छ र उक्त सङ्गठनले यसको नेटवर्क ट्राफिक अनुगमन गर्न सक्छ"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"यो यन्त्र तपाईंको सङ्गठनको स्वामित्वमा छ र <xliff:g id="VPN_APP">%1$s</xliff:g> मा कनेक्ट गरिएको छ"</string>
@@ -548,8 +548,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN असक्षम गर्नुहोस्"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"विच्छेद VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"नीतिहरू हेर्नुहोस्"</string>
- <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
- <skip />
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"नियन्त्रणहरू हेर्नुहोस्"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"यो यन्त्र <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> को स्वामित्वमा छ।\n\nतपाईंका IT एड्मिन सेटिङ, संस्थागत पहुँच, एप, तपाईंको यन्त्रसँग सम्बन्धित डेटा र तपाईंको यन्त्रको स्थानसम्बन्धी जानकारीको निगरानी र व्यवस्थापन गर्न सक्नुहुन्छ।\n\nथप जानकारीका लागि आफ्ना IT एड्मिनसँग सम्पर्क गर्नुहोस्।"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"यो यन्त्र तपाईंको सङ्गठनको स्वामित्वमा छ।\n\nतपाईंका IT एड्मिन सेटिङ, संस्थागत पहुँच, एप, तपाईंको यन्त्रसँग सम्बन्धित डेटा र तपाईंको यन्त्रको स्थानसम्बन्धी जानकारीको निगरानी र व्यवस्थापन गर्न सक्नुहुन्छ।\n\nथप जानकारीका लागि आफ्ना IT एड्मिनसँग सम्पर्क गर्नुहोस्।"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"तपाईंको संगठनले तपाईंको कार्य प्रोफाइलमा एउटा प्रमाणपत्र सम्बन्धी अख्तियार सुविधा स्थापित गऱ्यो। तपाईंको सुरक्षित नेटवर्क ट्राफिकको अनुगमन वा परिमार्जन हुनसक्छ।"</string>
@@ -573,8 +572,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"तपाईँको प्रशासकले तपाईँको यन्त्रमा ट्राफिकको अनुगमन गर्ने नेटवर्कको लगिङलाई सक्रिय पार्नुभएको छ।\n\nथप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"तपाईँले VPN जडान गर्न एपलाई अनुमति दिनुभयो।\n\nयो एपले तपाईँका यन्त्र र नेटवर्क गतिविधि लगायत इमेल, एप र वेबसाइटहरू अनुगमन गर्न सक्छ।"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"तपाईंको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> ले व्यवस्थापन गर्दछ।\n\nतपाईंको प्रशासकले तपाईंको इमेल, एप र वेबसाइट सहित नेटवर्कमा तपाईंको गतिविधिको अनुगमन गर्न सक्नुहुन्छ। \n\nथप जानकारीका लागि आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।\n\n तपाईं एउटा VPN मा जडित हुनुहुन्छ। यस VPN ले नेटवर्कमा तपाईंको गतिविधिको अनुगमन गर्न सक्छ।"</string>
- <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
- <skip />
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"यो यन्त्र तपाईंका अभिभावक व्यवस्थापन गर्नुहुन्छ। तपाईंका अभिभावक तपाईंले प्रयोग गर्ने एप, तपाईंको स्थान र तपाईंले यन्त्र चलाएर बिताउने समय जस्ता जानकारी हेर्न तथा व्यवस्थापन गर्न सक्नुहुन्छ।"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"तपाईं आफ्ना इमेल, एप र वेवसाइटहरू लगायत तपाईंको नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="APPLICATION">%1$s</xliff:g> मा जडान हुनुहुन्छ।"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"तपाईं <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, एपहरू र वेबसाइट लगायतका तपाईंको निजी नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।"</string>
@@ -717,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"यो अनुप्रयोगका सूचनाहरू देखाउने क्रम जारी राख्ने हो?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"मौन"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"पूर्वनिर्धारित"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"बबल"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"स्वचालित"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"न घन्टी बज्छ न त कम्पन नै हुन्छ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"न घन्टी बज्छ न त कम्पन नै हुन्छ र वार्तालाप खण्डको तलतिर देखा पर्छ"</string>
@@ -729,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिङ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापसम्बन्धी सुविधा प्रयोग गर्न मिल्दैन"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"हालैका बबलहरू छैनन्"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"हालैका बबल र खारेज गरिएका बबलहरू यहाँ देखिने छन्"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"यी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"यहाँबाट सूचनाहरूको यो समूह कन्फिगर गर्न सकिँदैन"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"प्रोक्सीमार्फत आउने सूचना"</string>
@@ -989,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"यन्त्रका सेवाहरू"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक छैन"</string>
<string name="restart_button_description" msgid="6916116576177456480">"यो एप पुनः सुरु गर्न ट्याप गर्नुहोस् र फुल स्क्रिन मोडमा जानुहोस्।"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> का बबलसम्बन्धी सेटिङहरू"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ओभरफ्लो देखाउनुहोस्"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"स्ट्याकमा फेरि थप्नुहोस्"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"व्यवस्थापन गर्नुहोस्"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> को <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> का <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> र थप <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"सार्नुहोस्"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"शीर्ष भागको बायाँतिर सार्नुहोस्"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"सिरानमा दायाँतिर सार्नुहोस्"</string>
- <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="1314082410868930066">"बबल खारेज गर्नुहोस्"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"वार्तालाप बबलको रूपमा नदेखाइयोस्"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"बबलहरू प्रयोग गरी कुराकानी गर्नुहोस्"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"नयाँ वार्तालापहरू तैरने आइकन वा बबलका रूपमा देखिन्छन्। बबल खोल्न ट्याप गर्नुहोस्। बबल सार्न सो बबललाई ड्र्याग गर्नुहोस्।"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"जुनसुकै बेला बबलहरू नियन्त्रण गर्नुहोस्"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"यो एपबाट आएका बबलहरू अफ गर्न \"व्यवस्थापन गर्नुहोस्\" बटनमा ट्याप गर्नुहोस्"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"बुझेँ"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> का सेटिङहरू"</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>
@@ -1097,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"नयाँ यन्त्रको जोडा बनाउनुहोस्"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"बिल्ड नम्बर"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"बिल्ड नम्बर कपी गरी क्लिपबोर्डमा सारियो।"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"यन्त्रको ब्याट्रीको मिटर रिडिङ क्रममा समस्या भयो"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"थप जानकारी प्राप्त गर्न ट्याप गर्नुहोस्"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings_tv.xml b/packages/SystemUI/res/values-ne/strings_tv.xml
index 22f7f71793fa..00cc10aadf8a 100644
--- a/packages/SystemUI/res/values-ne/strings_tv.xml
+++ b/packages/SystemUI/res/values-ne/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"माइक्रोफोन सक्रिय छ"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ले तपाईंको माइक्रोफोनमाथि पहुँच राख्यो"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN कनेक्ट गरिएको छ"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN डिस्कनेक्ट गरिएको छ"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> मार्फत"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index d1134d39fe81..6bed66bb171e 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Probeer opnieuw een screenshot te maken"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Kan screenshot niet opslaan vanwege beperkte opslagruimte"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Het maken van screenshots wordt niet toegestaan door de app of je organisatie"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Screenshot bewerken"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Screenshot sluiten"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Bewerken"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Screenshot bewerken"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scrollen"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Screenshot scrollen"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Screenshot sluiten"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Voorbeeld van screenshot"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Schermopname"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Schermopname verwerken"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batterij: twee streepjes."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batterij: drie streepjes."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batterij is vol."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batterijpercentage onbekend."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Geen telefoonsignaal."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefoon: één streepje."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefoon: twee streepjes."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Melding verwijderd."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubbel gesloten."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Meldingenpaneel."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Snelle instellingen."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Vergrendelscherm."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Meldingen van deze app blijven weergeven?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Stil"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standaard"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bubbel"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisch"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Geen geluid of trilling"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Geen geluid of trilling en wordt lager in het gedeelte met gesprekken weergegeven"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Instellingen"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ondersteunt geen gespreksfuncties"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Geen recente bubbels"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recente bubbels en gesloten bubbels worden hier weergegeven"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Deze meldingen kunnen niet worden aangepast."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Deze groep meldingen kan hier niet worden geconfigureerd"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Melding via proxy"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Apparaatservices"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Geen titel"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tik om deze app opnieuw te starten en te openen op het volledige scherm."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Instellingen voor <xliff:g id="APP_NAME">%1$s</xliff:g>-bubbels"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overloop"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Weer toevoegen aan stack"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Beheren"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g> en nog <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Verplaatsen"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Naar linksboven verplaatsen"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Naar rechtsboven verplaatsen"</string>
- <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="1314082410868930066">"Bubbel sluiten"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Gesprekken niet in bubbels weergeven"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatten met bubbels"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nieuwe gesprekken worden weergegeven als zwevende iconen of \'bubbels\'. Tik om een bubbel te openen. Sleep om de bubbel te verplaatsen."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Beheer bubbels wanneer je wilt"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tik op Beheren om bubbels van deze app uit te schakelen"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Instellingen voor <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Nieuw apparaat koppelen"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Build-nummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Build-nummer naar klembord gekopieerd."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Probleem bij het lezen van je batterijmeter"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tik hier voor meer informatie"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings_tv.xml b/packages/SystemUI/res/values-nl/strings_tv.xml
index 3b8e3201e440..11f70b4dfe94 100644
--- a/packages/SystemUI/res/values-nl/strings_tv.xml
+++ b/packages/SystemUI/res/values-nl/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Microfoon actief"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s heeft toegang tot je microfoon gehad"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"Verbinding met VPN"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Geen verbinding met VPN"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 264076f6b669..a809da3d2fe2 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ପୁଣିଥରେ ସ୍କ୍ରୀନ୍‌ଶଟ୍ ନେବାକୁ ଚେଷ୍ଟା କରନ୍ତୁ"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"ସୀମିତ ଷ୍ଟୋରେଜ୍‍ ସ୍ପେସ୍‍ ହେତୁ ସ୍କ୍ରୀନଶଟ୍‍ ସେଭ୍‍ ହୋଇପାରିବ ନାହିଁ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ଆପ୍‍ କିମ୍ବା ସଂସ୍ଥା ଦ୍ୱାରା ସ୍କ୍ରୀନଶଟ୍‍ ନେବାକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"ସ୍କ୍ରିନସଟକୁ ଏଡିଟ୍ କରନ୍ତୁ"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ସ୍କ୍ରିନସଟ୍ ଖାରଜ କରନ୍ତୁ"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"ଏଡିଟ୍ କରନ୍ତୁ"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"ସ୍କ୍ରିନସଟ୍ ଏଡିଟ୍ କରନ୍ତୁ"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"ସ୍କ୍ରୋଲ୍ କରନ୍ତୁ"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"ସ୍କ୍ରିନସଟ୍ ସ୍କ୍ରୋଲ୍ କରନ୍ତୁ"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ସ୍କ୍ରିନସଟ୍ ଖାରଜ କରନ୍ତୁ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ସ୍କ୍ରିନସଟର ପ୍ରିଭ୍ୟୁ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ସ୍କ୍ରିନ୍ ରେକର୍ଡର୍"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ସ୍କ୍ରିନ ରେକର୍ଡିଂର ପ୍ରକ୍ରିୟାକରଣ"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ବ୍ୟାଟେରୀର ଦୁଇଟି ବାର୍‍ ଅଛି।"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ବ୍ୟାଟେରୀର ତିନୋଟି ବାର୍‍ ଅଛି।"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ବ୍ୟାଟେରୀ ପୂର୍ଣ୍ଣ‍।"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ବ୍ୟାଟେରୀ ଶତକଡ଼ା ଅଜଣା ଅଟେ।"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"କୌଣସି ଫୋନ୍ ନାହିଁ।"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ଫୋନର ଗୋଟିଏ ବାର ଅଛି।"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ଫୋନର ଦୁଇଟି ବାର୍‌ ଅଛି।"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ବିଜ୍ଞପ୍ତି ଖାରଜ କରାଗଲା।"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ବବଲ୍ ଖାରଜ କରାଯାଇଛି।"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ବିଜ୍ଞପ୍ତି ଶେଡ୍‍।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ଦ୍ରୁତ ସେଟିଂସ୍।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ଲକ୍‌ ସ୍କ୍ରୀନ୍‌।"</string>
@@ -522,8 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ପ୍ରୋଫାଇଲ୍ ନିରୀକ୍ଷଣ କରାଯାଇପାରେ।"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ନେଟ୍‌ୱର୍କ ନୀରିକ୍ଷଣ କରାଯାଇପାରେ"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ନେଟ୍‌ୱର୍କକୁ ନିରୀକ୍ଷଣ କରାଯାଇପାରେ"</string>
- <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
- <skip />
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ଏହି ଡିଭାଇସ୍ ଆପଣଙ୍କ ବାପାମାଙ୍କ ଦ୍ୱାରା ପରିଚାଳିତ"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ଏହି ଡିଭାଇସର ମାଲିକାନା ଆପଣଙ୍କ ସଂସ୍ଥା ପାଖରେ ଅଛି ଏବଂ ଏହା ନେଟୱାର୍କ ଟ୍ରାଫିକର ନିରୀକ୍ଷଣ କରିପାରେ"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"ଏହି ଡିଭାଇସଟି <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ର ଅଟେ ଏବଂ ଏହା ନେଟୱାର୍କ ଟ୍ରାଫିକକୁ ନିରୀକ୍ଷଣ କରିପାରେ"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ଏହି ଡିଭାଇସଟି ଆପଣଙ୍କ ସଂସ୍ଥାର ଅଟେ ଏବଂ ଏହା <xliff:g id="VPN_APP">%1$s</xliff:g> ସହ ସଂଯୁକ୍ତ ଅଛି"</string>
@@ -548,8 +548,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN ଅକ୍ଷମ କରନ୍ତୁ"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN ବିଛିନ୍ନ କରନ୍ତୁ"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"ପଲିସୀ ଦେଖନ୍ତୁ"</string>
- <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
- <skip />
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"ଏହି ଡିଭାଇସଟି <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>ର ଅଟେ।\n\nଆପଣଙ୍କ IT ଆଡମିନ୍ ସେଟିଂସ୍, କର୍ପୋରେଟ୍ ଆକ୍ସେସ୍, ଆପ୍ସ, ଆପଣଙ୍କ ଡିଭାଇସ୍ ସହ ସମ୍ବନ୍ଧିତ ଡାଟା ଏବଂ ଆପଣଙ୍କ ଡିଭାଇସର ଲୋକେସନ୍ ସୂଚନାକୁ ନିରୀକ୍ଷଣ ଏବଂ ପରିଚାଳନା କରିପାରିବେ।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ଆପଣଙ୍କ IT ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ଏହି ଡିଭାଇସଟି ଆପଣଙ୍କ ସଂସ୍ଥାର ଅଟେ।\n\nଆପଣଙ୍କ IT ଆଡମିନ୍ ସେଟିଂସ୍, କର୍ପୋରେଟ୍ ଆକ୍ସେସ୍, ଆପ୍ସ, ଆପଣଙ୍କ ଡିଭାଇସ୍ ସହ ସମ୍ବନ୍ଧିତ ଡାଟା ଏବଂ ଆପଣଙ୍କ ଡିଭାଇସର ଲୋକେସନ୍ ସୂଚନାକୁ ନିରୀକ୍ଷଣ ଏବଂ ପରିଚାଳନା କରିପାରିବେ।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ଆପଣଙ୍କ IT ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ଏହି ଡିଭାଇସରେ ଆପଣଙ୍କ ସଂସ୍ଥା ଏକ ସର୍ଟିଫିକେଟ୍‍ ଅଥରିଟି ଇନଷ୍ଟଲ୍‍ କରିଛନ୍ତି। ଆପଣଙ୍କ ସୁରକ୍ଷିତ ନେଟୱର୍କ ଟ୍ରାଫିକ୍‍ ନୀରିକ୍ଷଣ କିମ୍ବା ସଂଶୋଧନ କରାଯାଇ ପାରେ।"</string>
@@ -573,8 +572,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"ଆପଣଙ୍କ ଆଡମିନ୍‍ ନେଟ୍‌ୱର୍କ ଲଗଇନ୍‍ କରିବା ଅନ୍‍ କରିଛନ୍ତି, ଯାହା ଆପଣଙ୍କ ଡିଭାଇସରେ ଟ୍ରାଫିକ୍‍ ନିରୀକ୍ଷଣ କରେ।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ନିଜ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"ଏକ VPN ସଂଯୋଗ ସେଟ୍‍ ଅପ୍‍ କରିବା ପାଇଁ ଆପଣ ଗୋଟିଏ ଆପକୁ ଅନୁମତି ଦେଲେ।\n\nଏହି ଆପ୍‍ ଇମେଲ୍‍, ଆପ୍‌ ଓ ୱେବସାଇଟ୍‍ ସମେତ ଆପଣଙ୍କ ଡିଭାଇସ୍‍ ଓ ନେଟ୍‌ୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲ୍‍ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳନା କରାଯାଉଛି।\n\nଆପଣଙ୍କ ଆଡମିନ୍‍ ଇମେଲ୍‍, ଆପ୍‌ ଓ ୱେବସାଇଟ୍‍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରିବେ।\n\nଅଧିକ ସୂଚନା ପାଇଁ, ନିଜ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।.\n\nଆପଣ ଏକ VPNରେ ମଧ୍ୟ ସଂଯୁକ୍ତ, ଯାହା ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
- <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
- <skip />
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ଏହି ଡିଭାଇସ୍ ଆପଣଙ୍କ ବାପାମାଙ୍କ ଦ୍ୱାରା ପରିଚାଳିତ। ଆପଣଙ୍କ ବାପାମା ଆପଣ ବ୍ୟବହାର କରୁଥିବା ଆପ୍ସ, ଆପଣଙ୍କ ଲୋକେସନ୍ ଓ ସ୍କ୍ରିନ୍ ସମୟ ପରି ସୂଚନା ଦେଖିପାରିବେ ଏବଂ ପରିଚାଳନା କରିପାରିବେ।"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"ଆପଣ <xliff:g id="APPLICATION">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ, ଯାହା ଇମେଲ୍‍, ଆପ୍‌ ଓ ୱେବସାଇଟ୍‍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"ଆପଣ <xliff:g id="APPLICATION">%1$s</xliff:g>ରେ ସଂଯୁକ୍ତ, ଯାହା ଇମେଲ୍‍, ଆପ୍‌ ଓ ୱେବସାଇଟ୍‍ ସମେତ ଆପଣଙ୍କ ନେଟ୍‌ୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
@@ -717,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"ଏହି ଆପ୍‌ରୁ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖାଇବା ଜାରି ରଖିବେ?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ନୀରବ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ଡିଫଲ୍ଟ"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"ବବଲ୍"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ସ୍ୱଚାଳିତ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"କୌଣସି ସାଉଣ୍ଡ କିମ୍ବା ଭାଇବ୍ରେସନ୍ ନାହିଁ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"କୌଣସି ସାଉଣ୍ଡ କିମ୍ବା ଭାଇବ୍ରେସନ୍ ନାହିଁ ଏବଂ ବାର୍ତ୍ତାଳାପ ବିଭାଗର ନିମ୍ନରେ ଦେଖାଯାଏ"</string>
@@ -729,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ସେଟିଂସ୍"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ପ୍ରାଥମିକତା"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ଫିଚରଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ବର୍ତ୍ତମାନ କୌଣସି ବବଲ୍ ନାହିଁ"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ବର୍ତ୍ତମାନର ଏବଂ ଖାରଜ କରାଯାଇଥିବା ବବଲଗୁଡ଼ିକ ଏଠାରେ ଦେଖାଯିବ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପରିବର୍ତ୍ତନ କରିହେବ ନାହିଁ।"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"ଏଠାରେ ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଗ୍ରୁପ୍ କନଫ୍ୟୁଗର୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ବିଜ୍ଞପ୍ତି ପ୍ରକ୍ସୀ ହୋଇଛି"</string>
@@ -989,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"ଡିଭାଇସ୍‍ ସେବାଗୁଡିକ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"କୌଣସି ଶୀର୍ଷକ ନାହିଁ"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ଏହି ଆପ୍‌କୁ ରିଷ୍ଟାର୍ଟ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ ଏବଂ ଫୁଲ୍‌ସ୍କ୍ରିନ୍‌କୁ ଯାଆନ୍ତୁ।"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବବଲ୍‌ଗୁଡ଼ିକ ପାଇଁ ସେଟିଂସ୍"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ଓଭରଫ୍ଲୋ"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ଷ୍ଟାକରେ ପୁଣି ଯୋଗ କରନ୍ତୁ"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"ପରିଚାଳନା କରନ୍ତୁ"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>ରୁ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> ଏବଂ ଅଧିକ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>ଟିରୁ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"ନିଅନ୍ତୁ"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ଉପର ବାମକୁ ନିଅନ୍ତୁ"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ଉପର-ଡାହାଣକୁ ନିଅନ୍ତୁ"</string>
- <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="1314082410868930066">"ବବଲ୍ ଖାରଜ କରନ୍ତୁ"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ବାର୍ତ୍ତାଳାପକୁ ବବଲ୍ କରନ୍ତୁ ନାହିଁ"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"ବବଲଗୁଡ଼ିକୁ ବ୍ୟବହାର କରି ଚାଟ୍ କରନ୍ତୁ"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"ନୂଆ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ଫ୍ଲୋଟିଂ ଆଇକନ୍ କିମ୍ବା ବବଲ୍ ଭାବେ ଦେଖାଯିବ। ବବଲ୍ ଖୋଲିବାକୁ ଟାପ୍ କରନ୍ତୁ। ଏହାକୁ ମୁଭ୍ କରିବାକୁ ଟାଣନ୍ତୁ।"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ଯେ କୌଣସି ସମୟରେ ବବଲଗୁଡ଼ିକ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ଏହି ଆପର ବବଲଗୁଡ଼ିକ ବନ୍ଦ କରିବା ପାଇଁ \'ପରିଚାଳନା କରନ୍ତୁ\' ବଟନରେ ଟାପ୍ କରନ୍ତୁ"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ବୁଝିଗଲି"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ସେଟିଂସ୍"</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>
@@ -1097,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ନୂଆ ଡିଭାଇସକୁ ପେୟାର୍ କରନ୍ତୁ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ବିଲ୍ଡ ନମ୍ୱର"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"କ୍ଲିପବୋର୍ଡକୁ କପି କରାଯାଇଥିବା ବିଲ୍ଡ ନମ୍ୱର।"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ଆପଣଙ୍କ ବ୍ୟାଟେରୀ ମିଟର୍ ପଢ଼ିବାରେ ସମସ୍ୟା ହେଉଛି"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ଅଧିକ ସୂଚନା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings_tv.xml b/packages/SystemUI/res/values-or/strings_tv.xml
index b44dc3bffe12..f436babfa20a 100644
--- a/packages/SystemUI/res/values-or/strings_tv.xml
+++ b/packages/SystemUI/res/values-or/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"ମାଇକ୍ରୋଫୋନ୍ ସକ୍ରିୟ"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ଆପଣଙ୍କର ମାଇକ୍ରୋଫୋନ୍‌କୁ ଆକ୍ସେସ୍ କରିଛି"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ସଂଯୋଗ କରାଯାଇଛି"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ବିଚ୍ଛିନ୍ନ କରାଯାଇଛି"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ମାଧ୍ୟମରେ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index d05f80d6698d..d9a68281eb73 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦੁਬਾਰਾ ਲੈ ਕੇ ਦੇਖੋ"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"ਸੀਮਿਤ ਸਟੋਰੇਜ ਹੋਣ ਕਾਰਨ ਸਕ੍ਰੀਨਸ਼ਾਟ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲੈਣ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਹੈ"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਖਾਰਜ ਕਰੋ"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"ਸੰਪਾਦਨ ਕਰੋ"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"ਸਕ੍ਰੋਲ ਕਰੋ"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨੂੰ ਸਕ੍ਰੋਲ ਕਰੋ"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਖਾਰਜ ਕਰੋ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਪੂਰਵ-ਝਲਕ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"ਬੈਟਰੀ ਦੋ ਬਾਰਸ।"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"ਬੈਟਰੀ ਤਿੰਨ ਬਾਰਸ।"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"ਬੈਟਰੀ ਪੂਰੀ।"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ਬੈਟਰੀ ਪ੍ਰਤੀਸ਼ਤ ਅਗਿਆਤ ਹੈ।"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"ਕੋਈ ਫ਼ੋਨ ਨਹੀਂ।"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ਫ਼ੋਨ ਇੱਕ ਬਾਰ।"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ਫ਼ੋਨ ਦੋ ਬਾਰਸ।"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ਸੂਚਨਾ ਰੱਦ ਕੀਤੀ।"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕੀਤਾ ਗਿਆ।"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ਸੂਚਨਾ ਸ਼ੇਡ।"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">" ਲਾਕ ਸਕ੍ਰੀਨ।"</string>
@@ -522,8 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"ਪ੍ਰੋਫਾਈਲ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
<string name="vpn_footer" msgid="3457155078010607471">"ਨੈੱਟਵਰਕ ਦਾ ਨਿਰੀਖਣ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"ਹੋ ਸਕਦਾ ਹੈ ਨੈੱਟਵਰਕ ਦੀ ਨਿਗਰਾਨੀ ਹੋ ਰਹੀ ਹੋਵੇ"</string>
- <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
- <skip />
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"ਇਸ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਬੰਧਨ ਤੁਹਾਡੇ ਮਾਂ-ਪਿਓ ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"ਤੁਹਾਡੀ ਸੰਸਥਾ ਕੋਲ ਇਸ ਡੀਵਾਈਸ ਦੀ ਮਲਕੀਅਤ ਹੈ ਅਤੇ ਇਹ ਨੈੱਟਵਰਕ ਟਰੈਫ਼ਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ਕੋਲ ਇਸ ਡੀਵਾਈਸ ਦੀ ਮਲਕੀਅਤ ਹੈ ਅਤੇ ਇਹ ਨੈੱਟਵਰਕ ਟਰੈਫ਼ਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"ਇਹ ਡੀਵਾਈਸ ਤੁਹਾਡੀ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ ਅਤੇ <xliff:g id="VPN_APP">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ"</string>
@@ -548,8 +548,7 @@
<string name="disable_vpn" msgid="482685974985502922">"VPN ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPN ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"ਨੀਤੀਆਂ ਦੇਖੋ"</string>
- <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
- <skip />
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"ਕੰਟਰੋਲ ਦੇਖੋ"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"ਇਹ ਡੀਵਾਈਸ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ।\n\nਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨਾਲ ਸੰਬੰਧਿਤ ਸੈਟਿੰਗਾਂ, ਕਾਰਪੋਰੇਟ ਪਹੁੰਚ, ਐਪਾਂ, ਡਾਟੇ ਅਤੇ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਟਿਕਾਣਾ ਜਾਣਕਾਰੀ ਦੀ ਨਿਗਰਾਨੀ ਅਤੇ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦਾ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"ਇਹ ਡੀਵਾਈਸ ਤੁਹਾਡੀ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਹੈ।\n\nਤੁਹਾਡਾ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨਾਲ ਸੰਬੰਧਿਤ ਸੈਟਿੰਗਾਂ, ਕਾਰਪੋਰੇਟ ਪਹੁੰਚ, ਐਪਾਂ, ਡਾਟੇ ਅਤੇ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਟਿਕਾਣਾ ਜਾਣਕਾਰੀ ਦੀ ਨਿਗਰਾਨੀ ਅਤੇ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦਾ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਇੱਕ ਪ੍ਰਮਾਣ-ਪੱਤਰ ਅਥਾਰਟੀ ਸਥਾਪਤ ਕੀਤੀ ਗਈ ਹੈ। ਤੁਹਾਡੇ ਸੁਰੱਖਿਅਤ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ ਜਾਂ ਉਸਨੂੰ ਸੋਧਿਆ ਜਾ ਸਕਦਾ ਹੈ।"</string>
@@ -573,8 +572,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਨੇ ਨੈੱਟਵਰਕ ਲੌਗਿੰਗ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਹੋਇਆ ਹੈ, ਜੋ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰਦਾ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"ਤੁਸੀਂ ਕਿਸੇ ਐਪ ਨੂੰ ਇੱਕ VPN ਕਨੈਕਸ਼ਨ ਸੈੱਟ ਅੱਪ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਹੈ।\n\nਇਹ ਐਪ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਅਤੇ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ, ਈਮੇਲਾਂ, ਐਪਾਂ ਅਤੇ ਸੁਰੱਖਿਅਤ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ।"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।\n\nਤੁਹਾਡਾ ਪ੍ਰਸ਼ਾਸਕ ਈਮੇਲ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰਨ ਦੇ ਸਮਰੱਥ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।\n\nਤੁਸੀਂ ਇੱਕ VPN ਨਾਲ ਵੀ ਕਨੈਕਟ ਹੋਂ, ਜੋ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ।"</string>
- <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
- <skip />
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ਇਸ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਬੰਧਨ ਤੁਹਾਡੇ ਮਾਂ-ਪਿਓ ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਤੁਹਾਡੇ ਮਾਂ-ਪਿਓ ਤੁਹਾਡੀਆਂ ਐਪਾਂ ਦੀ ਵਰਤੋਂ, ਤੁਹਾਡੇ ਟਿਕਾਣੇ ਅਤੇ ਤੁਹਾਡੇ ਸਕ੍ਰੀਨ ਸਮੇਂ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ ਦੇਖ ਅਤੇ ਉਸਦਾ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦੇ ਹਨ।"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲ, ਐਪਸ ਅਤੇ ਵੈਬਸਫ਼ਿਆਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨੈੱਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ।"</string>
@@ -717,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"ਕੀ ਇਸ ਐਪ ਤੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਦਿਖਾਉਣਾ ਜਾਰੀ ਰੱਖਣਾ ਹੈ?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ਸ਼ਾਂਤ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"ਬੁਲਬੁਲਾ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ਸਵੈਚਲਿਤ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ਕੋਈ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਹੀਂ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ਕੋਈ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਹੀਂ ਅਤੇ ਸੂਚਨਾਵਾਂ ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਵਿੱਚ ਹੇਠਲੇ ਪਾਸੇ ਦਿਸਦੀਆਂ ਹਨ"</string>
@@ -729,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ਸੈਟਿੰਗਾਂ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ਤਰਜੀਹ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਗੱਲਬਾਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ਕੋਈ ਹਾਲੀਆ ਬਬਲ ਨਹੀਂ"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ਹਾਲੀਆ ਬਬਲ ਅਤੇ ਖਾਰਜ ਕੀਤੇ ਬਬਲ ਇੱਥੇ ਦਿਸਣਗੇ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"ਇਹ ਸੂਚਨਾਵਾਂ ਦਾ ਗਰੁੱਪ ਇੱਥੇ ਸੰਰੂਪਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ਇੱਕ ਐਪ ਦੀ ਥਾਂ \'ਤੇ ਦੂਜੀ ਐਪ ਰਾਹੀਂ ਦਿੱਤੀ ਗਈ ਸੂਚਨਾ"</string>
@@ -989,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ਇਸ ਐਪ ਨੂੰ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਅਤੇ ਪੂਰੀ-ਸਕ੍ਰੀਨ ਮੋਡ \'ਤੇ ਜਾਓ।"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਬਬਲ ਲਈ ਸੈਟਿੰਗਾਂ"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ਓਵਰਫ਼ਲੋ"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"ਸਟੈਕ ਵਿੱਚ ਵਾਪਸ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਅਤੇ <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ਹੋਰਾਂ ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"ਲਿਜਾਓ"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ਉੱਪਰ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ਉੱਪਰ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
- <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="1314082410868930066">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕਰੋ"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ਗੱਲਬਾਤ \'ਤੇ ਬਬਲ ਨਾ ਲਾਓ"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"ਬਬਲ ਵਰਤਦੇ ਹੋਏ ਚੈਟ ਕਰੋ"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"ਨਵੀਆਂ ਗੱਲਾਂਬਾਤਾਂ ਫਲੋਟਿੰਗ ਪ੍ਰਤੀਕਾਂ ਜਾਂ ਬਬਲ ਦੇ ਰੂਪ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ। ਬਬਲ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਇਸਨੂੰ ਲਿਜਾਣ ਲਈ ਘਸੀਟੋ।"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ਬਬਲ ਨੂੰ ਕਿਸੇ ਵੇਲੇ ਵੀ ਕੰਟਰੋਲ ਕਰੋ"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ਇਸ ਐਪ \'ਤੇ ਬਬਲ ਬੰਦ ਕਰਨ ਲਈ \'ਪ੍ਰਬੰਧਨ ਕਰੋ\' \'ਤੇ ਟੈਪ ਕਰੋ"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ਸਮਝ ਲਿਆ"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ਸੈਟਿੰਗਾਂ"</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>
@@ -1097,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"ਬਿਲਡ ਨੰਬਰ"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"ਬਿਲਡ ਨੰਬਰ ਨੂੰ ਕਲਿੱਪਬੋਰਡ \'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ।"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ਤੁਹਾਡੇ ਬੈਟਰੀ ਮੀਟਰ ਨੂੰ ਪੜ੍ਹਨ ਵਿੱਚ ਸਮੱਸਿਆ ਹੋ ਰਹੀ ਹੈ"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings_tv.xml b/packages/SystemUI/res/values-pa/strings_tv.xml
index f5300b318d10..d10daa85da5a 100644
--- a/packages/SystemUI/res/values-pa/strings_tv.xml
+++ b/packages/SystemUI/res/values-pa/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਕਿਰਿਆਸ਼ੀਲ"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ਨੇ ਤੁਹਾਡੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਤੱਕ ਪਹੁੰਚ ਕੀਤੀ"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ਕਨੈਕਟ ਹੈ"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN ਡਿਸਕਨੈਕਟ ਹੈ"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ਰਾਹੀਂ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 7343b26c18ab..1c6b6a1d7961 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Spróbuj jeszcze raz wykonać zrzut ekranu"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Nie można zapisać zrzutu ekranu, bo brakuje miejsca w pamięci"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Nie możesz wykonać zrzutu ekranu, bo nie zezwala na to aplikacja lub Twoja organizacja."</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Edytuj zrzut ekranu"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Zamknij zrzut ekranu"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Edytuj"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Edytuj zrzut ekranu"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Przewiń"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Przewiń zrzut ekranu"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zamknij zrzut ekranu"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Podgląd zrzutu ekranu"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Nagrywanie ekranu"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Przetwarzam nagrywanie ekranu"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Bateria: dwa paski."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Bateria: trzy paski."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria naładowana."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Poziom naładowania baterii jest nieznany."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Brak sygnału telefonu."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon: jeden pasek."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon: dwa paski."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Zamknięto powiadomienie."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Zamknięto dymek"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Obszar powiadomień."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Szybkie ustawienia."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekran blokady."</string>
@@ -720,7 +721,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Nadal pokazywać powiadomienia z tej aplikacji?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Bez dźwięku"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Domyślne"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Dymek"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatycznie"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Brak dźwięku i wibracji"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Brak dźwięku i wibracji, wyświetla się niżej w sekcji rozmów"</string>
@@ -732,8 +732,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ustawienia"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorytet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje funkcji rozmów"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Brak ostatnich dymków"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Tutaj będą pojawiać się ostatnie i odrzucone dymki"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tych powiadomień nie można zmodyfikować."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Tej grupy powiadomień nie można tu skonfigurować"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Powiadomienie w zastępstwie"</string>
@@ -996,25 +994,7 @@
<string name="device_services" msgid="1549944177856658705">"Usługi urządzenia"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez tytułu"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Kliknij, by uruchomić tę aplikację ponownie i przejść w tryb pełnoekranowy."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Ustawienia dymków aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Przepełnienie"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Dodaj ponownie do stosu"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Zarządzaj"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikacji <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikacji <xliff:g id="APP_NAME">%2$s</xliff:g> i jeszcze <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Przenieś"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Przenieś w lewy górny róg"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Przenieś w prawy górny róg"</string>
- <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="1314082410868930066">"Zamknij dymek"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nie wyświetlaj rozmowy jako dymka"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Czatuj, korzystając z dymków"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nowe rozmowy będą wyświetlane jako pływające ikony lub dymki. Kliknij, by otworzyć dymek. Przeciągnij, by go przenieść."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Zarządzaj dymkami w dowolnym momencie"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Kliknij Zarządzaj, aby wyłączyć dymki z tej aplikacji"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – ustawienia"</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>
@@ -1106,8 +1086,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sparuj nowe urządzenie"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numer kompilacji"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numer kompilacji został skopiowany do schowka."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem z odczytaniem pomiaru wykorzystania baterii"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Kliknij, aby uzyskać więcej informacji"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings_tv.xml b/packages/SystemUI/res/values-pl/strings_tv.xml
index b060141b0275..d83391e01b57 100644
--- a/packages/SystemUI/res/values-pl/strings_tv.xml
+++ b/packages/SystemUI/res/values-pl/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon aktywny"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacja %1$s uzyskała dostęp do mikrofonu"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"Połączono z VPN"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Rozłączono z VPN"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Przez: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 344671d1df9c..d058eddbcf36 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Tente fazer a captura de tela novamente"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Não é possível salvar a captura de tela, porque não há espaço suficiente"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"O app ou a organização não permitem capturas de tela"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Editar captura de tela"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dispensar captura de tela"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de tela"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Rolar"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Captura de tela da página inteira"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dispensar captura de tela"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Visualização de captura de tela"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de tela"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processando gravação de tela"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Duas barras de bateria."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Três barras de bateria."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria cheia."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentagem da bateria desconhecida."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sem telefone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Uma barra de sinal do telefone."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Duas barras de sinal do telefone."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificação dispensada."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balão dispensado."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Aba de notificações."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configurações rápidas."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Tela de bloqueio."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Continuar mostrando notificações desse app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silencioso"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Padrão"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bolha"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Som e vibração desativados"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"O som e a vibração estão desativados, e o balão aparece na parte inferior da seção de conversa"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configurações"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritárias"</string>
<string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nenhum balão recente"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Os balões recentes e dispensados aparecerão aqui"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar esse grupo de notificações aqui"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notificação salva no proxy"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toque para reiniciar o app e usar tela cheia."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configurações de balões do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menu flutuante"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Devolver à pilha"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Gerenciar"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> mais <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Mover"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Mover para canto superior esquerdo"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover para canto superior direito"</string>
- <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="1314082410868930066">"Dispensar balão"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não criar balões de conversa"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse usando balões"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controle os balões a qualquer momento"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toque em \"Gerenciar\" para desativar os balões desse app"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Ok"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Configurações de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema para ler seu medidor de bateria"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para mais informações"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
index 19cb4eacf402..49b923d076b7 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Microfone ativado"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s acessou seu microfone"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"A VPN está conectada"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"A VPN está desconectada"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 709f532bb50c..dcaf46027b2c 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Experimente voltar a efetuar a captura de ecrã."</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Não é possível guardar a captura de ecrã devido a espaço de armazenamento limitado."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"A app ou a sua entidade não permitem tirar capturas de ecrã"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Editar captura de ecrã"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ignorar captura de ecrã"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de ecrã"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Deslocar"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Deslocar captura de ecrã"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ignorar captura de ecrã"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pré-visualização da captura de ecrã"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de ecrã"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"A processar a gravação de ecrã"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Duas barras de bateria."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Três barras de bateria."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria carregada."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percentagem da bateria desconhecida."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sem telefone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Uma barra de telefone."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Duas barras de telefone."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificação ignorada."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balão ignorado."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Painel de notificações."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Definições rápidas."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ecrã de bloqueio."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Pretende continuar a ver notificações desta app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silencioso"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Predefinição"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Balão"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sem som ou vibração"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sem som ou vibração e aparece na parte inferior na secção de conversas."</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Definições"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
<string name="no_shortcut" msgid="8257177117568230126">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> não suporta funcionalidades de conversa."</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nenhum balão recente"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Os balões recentes e ignorados vão aparecer aqui."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar estas notificações."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar este grupo de notificações aqui."</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notificação de app proxy"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toque para reiniciar esta app e ficar em ecrã inteiro."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Definições dos balões da app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menu adicional"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Adicionar novamente à pilha"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Gerir"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> do <xliff:g id="APP_NAME">%2$s</xliff:g> e mais<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>."</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Mover"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Mover p/ parte sup. esquerda"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover parte superior direita"</string>
- <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="1314082410868930066">"Ignorar balão"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não apresentar a conversa em balões"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse no chat através de balões"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"As novas conversas aparecem como ícones flutuantes ou balões. Toque para abrir o balão. Arraste para o mover."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controle os balões em qualquer altura"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toque em Gerir para desativar os balões desta app."</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Definições de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Sincronize o novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da compilação"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da compilação copiado para a área de transferência."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Ocorreu um problema ao ler o medidor da bateria"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para obter mais informações"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
index 2e60421c9008..a36a1a92d882 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Microfone ativado"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s acedeu ao microfone"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"A VPN está ligada"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"A VPN está desligada"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Através de <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 344671d1df9c..d058eddbcf36 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Tente fazer a captura de tela novamente"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Não é possível salvar a captura de tela, porque não há espaço suficiente"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"O app ou a organização não permitem capturas de tela"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Editar captura de tela"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Dispensar captura de tela"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de tela"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Rolar"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Captura de tela da página inteira"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Dispensar captura de tela"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Visualização de captura de tela"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Gravador de tela"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processando gravação de tela"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Duas barras de bateria."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Três barras de bateria."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria cheia."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Porcentagem da bateria desconhecida."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Sem telefone."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Uma barra de sinal do telefone."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Duas barras de sinal do telefone."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificação dispensada."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balão dispensado."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Aba de notificações."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Configurações rápidas."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Tela de bloqueio."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Continuar mostrando notificações desse app?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silencioso"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Padrão"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bolha"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Som e vibração desativados"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"O som e a vibração estão desativados, e o balão aparece na parte inferior da seção de conversa"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configurações"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritárias"</string>
<string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nenhum balão recente"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Os balões recentes e dispensados aparecerão aqui"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar esse grupo de notificações aqui"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notificação salva no proxy"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Toque para reiniciar o app e usar tela cheia."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Configurações de balões do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Menu flutuante"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Devolver à pilha"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Gerenciar"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> mais <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Mover"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Mover para canto superior esquerdo"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover para canto superior direito"</string>
- <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="1314082410868930066">"Dispensar balão"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não criar balões de conversa"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse usando balões"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controle os balões a qualquer momento"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toque em \"Gerenciar\" para desativar os balões desse app"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Ok"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Configurações de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parear novo dispositivo"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Número da versão"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Número da versão copiado para a área de transferência."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problema para ler seu medidor de bateria"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Toque para mais informações"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings_tv.xml b/packages/SystemUI/res/values-pt/strings_tv.xml
index 19cb4eacf402..49b923d076b7 100644
--- a/packages/SystemUI/res/values-pt/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Microfone ativado"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s acessou seu microfone"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"A VPN está conectada"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"A VPN está desconectada"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 6c544604821c..81caf56e4939 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Încercați să faceți din nou o captură de ecran"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Captura de ecran nu poate fi salvată din cauza spațiului de stocare limitat"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Crearea capturilor de ecran nu este permisă de aplicație sau de organizația dvs."</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Editați captura de ecran"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Închideți captura de ecran"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Editați"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Editați captura de ecran"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Derulați"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Derulați captura de ecran"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Închideți captura de ecran"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Previzualizare a capturii de ecran"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Recorder pentru ecran"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Se procesează înregistrarea"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterie: două bare."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterie: trei bare."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterie: complet."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Procentajul bateriei este necunoscut."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nu există semnal pentru telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Semnal pentru telefon: o bară."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Semnal pentru telefon: două bare."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Notificarea a fost închisă."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balonul a fost respins."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Fereastră pentru notificări."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Setări rapide."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ecranul de blocare."</string>
@@ -717,7 +718,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Doriți să continuați afișarea notificărilor de la această aplicație?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Silențios"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Prestabilite"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Balon"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automat"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Fără sunet sau vibrații"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Fără sunet sau vibrații și apare în partea de jos a secțiunii de conversație"</string>
@@ -729,8 +729,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Setări"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritate"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă funcții pentru conversații"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nu există baloane recente"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Baloanele recente și baloanele respinse vor apărea aici"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aceste notificări nu pot fi modificate."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Acest grup de notificări nu poate fi configurat aici"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Notificare prin proxy"</string>
@@ -991,25 +989,7 @@
<string name="device_services" msgid="1549944177856658705">"Servicii pentru dispozitiv"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Fără titlu"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Atingeți ca să reporniți aplicația și să treceți în modul ecran complet."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Setări pentru baloanele <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Suplimentar"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Adăugați înapoi în stivă"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Gestionați"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g> și încă <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Mutați"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Mutați în stânga sus"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mutați în dreapta sus"</string>
- <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="1314082410868930066">"Închideți balonul"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nu afișați conversația în balon"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat cu baloane"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Conversațiile noi apar ca pictograme flotante sau baloane. Atingeți pentru a deschide balonul. Trageți pentru a-l muta."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controlați oricând baloanele"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Atingeți Gestionați pentru a dezactiva baloanele din această aplicație"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Setări <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1100,8 +1080,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Asociați un nou dispozitiv"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numărul versiunii"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numărul versiunii s-a copiat în clipboard."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problemă la citirea măsurării bateriei"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Atingeți pentru mai multe informații"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings_tv.xml b/packages/SystemUI/res/values-ro/strings_tv.xml
index f4349ff91b05..69a31383a6cc 100644
--- a/packages/SystemUI/res/values-ro/strings_tv.xml
+++ b/packages/SystemUI/res/values-ro/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Microfon activ"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s a accesat microfonul"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN este conectat"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN este deconectat"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prin <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 53773cf4d253..bf5e6047a525 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Попробуйте сделать скриншот снова."</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Не удалось сохранить скриншот: недостаточно места."</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Не удалось сделать скриншот: нет разрешения от приложения или организации."</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Изменить скриншот"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Закрыть скриншот"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Изменить"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Изменить скриншот"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Прокрутить"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Прокрутить скриншот"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Закрыть скриншот"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Предварительный просмотр скриншота"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Запись видео с экрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обработка записи с экрана…"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Заряд батареи: два деления."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Заряд батареи: три деления."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батарея полностью заряжена."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Уровень заряда батареи в процентах неизвестен."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Сигнал телефонной сети отсутствует."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Сигнал телефонной сети: одно деление."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Сигнал телефонной сети: два деления."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Уведомление закрыто"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Всплывающий чат закрыт."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панель уведомлений"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Быстрые настройки"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Экран блокировки."</string>
@@ -720,7 +721,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Показывать уведомления от этого приложения?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Без звука"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"По умолчанию"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Всплывающая подсказка"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматически"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звука или вибрации"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звука или вибрации, появляется в нижней части списка разговоров"</string>
@@ -732,8 +732,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Настройки"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает функции разговоров."</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нет недавних всплывающих чатов"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Здесь будут появляться недавние и скрытые всплывающие чаты."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эти уведомления нельзя изменить."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Эту группу уведомлений нельзя настроить здесь."</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Уведомление отправлено через прокси-сервер."</string>
@@ -996,25 +994,7 @@
<string name="device_services" msgid="1549944177856658705">"Сервисы устройства"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без названия"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Нажмите, чтобы перезапустить приложение и перейти в полноэкранный режим."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Настройки всплывающих чатов от приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Дополнительное меню"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Добавить обратно в стек"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Настроить"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> из приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> от приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" и ещё <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Перенести"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Перенести в левый верхний угол"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перенести в правый верхний угол"</string>
- <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="1314082410868930066">"Скрыть всплывающий чат"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не показывать всплывающий чат для разговора"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Всплывающие чаты"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новые разговоры будут появляться в виде плавающих значков, или всплывающих чатов. Чтобы открыть чат, нажмите на него, а чтобы переместить – перетащите."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Всплывающие чаты"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Чтобы отключить всплывающие чаты из этого приложения, нажмите \"Настроить\"."</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ОК"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: настройки"</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>
@@ -1106,8 +1086,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Подключить новое устройство"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер сборки"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер сборки скопирован в буфер обмена."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не удается получить данные об уровне заряда батареи"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Нажмите, чтобы узнать больше."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings_tv.xml b/packages/SystemUI/res/values-ru/strings_tv.xml
index b8638b711176..bd8855bb1b56 100644
--- a/packages/SystemUI/res/values-ru/strings_tv.xml
+++ b/packages/SystemUI/res/values-ru/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Микрофон включен"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Приложение \"%1$s\" использовало доступ к микрофону."</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN-подключение установлено"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN-подключение отключено"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Отправлено через <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index afd556ac074f..c855be3dd624 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"තිර රුව නැවත ගැනීමට උත්සාහ කරන්න"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"සීමිත ගබඩා ඉඩ නිසා තිර රුව සුරැකිය නොහැකිය"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"තිර රූ ගැනීමට යෙදුම හෝ ඔබගේ සංවිධානය ඉඩ නොදේ"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"තිර රුව සංස්කරණය කරන්න"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"තිර රුව ඉවත ලන්න"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"සංස්කරණය කරන්න"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"තිර රුව සංස්කරණය කරන්න"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"අනුචලනය කරන්න"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"තිර රුව අනුචලනය කරන්න"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"තිර රුව ඉවත ලන්න"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"තිර රූ පෙර දසුන"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"තිර රෙකෝඩරය"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"තිර පටිගත කිරීම සකසමින්"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"බැටරිය තීරු දෙකයි."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"බැටරිය තීරු තුනයි."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"බැටරිය පිරී ඇත."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"බැටරි ප්‍රතිශතය නොදනී."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"දුරකථනයක් නැත."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"දුරකථනය තීරු එකයි."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"දුරකථනය තීරු දෙකයි."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"දැනුම්දීම නිෂ්ප්‍රභා කරඇත."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"බුබුල ඉවත දමා ඇත."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"දැනුම්දීම් ආවරණය."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ක්ෂණික සැකසීම්."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"අගුළු තිරය."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"මෙම යෙදුම වෙතින් දැනුම්දීම් පෙන්වමින් තබන්නද?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"නිහඬ"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"පෙරනිමි"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"බුබුළු"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ස්වයංක්‍රිය"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"හඬක් හෝ කම්පනයක් නැත"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"හඬක් හෝ කම්පනයක් නැති අතර සංවාද කොටසේ පහළම දිස් වේ"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"සැකසීම්"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ප්‍රමුඛතාව"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> සංවාද විශේෂාංගවලට සහාය නොදක්වයි"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"මෑත බුබුලු නැත"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"මෑත බුබුලු සහ ඉවත ලූ බුබුලු මෙහි දිස් වනු ඇත"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"මෙම දැනුම්දීම් වෙනස් කළ නොහැක."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"මෙම දැනුම්දීම් සමූහය මෙහි වින්‍යාස කළ නොහැක"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ප්‍රොක්සි කළ දැනුම්දීම"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"උපාංග සේවා"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"මාතෘකාවක් නැත"</string>
<string name="restart_button_description" msgid="6916116576177456480">"මෙම යෙදුම යළි ඇරඹීමට සහ පූර්ණ තිරයට යාමට තට්ටු කරන්න"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> බුබුළු සඳහා සැකසීම්"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"පිටාර යාම"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"අට්ටිය වෙත ආපසු එක් කරන්න"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"කළමනා කරන්න"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> වෙතින් <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> වෙතින් <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> සහ තවත් <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ක්"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"ගෙන යන්න"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ඉහළ වමට ගෙන යන්න"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ඉහළ දකුණට ගෙන යන්න"</string>
- <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="1314082410868930066">"බුබුලු ඉවත ලන්න"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"සංවාදය බුබුලු නොදමන්න"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"බුබුලු භාවිතයෙන් කතාබහ කරන්න"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"නව සංවාද පාවෙන අයිකන හෝ බුබුලු ලෙස දිස් වේ. බුබුල විවෘත කිරීමට තට්ටු කරන්න. එය ගෙන යාමට අදින්න."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ඕනෑම වේලාවක බුබුලු පාලනය කරන්න"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"මෙම යෙදුමෙන් බුබුලු ක්‍රියාවිරහිත කිරීමට කළමනාකරණය කරන්න තට්ටු කරන්න"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"තේරුණා"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> සැකසීම්"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"නව උපාංගය යුගල කරන්න"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"නිමැවුම් අංකය"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"නිමැවුම් අංකය පසුරු පුවරුවට පිටපත් කරන ලදි."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"ඔබගේ බැටරි මනුව කියවීමේ දෝෂයකි"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"තවත් තොරතුරු සඳහා තට්ටු කරන්න"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings_tv.xml b/packages/SystemUI/res/values-si/strings_tv.xml
index 411c0a075914..a04d166ebea3 100644
--- a/packages/SystemUI/res/values-si/strings_tv.xml
+++ b/packages/SystemUI/res/values-si/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"මයික්‍රොෆෝනය සක්‍රියයි"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ඔබේ මයික්‍රොෆෝනයට ප්‍රවේශ වී ඇත"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN සම්බන්ධිතයි"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN විසන්ධි කර ඇත"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> හරහා"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 4c518dcc8379..c2a94be4ad2d 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Skúste snímku urobiť znova"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Snímka obrazovky sa nedá uložiť z dôvodu nedostatku miesta v úložisku"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Vytváranie snímok obrazovky je zakázané aplikáciou alebo vašou organizáciou"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Upraviť snímku obrazovky"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Zavrieť snímku obrazovky"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Upraviť"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Upraviť snímku obrazovky"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Posúvanie"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Posúvať snímku obrazovky"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Zavrieť snímku obrazovky"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ukážka snímky obrazovky"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Rekordér obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Spracúva sa záznam obrazovky"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Dve čiarky batérie."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Tri čiarky batérie."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batéria je nabitá."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Percento batérie nie je známe."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Žiadna telefónna sieť."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Jeden stĺpec signálu telefónnej siete."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Dve čiarky signálu telefónnej siete."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Upozornenie bolo zrušené."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bublina bola zavretá."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Panel upozornení."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Rýchle nastavenia."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Uzamknutá obrazovka"</string>
@@ -720,7 +721,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Majú sa upozornenia z tejto aplikácie naďalej zobrazovať?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Tiché"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Predvolené"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bublina"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaticky"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Žiadny zvuk ani vibrácie"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Žiadny zvuk ani vibrácie a zobrazuje sa nižšie v sekcii konverzácií"</string>
@@ -732,8 +732,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavenia"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje funkcie konverzácie"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Žiadne nedávne bubliny"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Tu sa budú zobrazovať nedávne a zavreté bubliny"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tieto upozornenia sa nedajú upraviť."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Túto skupinu upozornení nejde na tomto mieste konfigurovať"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Približné upozornenie"</string>
@@ -996,25 +994,7 @@
<string name="device_services" msgid="1549944177856658705">"Služby zariadenia"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Klepnutím reštartujete túto aplikáciu a prejdete do režimu celej obrazovky."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Nastavenia bublín aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Rozšírená ponuka"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Pridať späť do zásobníka"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Spravovať"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikácie <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikácie <xliff:g id="APP_NAME">%2$s</xliff:g> a ďalšie (<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>)"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Presunúť"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Presunúť doľava nahor"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Presunúť doprava nahor"</string>
- <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="1314082410868930066">"Zavrieť bublinu"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nezobrazovať konverzáciu ako bublinu"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Čet pomocou bublín"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nové konverzácie sa zobrazujú ako plávajúce ikony či bubliny. Bublinu otvoríte klepnutím. Premiestnite ju presunutím."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Nastavenie bublín môžete kedykoľvek zmeniť"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bubliny pre túto aplikáciu môžete vypnúť klepnutím na Spravovať"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Dobre"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Nastavenia aplikácie <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1106,8 +1086,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Spárovať nové zariadenie"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Číslo zostavy"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Číslo zostavy bolo skopírované do schránky."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pri čítaní meradla batérie sa vyskytol problém"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Klepnutím si zobrazíte ďalšie informácie"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings_tv.xml b/packages/SystemUI/res/values-sk/strings_tv.xml
index b52dada595c7..3b8fcc836c66 100644
--- a/packages/SystemUI/res/values-sk/strings_tv.xml
+++ b/packages/SystemUI/res/values-sk/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofón je aktívny"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Aplikácia %1$s použila váš mikrofón"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"Sieť VPN je pripojená"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Sieť VPN je odpojená"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Cez: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index f459bc864605..5828d659efb4 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Poskusite znova ustvariti posnetek zaslona"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Shranjevanje posnetka zaslona ni mogoče zaradi omejenega prostora za shranjevanje"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Aplikacija ali vaša organizacija ne dovoljuje posnetkov zaslona"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Urejanje posnetka zaslona"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Opusti posnetek zaslona"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Uredi"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Urejanje posnetka zaslona"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Drseče pomikanje"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Drseče pomikanje po posnetku zaslona"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Opusti posnetek zaslona"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Predogled posnetka zaslona"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Snemalnik zaslona"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obdelava videoposnetka zaslona"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterija z dvema črticama."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterija s tremi črticami."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Baterija je polna."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Neznan odstotek napolnjenosti baterije."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ni telefona."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon z eno črtico."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon z dvema črticama."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Obvestilo je bilo odstranjeno."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Oblaček je bil opuščen."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Zaslon z obvestili."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hitre nastavitve."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Zaklenjen zaslon"</string>
@@ -720,7 +721,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Želite, da so obvestila te aplikacije še naprej prikazana?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Tiho"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Privzeto"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Mehurček"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Samodejno"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Brez zvočnega opozarjanja ali vibriranja"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Brez zvočnega opozarjanja ali vibriranja, prikaz nižje v razdelku s pogovorom"</string>
@@ -732,8 +732,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavitve"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prednost"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira pogovornih funkcij"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ni nedavnih oblačkov"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Tukaj bodo prikazani tako nedavni kot tudi opuščeni oblački"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Za ta obvestila ni mogoče spremeniti nastavitev."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Te skupine obvestil ni mogoče konfigurirati tukaj"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Posredovano obvestilo"</string>
@@ -996,25 +994,7 @@
<string name="device_services" msgid="1549944177856658705">"Storitve naprave"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Brez naslova"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Dotaknite se za vnovični zagon te aplikacije in preklop v celozaslonski način."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Nastavitve za oblačke aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Prelivanje"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Dodaj nazaj v sklad"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Upravljanje"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g> in toliko drugih: <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Premakni"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Premakni zgoraj levo"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premakni zgoraj desno"</string>
- <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="1314082410868930066">"Opusti oblaček"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Pogovora ne prikaži v oblačku"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Klepet z oblački"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi pogovori so prikazani kot lebdeče ikone ali oblački. Če želite odpreti oblaček, se ga dotaknite. Če ga želite premakniti, ga povlecite."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Upravljanje oblačkov"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dotaknite se »Upravljanje«, da izklopite oblačke iz te aplikacije"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Razumem"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Nastavitve za <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1106,8 +1086,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Seznanitev nove naprave"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Delovna različica"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Delovna različica je bila kopirana v odložišče."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Težava z branjem indikatorja stanja napolnjenosti baterije"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Dotaknite se za več informacij"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings_tv.xml b/packages/SystemUI/res/values-sl/strings_tv.xml
index 109d797ebcf9..af5d75db1a56 100644
--- a/packages/SystemUI/res/values-sl/strings_tv.xml
+++ b/packages/SystemUI/res/values-sl/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon je aktiven"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacija %1$s je dostopala do mikrofona"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"Povezava z navideznim zasebnim omrežjem je vzpostavljena"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Povezava z navideznim zasebnim omrežjem je prekinjena"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prek storitve <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 73408cee8321..297ebc6e6a3c 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Provo ta nxjerrësh përsëri pamjen e ekranit"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Pamja e ekranit nuk mund të ruhet për shkak të hapësirës ruajtëse të kufizuar"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Nxjerrja e pamjeve të ekranit nuk lejohet nga aplikacioni ose organizata jote."</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Modifiko pamjen e ekranit"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Hiq pamjen e ekranit"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Modifiko"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Modifiko pamjen e ekranit"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Lëviz"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Lëviz në pamjen e ekranit"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Hiq pamjen e ekranit"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Pamja paraprake e imazhit"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Regjistruesi i ekranit"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Regjistrimi i ekranit po përpunohet"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Bateria ka edhe dy vija."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Bateria ka edhe tre vija."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Bateria u mbush."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Përqindja e baterisë e panjohur."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Nuk ka telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefoni ka edhe një vijë."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefoni ka dy vija."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Njoftimi është hequr."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Flluska u hoq."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Streha e njoftimeve."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Cilësimet e shpejta."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Ekrani i kyçjes."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Do të vazhdosh t\'i shfaqësh njoftimet nga ky aplikacion?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Në heshtje"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"E parazgjedhur"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Flluskë"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatike"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Asnjë tingull ose dridhje"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Asnjë tingull ose dridhje dhe shfaqet më poshtë në seksionin e bisedave"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cilësimet"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Përparësia"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet veçoritë e bisedës"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nuk ka flluska të fundit"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Flluskat e fundit dhe flluskat e hequra do të shfaqen këtu"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Këto njoftime nuk mund të modifikohen."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ky grup njoftimesh nuk mund të konfigurohet këtu"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Njoftim i dërguar me përfaqësues"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Shërbimet e pajisjes"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Pa titull"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Trokit për ta rinisur këtë aplikacion dhe për të kaluar në ekranin e plotë."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Cilësimet për flluskat e <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Tejkalo"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Shto përsëri te stiva"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Menaxho"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> nga <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> nga <xliff:g id="APP_NAME">%2$s</xliff:g> dhe <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> të tjera"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Zhvendos"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Zhvendos lart majtas"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Lëviz lart djathtas"</string>
- <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="1314082410868930066">"Hiqe flluskën"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Mos e vendos bisedën në flluskë"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bisedo duke përdorur flluskat"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Bisedat e reja shfaqen si ikona pluskuese ose flluska. Trokit për të hapur flluskën. Zvarrit për ta zhvendosur."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrollo flluskat në çdo moment"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Trokit \"Menaxho\" për të çaktivizuar flluskat nga ky aplikacion"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"E kuptova"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Cilësimet e <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Çifto pajisjen e re"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numri i ndërtimit"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Numri i ndërtimit u kopjua te kujtesa e fragmenteve"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Problem me leximin e matësit të baterisë"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Trokit për më shumë informacione"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings_tv.xml b/packages/SystemUI/res/values-sq/strings_tv.xml
index 6cecdb6e38f4..713130f30879 100644
--- a/packages/SystemUI/res/values-sq/strings_tv.xml
+++ b/packages/SystemUI/res/values-sq/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofoni aktiv"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s pati qasje te mikrofoni yt"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN-ja është e lidhur"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN-ja është shkëputur"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Nëpërmjet <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index d173f007bd2b..f9262b0e48be 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Пробајте да поново направите снимак екрана"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Чување снимка екрана није успело због ограниченог меморијског простора"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Апликација или организација не дозвољавају прављење снимака екрана"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Измените снимак екрана"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Одбаците снимак екрана"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Измени"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Измените снимак екрана"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Померај"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Померајте снимак екрана"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Одбаците снимак екрана"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Преглед снимка екрана"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Снимач екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обрађујемо видео снимка екрана"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Батерија од две црте."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Батерија од три црте."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Батерија је пуна."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Проценат напуњености батерије није познат."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Нема телефона."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Сигнал телефона има једну црту."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Сигнал телефона од две црте."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Обавештење је одбачено."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Облачић је одбачен."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Прозор са обавештењима."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Брза подешавања."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Закључан екран."</string>
@@ -717,7 +718,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Желите ли да се обавештења из ове апликације и даље приказују?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Нечујно"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Подразумевано"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Облачић"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Аутоматска"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звука и вибрирања"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звука и вибрирања и приказује се у наставку одељка за конверзације"</string>
@@ -729,8 +729,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Подешавања"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава функције конверзације"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нема недавних облачића"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Овде се приказују недавни и одбачени облачићи"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ова обавештења не могу да се мењају."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ова група обавештења не може да се конфигурише овде"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Обавештење преко проксија"</string>
@@ -991,25 +989,7 @@
<string name="device_services" msgid="1549944177856658705">"Услуге за уређаје"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслова"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Додирните да бисте рестартовали апликацију и прешли у режим целог екрана."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Подешавања за <xliff:g id="APP_NAME">%1$s</xliff:g> облачиће"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Преклапање"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Додај поново у групу"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Управљајте"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> из апликације <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> из апликације <xliff:g id="APP_NAME">%2$s</xliff:g> и још <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Премести"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Премести горе лево"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Премести горе десно"</string>
- <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="1314082410868930066">"Одбаци облачић"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не користи облачиће за конверзацију"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ћаскајте у облачићима"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Нове конверзације се приказују као плутајуће иконе или облачићи. Додирните да бисте отворили облачић. Превуците да бисте га преместили."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Контролишите облачиће у било ком тренутку"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Додирните Управљајте да бисте искључили облачиће из ове апликације"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Важи"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Подешавања за <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1100,8 +1080,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Упари нови уређај"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Број верзије"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Број верзије је копиран у привремену меморију."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Проблем са очитавањем мерача батерије"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Додирните за више информација"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings_tv.xml b/packages/SystemUI/res/values-sr/strings_tv.xml
index 322938f4f787..77f842c5d1fd 100644
--- a/packages/SystemUI/res/values-sr/strings_tv.xml
+++ b/packages/SystemUI/res/values-sr/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Микрофон је активан"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Апликација %1$s је приступила микрофону"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN је повезан"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Веза са VPN-ом је прекинута"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Преко: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index b79fb40e2324..3401294139da 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Testa att ta en skärmdump igen"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Det går inte att spara skärmdumpen eftersom lagringsutrymmet inte räcker"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Appen eller organisationen tillåter inte att du tar skärmdumpar"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Redigera skärmdump"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Stäng skärmdump"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Redigera"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Redigera skärmdump"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Scrolla"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Rullande skärmdump"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Stäng skärmdump"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Förhandsgranskning av skärmdump"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Skärminspelare"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Behandlar skärminspelning"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batteri: två staplar."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batteri: tre staplar."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batteriet är fulladdat."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Okänd batterinivå."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ingen telefon."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon: en stapel."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon: två staplar."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Meddelandet ignorerades."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubblan ignorerades."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Meddelandepanel."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Snabbinställningar."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Låsskärm."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Vill du fortsätta visa aviseringar för den här appen?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Tyst"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standard"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bubbla"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatiskt"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Inga ljud eller vibrationer"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Inga ljud eller vibrationer och visas längre ned bland konversationerna"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Inställningar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsfunktioner"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Inga nya bubblor"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"De senaste bubblorna och ignorerade bubblor visas här"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Det går inte att ändra de här aviseringarna."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Den här aviseringsgruppen kan inte konfigureras här"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Avisering via proxy"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Enhetstjänster"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Tryck för att starta om appen i helskärmsläge."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Inställningar för <xliff:g id="APP_NAME">%1$s</xliff:g>-bubblor"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Fler menyalternativ"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Lägg tillbaka på stack"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Hantera"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> från <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> från <xliff:g id="APP_NAME">%2$s</xliff:g> och <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> fler"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Flytta"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Flytta högst upp till vänster"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flytta högst upp till höger"</string>
- <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="1314082410868930066">"Stäng bubbla"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Visa inte konversationen i bubblor"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatta med bubblor"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nya konversationer visas som flytande ikoner, så kallade bubblor. Tryck på bubblan om du vill öppna den. Dra den om du vill flytta den."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Styr bubblor när som helst"</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="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Inställningar för <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Parkoppla en ny enhet"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Versionsnummer"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Versionsnumret har kopierats till urklipp."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batteriindikatorn visas inte"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Tryck för mer information"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml
index fb28af449fb7..141aabf207aa 100644
--- a/packages/SystemUI/res/values-sv/strings_tv.xml
+++ b/packages/SystemUI/res/values-sv/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofonen är aktiv"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s har fått åtkomst till mikrofonen"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN är anslutet"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN är frånkopplat"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 2e4c91df087e..4cf09c775c20 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Jaribu kupiga picha ya skrini tena"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Imeshindwa kuhifadhi picha ya skrini kwa sababu nafasi haitoshi"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Programu au shirika lako halikuruhusu kupiga picha za skrini"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Badilisha picha ya skrini"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ondoa picha ya skrini"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Badilisha"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Badilisha picha ya skrini"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Fanya iwe ndefu"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Fanya picha ya skrini iwe ndefu"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ondoa picha ya skrini"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Onyesho la kukagua picha ya skrini"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Kinasa Skrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Inachakata rekodi ya skrini"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Pau mbili za betri"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Pau tatu za betri."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Betri imejaa."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Asilimia ya betri haijulikani."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Hakuna simu"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Mwambaa mmoja wa simu."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Miambaa miwili ya simu"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Arifa imetupwa."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Umeondoa kiputo."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Kivuli cha arifa."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Mipangilio ya haraka."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Skrini iliyofungwa."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Ungependa kuendelea kuonyesha arifa kutoka programu hii?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Kimya"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Chaguomsingi"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Kiputo"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatiki"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Hakuna sauti wala mtetemo"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Hakuna sauti wala mtetemo na huonekana upande wa chini katika sehemu ya mazungumzo"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Mipangilio"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Kipaumbele"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> haitumii vipengele vya mazungumzo"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Hakuna viputo vya hivi majuzi"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Viputo vya hivi karibuni na vile vilivyoondolewa vitaonekana hapa"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Arifa hizi haziwezi kubadilishwa."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Kikundi hiki cha arifa hakiwezi kuwekewa mipangilio hapa"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Arifa wakilishi"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Huduma za Kifaa"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Wimbo hauna jina"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Gusa ili uzime na uwashe upya programu hii kisha nenda kwenye skrini nzima."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Mipangilio ya viputo vya <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Vipengee vya ziada"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Rejesha kwenye rafu"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Dhibiti"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kutoka kwa <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kutoka kwa <xliff:g id="APP_NAME">%2$s</xliff:g> na nyingine<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Sogeza"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Sogeza juu kushoto"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sogeza juu kulia"</string>
- <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="1314082410868930066">"Ondoa kiputo"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Usiweke viputo kwenye mazungumzo"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Piga gumzo ukitumia viputo"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Mazungumzo mapya huonekena kama aikoni au viputo vinavyoelea. Gusa ili ufungue kiputo. Buruta ili ukisogeze."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Dhibiti viputo wakati wowote"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Gusa Dhibiti ili uzime viputo kwenye programu hii"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Nimeelewa"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Mipangilio ya <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Oanisha kifaa kipya"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nambari ya muundo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nambari ya muundo imewekwa kwenye ubao wa kunakili."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Tatizo la kusoma mita ya betri yako"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Gusa ili upate maelezo zaidi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings_tv.xml b/packages/SystemUI/res/values-sw/strings_tv.xml
index b51f93410bb4..9dd37ce63bb3 100644
--- a/packages/SystemUI/res/values-sw/strings_tv.xml
+++ b/packages/SystemUI/res/values-sw/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Maikrofoni Inatumika"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s imefikia maikrofoni yako"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN imeunganishwa"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN imeondolewa"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Kupitia <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 97240d9eb8dd..5d29c91998bf 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ஸ்கிரீன் ஷாட்டை மீண்டும் எடுக்க முயலவும்"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"போதுமான சேமிப்பிடம் இல்லாததால் ஸ்கிரீன்ஷாட்டைச் சேமிக்க முடியவில்லை"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ஸ்கிரீன் ஷாட்டுகளை எடுப்பதை, ஆப்ஸ் அல்லது உங்கள் நிறுவனம் அனுமதிக்கவில்லை"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"ஸ்கிரீன்ஷாட்டைத் திருத்தும்"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ஸ்கிரீன்ஷாட்டை நிராகரி"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"திருத்து"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"ஸ்கிரீன்ஷாட்டைத் திருத்தும்"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"ஸ்க்ரோல்"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"ஸ்கிரீன்ஷாட்டைப் பெரிதாக்கும்"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ஸ்கிரீன்ஷாட்டை நிராகரிக்கும்"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ஸ்கிரீன்ஷாட்டின் மாதிரிக்காட்சி"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"ஸ்கிரீன் ரெக்கார்டர்"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ஸ்க்ரீன் ரெக்கார்டிங் செயலாக்கப்படுகிறது"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"பேட்டரி சக்தி இரண்டு பார் அளவில் உள்ளது."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"பேட்டரி சக்தி மூன்று பார் அளவில் உள்ளது."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"பேட்டரி முழுமையாக உள்ளது."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"பேட்டரி சதவீதம் தெரியவில்லை."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"சிக்னல் இல்லை."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"சிக்னல் ஒரு கோட்டில் உள்ளது."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"சிக்னல் இரண்டு கோட்டில் உள்ளது."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"அறிவிப்பு நிராகரிக்கப்பட்டது."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"குமிழ் நிராகரிக்கப்பட்டது."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"அறிவிப்பு விவரம்."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"உடனடி அமைப்பு."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"லாக் ஸ்கிரீன்."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"இந்த ஆப்ஸின் அறிவிப்புகளைத் தொடர்ந்து காட்டவா?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"நிசப்தம்"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"இயல்புநிலை"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"பபிள்"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"தானியங்கு"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ஒலி / அதிர்வு இல்லை"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ஒலி / அதிர்வு இல்லாமல் உரையாடல் பிரிவின் கீழ்ப் பகுதியில் தோன்றும்"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"அமைப்புகள்"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"முன்னுரிமை"</string>
<string name="no_shortcut" msgid="8257177117568230126">"உரையாடல் அம்சங்களை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"சமீபத்திய குமிழ்கள் இல்லை"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"சமீபத்திய குமிழ்களும் நிராகரிக்கப்பட்ட குமிழ்களும் இங்கே தோன்றும்"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"இந்த அறிவுப்புக் குழுக்களை இங்கே உள்ளமைக்க இயலாது"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ப்ராக்ஸியான அறிவிப்பு"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"சாதன சேவைகள்"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"தலைப்பு இல்லை"</string>
<string name="restart_button_description" msgid="6916116576177456480">"தட்டுவதன் மூலம் இந்த ஆப்ஸை மீண்டும் தொடங்கலாம், முழுத்திரையில் பார்க்கலாம்."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> குமிழ்களுக்கான அமைப்புகள்"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ஓவர்ஃப்லோ"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"மீண்டும் ஸ்டேக்கில் சேர்க்கவும்"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"நிர்வகி"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> இலிருந்து <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> மற்றும் மேலும் <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ஆப்ஸிலிருந்து வந்துள்ள அறிவிப்பு: <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"நகர்த்து"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"மேலே இடப்புறமாக நகர்த்து"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"மேலே வலப்புறமாக நகர்த்து"</string>
- <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="1314082410868930066">"குமிழை அகற்று"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"உரையாடலைக் குமிழாக்காதே"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"குமிழ்களைப் பயன்படுத்தி அரட்டையடியுங்கள்"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"புதிய உரையாடல்கள் மிதக்கும் ஐகான்களாகவோ குமிழ்களாகவோ தோன்றும். குமிழைத் திறக்க தட்டவும். நகர்த்த இழுக்கவும்."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"குமிழ்களை எப்போது வேண்டுமானாலும் கட்டுப்படுத்தலாம்"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"இந்த ஆப்ஸிலிருந்து வரும் குமிழ்களை முடக்க, நிர்வகி என்பதைத் தட்டவும்"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"சரி"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> அமைப்புகள்"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"புதிய சாதனத்தை இணைத்தல்"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"பதிப்பு எண்"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"பதிப்பு எண் கிளிப்போர்டுக்கு நகலெடுக்கப்பட்டது."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"பேட்டரி அளவை அறிவதில் சிக்கல்"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"மேலும் தகவல்களுக்கு தட்டவும்"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings_tv.xml b/packages/SystemUI/res/values-ta/strings_tv.xml
index 1ae3d1d3bdcd..04832016cf67 100644
--- a/packages/SystemUI/res/values-ta/strings_tv.xml
+++ b/packages/SystemUI/res/values-ta/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"மைக்ரோஃபோன் செயலிலுள்ளது"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s உங்கள் மைக்ரோஃபோனைப் பயன்படுத்தியது"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN இணைக்கப்பட்டது"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN துண்டிக்கப்பட்டது"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> வழியாக"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 7100c3307047..5fed052d9f5b 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"స్క్రీన్‌షాట్ తీయడానికి మళ్లీ ప్రయత్నించండి"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"నిల్వ స్థలం పరిమితంగా ఉన్న కారణంగా స్క్రీన్‌షాట్‌ను సేవ్ చేయడం సాధ్యపడదు"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"స్క్రీన్‌షాట్‌లు తీయడానికి యాప్ లేదా మీ సంస్థ అనుమతించలేదు"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"స్క్రీన్‌షాట్‌ను ఎడిట్ చేస్తుంది"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"స్క్రీన్‌షాట్‌ను మూసివేస్తుంది"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"ఎడిట్ చేయండి"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"స్క్రీన్‌షాట్‌ను ఎడిట్ చేయండి"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"స్క్రోల్ చేయి"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"స్క్రీన్‌షాట్‌కు స్క్రోల్ చేయండి"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"స్క్రీన్‌షాట్‌ను విస్మరించు"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"స్క్రీన్‌షాట్ ప్రివ్యూ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"స్క్రీన్ రికార్డర్"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"స్క్రీన్ రికార్డింగ్ అవుతోంది"</string>
@@ -120,7 +123,7 @@
<string name="installer_cd_button_title" msgid="5499998592841984743">"Macకు Android ఫైల్ బదిలీ యాప్ ఇన్‌స్టాల్ చేయండి"</string>
<string name="accessibility_back" msgid="6530104400086152611">"వెనుకకు"</string>
<string name="accessibility_home" msgid="5430449841237966217">"హోమ్"</string>
- <string name="accessibility_menu" msgid="2701163794470513040">"మెను"</string>
+ <string name="accessibility_menu" msgid="2701163794470513040">"మెనూ"</string>
<string name="accessibility_accessibility_button" msgid="4089042473497107709">"యాక్సెస్ సామర్థ్యం"</string>
<string name="accessibility_rotate_button" msgid="1238584767612362586">"స్క్రీన్‌ను తిప్పండి"</string>
<string name="accessibility_recent" msgid="901641734769533575">"ఓవర్‌వ్యూ"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"బ్యాటరీ రెండు బార్లు."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"బ్యాటరీ మూడు బార్లు."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"బ్యాటరీ నిండింది."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"బ్యాటరీ శాతం తెలియదు."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"ఫోన్ లేదు."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"ఫోన్ ఒక బారు."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"ఫోన్ రెండు బార్లు."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"నోటిఫికేషన్ తీసివేయబడింది."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"బబుల్ విస్మరించబడింది."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"నోటిఫికేషన్ షేడ్."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"శీఘ్ర సెట్టింగ్‌లు."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"లాక్ స్క్రీన్."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"ఈ యాప్ నుండి నోటిఫికేషన్‌లను చూపిస్తూ ఉండాలా?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"నిశ్శబ్దం"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ఆటోమేటిక్ సెట్టింగ్"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"బబుల్"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"ఆటోమేటిక్"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"శబ్దం లేదా వైబ్రేషన్‌లు ఏవీ లేవు"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"శబ్దం లేదా వైబ్రేషన్ లేదు, సంభాషణ విభాగం దిగువన కనిపిస్తుంది"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"సెట్టింగ్‌లు"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> సంభాషణ ఫీచర్‌లను సపోర్ట్ చేయదు"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ఇటీవలి బబుల్స్ ఏవీ లేవు"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ఇటీవలి బబుల్స్ మరియు తీసివేసిన బబుల్స్ ఇక్కడ కనిపిస్తాయి"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ఈ నోటిఫికేషన్‌లను సవరించడం వీలుపడదు."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"ఈ నోటిఫికేషన్‌ల సమూహాన్ని ఇక్కడ కాన్ఫిగర్ చేయలేము"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ప్రాక్సీ చేయబడిన నోటిఫికేషన్"</string>
@@ -929,7 +927,7 @@
<string name="tuner_minus" msgid="5258518368944598545">"తీసివేత చిహ్నం"</string>
<string name="tuner_left" msgid="5758862558405684490">"ఎడమ"</string>
<string name="tuner_right" msgid="8247571132790812149">"కుడి"</string>
- <string name="tuner_menu" msgid="363690665924769420">"మెను"</string>
+ <string name="tuner_menu" msgid="363690665924769420">"మెనూ"</string>
<string name="tuner_app" msgid="6949280415826686972">"<xliff:g id="APP">%1$s</xliff:g> అనురవర్తనం"</string>
<string name="notification_channel_alerts" msgid="3385787053375150046">"హెచ్చరికలు"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"బ్యాటరీ"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"పరికర సేవలు"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"శీర్షిక లేదు"</string>
<string name="restart_button_description" msgid="6916116576177456480">"ఈ యాప్‌ను పునఃప్రారంభించేలా నొక్కి, ఆపై పూర్తి స్క్రీన్‌‍లోకి వెళ్లండి."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> బబుల్స్ సెట్టింగ్‌లు"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"ఓవర్‌ఫ్లో"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"స్ట్యాక్‌కు తిరిగి జోడించండి"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"మేనేజ్ చేయండి"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> మరియు మరో <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"తరలించు"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ఎగువ ఎడమవైపునకు జరుపు"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ఎగువ కుడివైపునకు జరుపు"</string>
- <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="1314082410868930066">"బబుల్‌ను విస్మరించు"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"సంభాషణను బబుల్ చేయవద్దు"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"బబుల్స్‌ను ఉపయోగించి చాట్ చేయండి"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"కొత్త సంభాషణలు తేలియాడే చిహ్నాలుగా లేదా బబుల్స్ లాగా కనిపిస్తాయి. బబుల్‌ని తెరవడానికి నొక్కండి. తరలించడానికి లాగండి."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"బబుల్స్‌ను ఎప్పుడైనా నియంత్రించండి"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ఈ యాప్ నుండి వచ్చే బబుల్స్‌ను ఆఫ్ చేయడానికి మేనేజ్ బటన్‌ను ట్యాప్ చేయండి"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"అర్థమైంది"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> సెట్టింగ్‌లు"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"బిల్డ్ నంబర్"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"బిల్డ్ నంబర్, క్లిప్‌బోర్డ్‌కు కాపీ చేయబడింది."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"మీ బ్యాటరీ మీటర్‌ను చదవడంలో సమస్య"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"మరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings_tv.xml b/packages/SystemUI/res/values-te/strings_tv.xml
index 27911795d771..67fb678466cb 100644
--- a/packages/SystemUI/res/values-te/strings_tv.xml
+++ b/packages/SystemUI/res/values-te/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"మైక్రోఫోన్ యాక్టివ్‌గా ఉంది"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"మీ మైక్రోఫోన్‌ను %1$s యాక్సెస్ చేసింది"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN కనెక్ట్ చేయబడింది"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN డిస్‌కనెక్ట్ చేయబడింది"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> ద్వారా"</string>
</resources>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 015ac90e2521..cebe1e83ceed 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -30,6 +30,7 @@
<item>com.android.systemui.volume.VolumeUI</item>
<item>com.android.systemui.statusbar.tv.TvStatusBar</item>
<item>com.android.systemui.statusbar.tv.TvNotificationPanel</item>
+ <item>com.android.systemui.statusbar.tv.VpnStatusObserver</item>
<item>com.android.systemui.usb.StorageNotification</item>
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 8db84b8d1e67..ffa84d3531ee 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ลองบันทึกภาพหน้าจออีกครั้ง"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"บันทึกภาพหน้าจอไม่ได้เนื่องจากพื้นที่เก็บข้อมูลมีจำกัด"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"แอปหรือองค์กรของคุณไม่อนุญาตให้จับภาพหน้าจอ"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"แก้ไขภาพหน้าจอ"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"ปิดภาพหน้าจอ"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"แก้ไข"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"แก้ไขภาพหน้าจอ"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"เลื่อน"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"เลื่อนจับภาพหน้าจอ"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"ปิดภาพหน้าจอ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ตัวอย่างภาพหน้าจอ"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"โปรแกรมอัดหน้าจอ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"กำลังประมวลผลการอัดหน้าจอ"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"แบตเตอรี่สองขีด"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"แบตเตอรี่สามขีด"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"แบตเตอรี่เต็ม"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"ไม่ทราบเปอร์เซ็นต์แบตเตอรี่"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"ไม่มีสัญญาณโทรศัพท์"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"สัญญาณโทรศัพท์หนึ่งขีด"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"สัญญาณโทรศัพท์สองขีด"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ปิดการแจ้งเตือนแล้ว"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"ปิดบับเบิลแล้ว"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"หน้าต่างแจ้งเตือน"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"การตั้งค่าด่วน"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ล็อกหน้าจอ"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"แสดงการแจ้งเตือนจากแอปนี้ต่อไปไหม"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"ปิดเสียง"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ค่าเริ่มต้น"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"บับเบิล"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"อัตโนมัติ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ไม่มีเสียงหรือการสั่น"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ไม่มีเสียงหรือการสั่น และปรากฏต่ำลงมาในส่วนการสนทนา"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"การตั้งค่า"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ลำดับความสำคัญ"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่รองรับฟีเจอร์การสนทนา"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ไม่มีบับเบิลเมื่อเร็วๆ นี้"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"บับเบิลที่แสดงและที่ปิดไปเมื่อเร็วๆ นี้จะปรากฏที่นี่"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"แก้ไขการแจ้งเตือนเหล่านี้ไม่ได้"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"การแจ้งเตือนกลุ่มนี้กำหนดค่าที่นี่ไม่ได้"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"การแจ้งเตือนที่ผ่านพร็อกซี"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"บริการของอุปกรณ์"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ไม่มีชื่อ"</string>
<string name="restart_button_description" msgid="6916116576177456480">"แตะเพื่อรีสตาร์ทแอปนี้และแสดงแบบเต็มหน้าจอ"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"การตั้งค่าบับเบิล <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"รายการเพิ่มเติม"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"เพิ่มกลับไปที่สแต็ก"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"จัดการ"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g> และอีก <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> รายการ"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"ย้าย"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"ย้ายไปด้านซ้ายบน"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ย้ายไปด้านขวาบน"</string>
- <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="1314082410868930066">"ปิดบับเบิล"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ไม่ต้องแสดงการสนทนาเป็นบับเบิล"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"แชทโดยใช้บับเบิล"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"การสนทนาใหม่ๆ จะปรากฏเป็นไอคอนแบบลอยหรือบับเบิล แตะเพื่อเปิดบับเบิล ลากเพื่อย้ายที่"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ควบคุมบับเบิลได้ทุกเมื่อ"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"แตะ \"จัดการ\" เพื่อปิดบับเบิลจากแอปนี้"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"รับทราบ"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"การตั้งค่า <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1092,10 +1072,8 @@
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (ยกเลิกการเชื่อมต่อแล้ว)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"เชื่อมต่อไม่ได้ ลองใหม่"</string>
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"จับคู่อุปกรณ์ใหม่"</string>
- <string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิวด์"</string>
- <string name="build_number_copy_toast" msgid="877720921605503046">"คัดลอกหมายเลขบิวด์ไปยังคลิปบอร์ดแล้ว"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="build_number_clip_data_label" msgid="3623176728412560914">"หมายเลขบิลด์"</string>
+ <string name="build_number_copy_toast" msgid="877720921605503046">"คัดลอกหมายเลขบิลด์ไปยังคลิปบอร์ดแล้ว"</string>
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"พบปัญหาในการอ่านเครื่องวัดแบตเตอรี่"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"แตะดูข้อมูลเพิ่มเติม"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings_tv.xml b/packages/SystemUI/res/values-th/strings_tv.xml
index 783b1f47ca7a..4a9144b227fa 100644
--- a/packages/SystemUI/res/values-th/strings_tv.xml
+++ b/packages/SystemUI/res/values-th/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"ไมโครโฟนเปิดใช้งานอยู่"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s เข้าถึงไมโครโฟนแล้ว"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"เชื่อมต่อ VPN แล้ว"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"ยกเลิกการเชื่อมต่อ VPN แล้ว"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"ผ่าน <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 09f8a71167b3..b8cdef1979ad 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -28,15 +28,15 @@
<string name="battery_low_percent_format" msgid="4276661262843170964">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira"</string>
<string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> na lang ang natitira, humigit-kumulang <xliff:g id="TIME">%2$s</xliff:g> ang natitira batay sa iyong paggamit"</string>
<string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> na lang ang natitira, humigit-kumulang <xliff:g id="TIME">%2$s</xliff:g> ang natitira"</string>
- <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira. Naka-on ang Pangtipid sa Baterya."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"<xliff:g id="PERCENTAGE">%s</xliff:g> na lang ang natitira. Naka-on ang Pantipid ng Baterya."</string>
<string name="invalid_charger" msgid="4370074072117767416">"Hindi makapag-charge sa pamamagitan ng USB. Gamitin ang charger na kasama ng iyong device."</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Hindi makapag-charge sa pamamagitan ng USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Gamitin ang charger na kasama ng iyong device"</string>
<string name="battery_low_why" msgid="2056750982959359863">"Mga Setting"</string>
- <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"I-on ang Pangtipid sa Baterya?"</string>
- <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tungkol sa Pangtipid sa Baterya"</string>
+ <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"I-on ang Pantipid ng Baterya?"</string>
+ <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Tungkol sa Pantipid ng Baterya"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"I-on"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"I-on ang Pangtipid sa Baterya"</string>
+ <string name="battery_saver_start_action" msgid="4553256017945469937">"I-on ang Pantipid ng Baterya"</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"Mga Setting"</string>
<string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"I-auto rotate ang screen"</string>
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Subukang kumuhang muli ng screenshot"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Hindi ma-save ang screenshot dahil sa limitadong espasyo ng storage"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Hindi pinahihintulutan ng app o ng iyong organisasyon ang pagkuha ng mga screenshot"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"I-edit ang screenshot"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"I-dismiss ang screenshot"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"I-edit"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"I-edit ang screenshot"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Mag-scroll"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"I-scroll ang screenshot"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"I-dismiss ang screenshot"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Preview ng screenshot"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Recorder ng Screen"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pinoproseso screen recording"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Baterya na dalawang bar."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Baterya na tatlong bar."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Puno na ang baterya."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Hindi alam ang porsyento ng baterya."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Walang telepono."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telepono na isang bar."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telepono na dalawang bar."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Na-dismiss ang notification."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Na-dismiss na ang bubble."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Notification shade."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Mga mabilisang setting."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Lock screen."</string>
@@ -422,7 +423,7 @@
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Mao-on sa ganap na <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"Hanggang <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Madilim na tema"</string>
- <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Pangtipid sa Baterya"</string>
+ <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Pantipid ng Baterya"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Mao-on sa sunset"</string>
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Hanggang sunrise"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Ma-o-on nang <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -500,9 +501,9 @@
<string name="user_remove_user_title" msgid="9124124694835811874">"Gusto mo bang alisin ang user?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Made-delete ang lahat ng app at data ng user na ito."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Alisin"</string>
- <string name="battery_saver_notification_title" msgid="8419266546034372562">"Naka-on ang Pangtipid sa Baterya"</string>
+ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Naka-on ang Pantipid ng Baterya"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"Binabawasan ang performance at data sa background"</string>
- <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"I-off ang Pangtipid sa Baterya"</string>
+ <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"I-off ang Pantipid ng Baterya"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"Magkakaroon ng access ang <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sa lahat ng impormasyong nakikita sa iyong screen o pine-play mula sa device mo habang nagre-record o nagka-cast. Kasama rito ang impormasyong tulad ng mga password, detalye ng pagbabayad, larawan, mensahe, at audio na pine-play mo."</string>
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"Ang serbisyong nagbibigay ng function na ito ay magkakaroon ng access sa lahat ng impormasyong nakikita sa iyong screen o pine-play mula sa device mo habang nagre-record o nagka-cast. Kasama rito ang impormasyong tulad ng mga password, detalye ng pagbabayad, larawan, mensahe, at audio na pine-play mo."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Magsimulang mag-record o mag-cast?"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Patuloy na ipakita ang mga notification mula sa app na ito?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Naka-silent"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Default"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Awtomatiko"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Walang tunog o pag-vibrate"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Walang tunog o pag-vibrate at lumalabas nang mas mababa sa seksyon ng pag-uusap"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Mga Setting"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priyoridad"</string>
<string name="no_shortcut" msgid="8257177117568230126">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang mga feature ng pag-uusap"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Walang kamakailang bubble"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Lalabas dito ang mga kamakailang bubble at na-dismiss na bubble"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Hindi puwedeng baguhin ang mga notification na ito."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Hindi mako-configure dito ang pangkat na ito ng mga notification"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Na-proxy na notification"</string>
@@ -779,8 +777,8 @@
<item quantity="other">%d na minuto</item>
</plurals>
<string name="battery_panel_title" msgid="5931157246673665963">"Paggamit ng baterya"</string>
- <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Hindi available ang Pangtipid sa Baterya kapag nagcha-charge"</string>
- <string name="battery_detail_switch_title" msgid="6940976502957380405">"Pangtipid sa Baterya"</string>
+ <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Hindi available ang Pantipid ng Baterya kapag nagcha-charge"</string>
+ <string name="battery_detail_switch_title" msgid="6940976502957380405">"Pantipid ng Baterya"</string>
<string name="battery_detail_switch_summary" msgid="3668748557848025990">"Binabawasan ang performance at data sa background"</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Button na <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"Home"</string>
@@ -967,11 +965,11 @@
<string name="slice_permission_checkbox" msgid="4242888137592298523">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na ipakita ang mga slice mula sa anumang app"</string>
<string name="slice_permission_allow" msgid="6340449521277951123">"Payagan"</string>
<string name="slice_permission_deny" msgid="6870256451658176895">"Tanggihan"</string>
- <string name="auto_saver_title" msgid="6873691178754086596">"I-tap para iiskedyul ang Pangtipid sa Baterya"</string>
+ <string name="auto_saver_title" msgid="6873691178754086596">"I-tap para iiskedyul ang Pantipid ng Baterya"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"I-on kapag malamang na maubos ang baterya"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Hindi, salamat na lang"</string>
- <string name="auto_saver_enabled_title" msgid="4294726198280286333">"Na-on ang iskedyul ng Pangtipid sa Baterya"</string>
- <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Awtomatikong mao-on ang Pangtipid sa Baterya kapag mas mababa na sa <xliff:g id="PERCENTAGE">%d</xliff:g>%% ang baterya."</string>
+ <string name="auto_saver_enabled_title" msgid="4294726198280286333">"Na-on ang iskedyul ng Pantipid ng Baterya"</string>
+ <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Awtomatikong mao-on ang Pantipid ng Baterya kapag mas mababa na sa <xliff:g id="PERCENTAGE">%d</xliff:g>%% ang baterya."</string>
<string name="open_saver_setting_action" msgid="2111461909782935190">"Mga Setting"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Mga Serbisyo ng Device"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Walang pamagat"</string>
<string name="restart_button_description" msgid="6916116576177456480">"I-tap para i-restart ang app na ito at mag-full screen."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Mga setting para sa mga bubble ng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Overflow"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Idagdag ulit sa stack"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Pamahalaan"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> mula sa <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> mula sa <xliff:g id="APP_NAME">%2$s</xliff:g> at <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> pa"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Ilipat"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Ilipat sa kaliwa sa itaas"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Ilipat sa kanan sa itaas"</string>
- <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="1314082410868930066">"I-dismiss ang bubble"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Huwag ipakita sa bubble ang mga pag-uusap"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Mag-chat gamit ang bubbles"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Lumalabas bilang mga nakalutang na icon o bubble ang mga bagong pag-uusap. I-tap para buksan ang bubble. I-drag para ilipat ito."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrolin ang mga bubble anumang oras"</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="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Mga setting ng <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Magpares ng bagong device"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Numero ng build"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nakopya sa clipboard ang numero ng build."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Nagkaproblema sa pagbabasa ng iyong battery meter"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"I-tap para sa higit pang impormasyon"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings_tv.xml b/packages/SystemUI/res/values-tl/strings_tv.xml
index bf46b8fe599a..3489503652ea 100644
--- a/packages/SystemUI/res/values-tl/strings_tv.xml
+++ b/packages/SystemUI/res/values-tl/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Aktibo ang Mikropono"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Na-access ng %1$s ang iyong mikropono"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"Nakakonekta ang VPN"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Nakadiskonekta ang VPN"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Sa pamamagitan ng <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 89d737410ddb..74666b2ec0c3 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Tekrar ekran görüntüsü almayı deneyin"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Depolama alanı sınırlı olduğundan ekran görüntüsü kaydedilemiyor"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Uygulama veya kuruluşunuz, ekran görüntüsü alınmasına izin vermiyor."</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Ekran görüntüsünü düzenleyin"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Ekran görüntüsünü kapat"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Düzenle"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Ekran görüntüsünü düzenle"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Kaydır"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Kayan ekran görüntüsü"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Ekran görüntüsünü kapat"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ekran görüntüsü önizlemesi"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekran Kaydedicisi"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran kaydı işleniyor"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Pil gücü iki çubuk."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Pil gücü üç çubuk."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Pil tam dolu."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Pil yüzdesi bilinmiyor."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Telefon sinyali yok."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon sinyali bir çubuk."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon sinyali iki çubuk."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Bildirim kapatıldı."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Balon kapatıldı."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bildirim gölgesi."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Hızlı ayarlar."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Kilit ekranı"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Bu uygulamadan gelen bildirimler gösterilmeye devam edilsin mi?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Sessiz"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Varsayılan"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Baloncuk"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sessiz veya titreşim yok"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sessizdir veya titreşim yoktur ve görüşme bölümünün altında görünür"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Öncelik"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>, sohbet özelliklerini desteklemiyor"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Son kapatılan baloncuk yok"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Son baloncuklar ve kapattığınız baloncuklar burada görünür"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirimler değiştirilemez."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Bu bildirim grubu burada yapılandırılamaz"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Proxy uygulanan bildirim"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Cihaz Hizmetleri"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıksız"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Bu uygulamayı yeniden başlatmak ve tam ekrana geçmek için dokunun."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> baloncukları için ayarlar"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Taşma"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Yığına geri ekle"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Yönet"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> uygulamasından <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> uygulamasından <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ve diğer <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Taşı"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Sol üste taşı"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sağ üste taşı"</string>
- <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="1314082410868930066">"Baloncuğu kapat"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Görüşmeyi baloncuk olarak görüntüleme"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Baloncukları kullanarak sohbet edin"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yeni görüşmeler kayan simgeler veya baloncuk olarak görünür. Açmak için baloncuğa dokunun. Baloncuğu taşımak için sürükleyin."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Baloncukları istediğiniz zaman kontrol edin"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu uygulamanın baloncuklarını kapatmak için Yönet\'e dokunun"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Anladım"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ayarları"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yeni cihaz eşle"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Derleme numarası"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Derleme numarası panoya kopyalandı."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Pil ölçeriniz okunurken sorun oluştu"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Daha fazla bilgi için dokunun"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings_tv.xml b/packages/SystemUI/res/values-tr/strings_tv.xml
index 30d1fc9cdb9f..bfb1ae24c890 100644
--- a/packages/SystemUI/res/values-tr/strings_tv.xml
+++ b/packages/SystemUI/res/values-tr/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon Etkin"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s mikrofonunuza erişti"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN bağlandı"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN bağlantısı kesildi"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> yoluyla"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index f1962939622d..2737ce892f71 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Спробуйте зробити знімок екрана ще раз"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Не вдалося зберегти знімок екрана через обмежений обсяг пам’яті"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Додаток або адміністратор вашої організації не дозволяють робити знімки екрана"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Редагувати знімок екрана"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Закрити знімок екрана"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Редагувати"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Редагувати знімок екрана"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Прокрутити"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Прокрутити знімок екрана"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Закрити знімок екрана"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Перегляд знімка екрана"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Відеозапис екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обробка записування екрана"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Заряд акумулятора: дві смужки."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Заряд акумулятора: три смужки."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Акумулятор заряджений."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Відсоток заряду акумулятора невідомий."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Немає сигналу телефону."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Одна смужка сигналу телефону."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Дві смужки сигналу телефону."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Сповіщення відхилено."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Спливаюче сповіщення закрито."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Панель сповіщень."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Швидке налаштування."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Заблокований екран."</string>
@@ -720,7 +721,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Чи показувати сповіщення з цього додатка надалі?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Без звуку"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"За умовчанням"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Спливаюче сповіщення"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматично"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звуку чи вібрації"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звуку чи вібрації, з\'являється нижче в розділі розмов"</string>
@@ -732,8 +732,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налаштування"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Пріоритет"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує функції розмов"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Немає нещодавніх спливаючих чатів"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Тут з\'являтимуться нещодавні й закриті спливаючі чати"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ці сповіщення не можна змінити."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Цю групу сповіщень не можна налаштувати тут"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Проксі-сповіщення"</string>
@@ -996,25 +994,7 @@
<string name="device_services" msgid="1549944177856658705">"Сервіси на пристрої"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назви"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Натисніть, щоб перезапустити додаток і перейти в повноекранний режим."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Налаштування спливаючих чатів від додатка <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Додаткове меню"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Додати в список"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Налаштувати"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"Cповіщення \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" від додатка <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"Сповіщення \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" від додатка <xliff:g id="APP_NAME">%2$s</xliff:g> (і ще <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g>)"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Перемістити"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Перемістити ліворуч угору"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перемістити праворуч угору"</string>
- <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="1314082410868930066">"Закрити підказку"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не показувати спливаючі чати для розмов"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Спливаючий чат"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Нові повідомлення чату з\'являються у вигляді спливаючих значків. Щоб відкрити чат, натисніть його, а щоб перемістити – перетягніть."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Контроль спливаючих чатів"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Натисніть \"Налаштувати\", щоб вимкнути спливаючі чати від цього додатка"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Налаштування параметра \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\""</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>
@@ -1106,8 +1086,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Підключити новий пристрій"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Номер складання"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Номер складання скопійовано в буфер обміну."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Не вдалось отримати дані лічильника акумулятора"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Натисніть, щоб дізнатися більше"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings_tv.xml b/packages/SystemUI/res/values-uk/strings_tv.xml
index e3872cc35963..4a4cac92e6c1 100644
--- a/packages/SystemUI/res/values-uk/strings_tv.xml
+++ b/packages/SystemUI/res/values-uk/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Мікрофон активовано"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Додаток %1$s отримав доступ до вашого мікрофона"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"Мережу VPN під\'єднано"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Мережу VPN від\'єднано"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Через <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 6973c5e9127f..7488323b00c0 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"دوبارہ اسکرین شاٹ لینے کی کوشش کریں"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"اسٹوریج کی محدود جگہ کی وجہ سے اسکرین شاٹ کو محفوظ نہیں کیا جا سکتا"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ایپ یا آپ کی تنظیم کی جانب سے اسکرین شاٹس لینے کی اجازت نہیں ہے"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"اسکرین شاٹ میں ترمیم کریں"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"اسکرین شاٹ برخاست کریں"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"ترمیم کریں"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"اسکرین شاٹ میں ترمیم کریں"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"اسکرول کریں"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"اسکرین شاٹ پر اسکرول کریں"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"اسکرین شاٹ برخاست کریں"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"اسکرین شاٹ کا پیش منظر"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"سکرین ریکارڈر"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"سکرین ریکارڈنگ پروسیس ہورہی ہے"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"بیٹری کے دو بارز۔"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"بیٹری کے تین بارز۔"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"بیٹری بھری ہے۔"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"بیٹری کی فیصد نامعلوم ہے۔"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"کوئی فون نہیں ہے۔"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"فون کا ایک بار۔"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"فون کے دو بارز۔"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"اطلاع مسترد ہوگئی۔"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"بلبلہ برخاست کر دیا گیا۔"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"اطلاعاتی شیڈ۔"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"فوری ترتیبات۔"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"مقفل اسکرین۔"</string>
@@ -522,8 +523,7 @@
<string name="profile_owned_footer" msgid="2756770645766113964">"پروفائل کو مانیٹر کیا جا سکتا ہے"</string>
<string name="vpn_footer" msgid="3457155078010607471">"نیٹ ورک کو مانیٹر کیا جا سکتا ہے"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"نیٹ ورک کو شاید مانیٹر کیا جائے"</string>
- <!-- no translation found for quick_settings_disclosure_parental_controls (2114102871438223600) -->
- <skip />
+ <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"یہ آلہ آپ کے والدین کے زیر انتظام ہے"</string>
<string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"آپ کی تنظیم اس آلے کی مالک ہے اور نیٹ ورک ٹریفک کی نگرانی کر سکتی ہے"</string>
<string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> اس آلے کی مالک ہے اور نیٹ ورک ٹریفک کی نگرانی کر سکتی ہے"</string>
<string name="quick_settings_disclosure_management_named_vpn" msgid="6096715329056415588">"یہ آلہ آپ کی تنظیم کا ہے اور <xliff:g id="VPN_APP">%1$s</xliff:g> سے منسلک ہے"</string>
@@ -548,8 +548,7 @@
<string name="disable_vpn" msgid="482685974985502922">"‏VPN کو غیر فعال کریں"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"‏VPN کو غیر منسلک کریں"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"پالیسیاں دیکھیں"</string>
- <!-- no translation found for monitoring_button_view_controls (8316440345340701117) -->
- <skip />
+ <string name="monitoring_button_view_controls" msgid="8316440345340701117">"کنٹرولز دیکھیں"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"‏یہ آلہ <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> کا ہے۔\n\nآپ کا IT منتظم ترتیبات، کارپوریٹ رسائی، ایپس، آپ کے آلہ سے وابستہ ڈیٹا اور آپ کے آلہ کے مقام کی معلومات کی نگرانی اور ان کا نظم کر سکتا ہے۔\n\nمزید معلومات کے لیے اپنے IT منتظم سے رابطہ کریں۔"</string>
<string name="monitoring_description_management" msgid="4308879039175729014">"‏یہ آلہ آپ کی تنظیم کا ہے۔\n\nآپ کا IT منتظم ترتیبات، کارپوریٹ رسائی، ایپس، آپ کے آلہ سے وابستہ ڈیٹا اور آپ کے آلہ کے مقام کی معلومات کی نگرانی اور ان کا نظم کر سکتا ہے۔\n\nمزید معلومات کے لیے اپنے IT منتظم سے رابطہ کریں۔"</string>
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"آپ کی تنظیم نے اس آلے پر ایک سرٹیفکیٹ کی اتھارٹی کو انسٹال کیا ہے۔ آپ کا محفوظ نیٹ ورک ٹریفک مانیٹر ہو سکتا ہے یا اس میں ترمیم کی جا سکتی ہے۔"</string>
@@ -573,8 +572,7 @@
<string name="monitoring_description_network_logging" msgid="577305979174002252">"آپ کے ایڈمن نے نیٹ ورک لاگنگ آن کر دی ہے، جو آپ کے آلہ پر ٹریفک کو مانیٹر کرتی ہے۔\n\nمزید معلومات کیلئے اپنے ایڈمن سے رابطہ کریں۔"</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"‏آپ نے ایک ایپ کو VPN کنکشن ترتیب دینے کی اجازت دی ہے۔\n\nیہ ایپ ای میلز، ایپس اور ویب سائٹس سمیت آپ کے آلہ اور نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"‏آپ کی دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر نظم ہے۔\n\nآپ کا ایڈمن بشمول ای میلز، ایپس، اور ویب سائٹس، آپ کے نیٹ ورک کی سرگرمی کو مانیٹر کرنے کا اہل ہے۔\n\nمزید معلومات کے لیے اپنے ایڈمن سے رابطہ کریں۔\n\nآپ ایک VPN سے بھی منسلک ہیں، جو آپ کے نیٹ ورک کی سرگرمی کو مانیٹر کر سکتا ہے۔"</string>
- <!-- no translation found for monitoring_description_parental_controls (8184693528917051626) -->
- <skip />
+ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"یہ آلہ آپ کے والدین کے زیر انتظام ہے۔ آپ کے والدین آپ کی استعمال والی ایپس، آپ کا مقام اور آپ کے اسکرین کے وقت جیسی معلومات کو دیکھ اور اس کا نظم کر سکتے ہیں۔"</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
<string name="monitoring_description_app_personal" msgid="1970094872688265987">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو آپ کے نجی نیٹ ورک کی سرگرمی سمیت ای میلز، ایپس اور ویب سائٹس مانیٹر کر سکتی ہے۔"</string>
@@ -717,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"اس ایپ کی طرف سے اطلاعات دکھانا جاری رکھیں؟"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"خاموش"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"ڈیفالٹ"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"بلبلہ"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"خودکار"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"کوئی آواز یا وائبریشن نہیں"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"کوئی آواز یا وائبریشن نہیں اور گفتگو کے سیکشن میں نیچے ظاہر ہوتا ہے"</string>
@@ -729,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ترتیبات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ترجیح"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> گفتگو کی خصوصیات کو سپورٹ نہیں کرتا ہے"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"کوئی حالیہ بلبلہ نہیں"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"حالیہ بلبلے اور برخاست شدہ بلبلے یہاں ظاہر ہوں گے"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ان اطلاعات کی ترمیم نہیں کی جا سکتی۔"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"اطلاعات کے اس گروپ کو یہاں کنفیگر نہیں کیا جا سکتا"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"پراکسی اطلاع"</string>
@@ -989,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"آلہ کی سروس"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"کوئی عنوان نہیں ہے"</string>
<string name="restart_button_description" msgid="6916116576177456480">"یہ ایپ دوبارہ شروع کرنے کے لیے تھپتھپائیں اور پوری اسکرین پر جائیں۔"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> بلبلوں کے لیے ترتیبات"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"اوورفلو"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"انبار میں واپس شامل کریں"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"نظم کریں"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g> کی جانب سے <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> اور <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> مزید سے <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"منتقل کریں"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"اوپر بائیں جانب لے جائیں"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"اوپر دائیں جانب لے جائيں"</string>
- <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="1314082410868930066">"بلبلہ برخاست کریں"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"گفتگو بلبلہ نہ کریں"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"بلبلے کے ذریعے چیٹ کریں"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"نئی گفتگوئیں فلوٹنگ آئیکن یا بلبلے کے طور پر ظاہر ہوں گی۔ بلبلہ کھولنے کے لیے تھپتھپائیں۔ اسے منتقل کرنے کے لیے گھسیٹیں۔"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"کسی بھی وقت بلبلے کو کنٹرول کریں"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"اس ایپ سے بلبلوں کو آف کرنے کے لیے نظم کریں پر تھپتھپائیں"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"سمجھ آ گئی"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ترتیبات"</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>
@@ -1097,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"نئے آلہ کا جوڑا بنائیں"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"بلڈ نمبر"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"بلڈ نمبر کلپ بورڈ میں کاپی ہو گیا۔"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"آپ کے بیٹری میٹر کو پڑھنے میں دشواری"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"مزید معلومات کے لیے تھپتھپائیں"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings_tv.xml b/packages/SystemUI/res/values-ur/strings_tv.xml
index cb50fafaf931..29e4307004cb 100644
--- a/packages/SystemUI/res/values-ur/strings_tv.xml
+++ b/packages/SystemUI/res/values-ur/strings_tv.xml
@@ -21,4 +21,10 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"مائیکروفون فعال ہے"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"‏%1$s نے آپ کے مائیکروفون تک رسائی حاصل کی ہے"</string>
+ <!-- no translation found for notification_vpn_connected (3891023882833274730) -->
+ <skip />
+ <!-- no translation found for notification_vpn_disconnected (7150747626448044843) -->
+ <skip />
+ <!-- no translation found for notification_disclosure_vpn_text (3873532735584866236) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index a97f1e4a13d6..997197da19cb 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Qayta skrinshot olib ko‘ring"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Xotirada joy kamligi uchun skrinshot saqlanmadi"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ilova yoki tashkilotingiz skrinshot olishni taqiqlagan"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Skrinshotni tahrirlash"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Skrinshotni yopish"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Tahrirlash"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Skrinshotni tahrirlash"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Aylantirish"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Skrinshotni aylantirish"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Skrinshotni yopish"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Skrinshotga razm solish"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Ekrandan yozib olish"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekran yozib olinmoqda"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Batareya ikkta panelda."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Batareya uchta panelda."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Batareya to‘la."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Batareya quvvati foizi nomaʼlum."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Signal yo‘q."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Telefon bitta panelda."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Telefon ikkita panelda."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Xabarnoma e‘tiborsiz qoldirildi."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bulutcha yopildi."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Xabarnoma soyasi."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Tezkor sozlamalar."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Qulflash ekrani."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Bu ilovadan keladigan bildirishnomalar chiqaversinmi?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Tovushsiz"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Standart"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Pufaklar"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Avtomatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Tovush yoki tebranishsiz"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Tovush yoki tebranishsiz hamda suhbatlar ruknining pastida chiqadi"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Sozlamalar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Muhim"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasida suhbat funksiyalari ishlamaydi"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Avvalgi bulutchalar topilmadi"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Bu yerda oxirgi va yopilgan bulutcha shaklidagi bildirishnomalar chiqadi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Ushbu bildirishnomalar guruhi bu yerda sozlanmaydi"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Ishonchli bildirishnoma"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Qurilma xizmatlari"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nomsiz"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Bu ilovani qaytadan ishga tushirish va butun ekranga ochish uchun bosing."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g> bulutchalari uchun sozlamalar"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Kengaytirilgan"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Yana toʻplamga kiritish"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Boshqarish"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g> ilovasidan <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> va yana <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ta bildirishnoma"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Surish"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Yuqori chapga surish"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Yuqori oʻngga surish"</string>
- <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="1314082410868930066">"Bulutchani yopish"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Suhbatlar bulutchalar shaklida chiqmasin"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bulutchalar yordamida subhatlashish"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yangi xabarlar qalqib chiquvchi belgilar yoki bulutchalar kabi chiqadi. Xabarni ochish uchun bildirishnoma ustiga bosing. Xabarni qayta joylash uchun bildirishnomani suring."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Bulutchalardagi bildirishnomalar"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu ilova bulutchalarini faolsizlantirish uchun Boshqarish tugmasini bosing"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> sozlamalari"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Yangi qurilmani ulash"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Nashr raqami"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Nashr raqami vaqtinchalik xotiraga nusxalandi."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Batareya quvvati aniqlanmadi"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Batafsil axborot olish uchun bosing"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings_tv.xml b/packages/SystemUI/res/values-uz/strings_tv.xml
index 09bc51ee293c..fc4ecd34873f 100644
--- a/packages/SystemUI/res/values-uz/strings_tv.xml
+++ b/packages/SystemUI/res/values-uz/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon faol"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s mikrofondan foydalandi"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN ulandi"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN uzildi"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> orqali"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 4a69cc70abf6..1acdbb51c859 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Hãy thử chụp lại màn hình"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Không thể lưu ảnh chụp màn hình do giới hạn dung lượng bộ nhớ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ứng dụng hoặc tổ chức của bạn không cho phép chụp ảnh màn hình"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Chỉnh sửa ảnh chụp màn hình"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Đóng ảnh chụp màn hình"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Chỉnh sửa"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Chỉnh sửa ảnh chụp màn hình"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Cuộn"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Cuộn để phóng to ảnh chụp màn hình"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Đóng ảnh chụp màn hình"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Xem trước ảnh chụp màn hình"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Trình ghi màn hình"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Đang xử lý video ghi màn hình"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Mức pin hai vạch."</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Mức pin ba vạch."</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Mức pin đầy."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Tỷ lệ phần trăm pin không xác định."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Không có điện thoại nào."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Tín hiệu điện thoại một vạch."</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Tín hiệu điện thoại hai vạch."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Đã loại bỏ thông báo."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Đã đóng bong bóng."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Bóng thông báo."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Cài đặt nhanh."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Màn hình khóa."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Tiếp tục hiển thị các thông báo từ ứng dụng này?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Im lặng"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Mặc định"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Bong bóng"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Tự động"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Không phát âm thanh hoặc rung"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Không phát âm thanh hoặc rung và xuất hiện phía dưới trong phần cuộc trò chuyện"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cài đặt"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Mức độ ưu tiên"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ các tính năng trò chuyện"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Không có bong bóng trò chuyện nào gần đây"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Bong bóng trò chuyện đã đóng và bong bóng trò chuyện gần đây sẽ xuất hiện ở đây"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Không thể sửa đổi các thông báo này."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Không thể định cấu hình nhóm thông báo này tại đây"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Thông báo đã xử lý qua máy chủ proxy"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Dịch vụ cho thiết bị"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Không có tiêu đề"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Nhấn để khởi động lại ứng dụng này và xem ở chế độ toàn màn hình."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Tùy chọn cài đặt cho bong bóng trò chuyện <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Trình đơn mục bổ sung"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Thêm lại vào ngăn xếp"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Quản lý"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> của <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> từ <xliff:g id="APP_NAME">%2$s</xliff:g> và <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> bong bóng khác"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Di chuyển"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Chuyển lên trên cùng bên trái"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Chuyển lên trên cùng bên phải"</string>
- <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="1314082410868930066">"Đóng bong bóng"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Dừng sử dụng bong bóng cho cuộc trò chuyện"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Trò chuyện bằng bong bóng trò chuyện"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Các cuộc trò chuyện mới sẽ xuất hiện dưới dạng biểu tượng nổi hoặc bong bóng trò chuyện. Nhấn để mở bong bóng trò chuyện. Kéo để di chuyển bong bóng trò chuyện."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kiểm soát bong bóng bất cứ lúc nào"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Nhấn vào nút Quản lý để tắt bong bóng trò chuyện từ ứng dụng này"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"Cài đặt <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Ghép nối thiết bị mới"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Số bản dựng"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Đã sao chép số bản dựng vào khay nhớ tạm."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Đã xảy ra vấn đề khi đọc dung lượng pin của bạn"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Nhấn để biết thêm thông tin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings_tv.xml b/packages/SystemUI/res/values-vi/strings_tv.xml
index f298407bcaf3..98697fd93204 100644
--- a/packages/SystemUI/res/values-vi/strings_tv.xml
+++ b/packages/SystemUI/res/values-vi/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Micrô đang hoạt động"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s đang dùng micrô của bạn"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN đã được kết nối"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN đã bị ngắt kết nối"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Thông qua <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 9c34b31f6051..68630bba8212 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"请再次尝试截屏"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"由于存储空间有限,无法保存屏幕截图"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"此应用或您所在的单位不允许进行屏幕截图"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"编辑屏幕截图"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"关闭屏幕截图"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"编辑"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"编辑屏幕截图"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"滚动"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"滚动抓取长截图"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"关闭屏幕截图"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"屏幕截图预览"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"屏幕录制器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在处理屏幕录制视频"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"电池电量为两格。"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"电池电量为三格。"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"电池电量满格。"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"电池电量百分比未知。"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"没有手机信号。"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"手机信号强度为一格。"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"手机信号强度为两格。"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"已关闭通知。"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"已关闭对话泡。"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知栏。"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快捷设置。"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"锁定屏幕。"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"要继续显示来自此应用的通知吗?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"静音"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"默认"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"气泡"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"自动"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"不发出提示音,也不振动"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"不发出提示音,也不振动;显示在对话部分的靠下位置"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"设置"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"优先"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话功能"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近没有对话泡"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"此处会显示最近的对话泡和已关闭的对话泡"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"无法修改这些通知。"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"您无法在此处配置这组通知"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"代理通知"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"设备服务"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"无标题"</string>
<string name="restart_button_description" msgid="6916116576177456480">"点按即可重启此应用并进入全屏模式。"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"<xliff:g id="APP_NAME">%1$s</xliff:g>对话泡的设置"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"菜单"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"重新加入叠放"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"管理"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"<xliff:g id="APP_NAME">%2$s</xliff:g>和另外 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 个应用:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"移动"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"移至左上角"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移至右上角"</string>
- <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="1314082410868930066">"关闭对话泡"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不以对话泡形式显示对话"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"使用对话泡聊天"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"新对话会以浮动图标或对话泡形式显示。点按即可打开对话泡。拖动即可移动对话泡。"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"随时控制对话泡"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"点按“管理”按钮,可关闭来自此应用的对话泡"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"知道了"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>设置"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"与新设备配对"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本号"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已将版本号复制到剪贴板。"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"读取电池计量器时出现问题"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"点按即可了解详情"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
index aa3e251c9c35..169d98a538ed 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"麦克风处于启用状态"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s访问过您的麦克风"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN 已连接"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN 已断开连接"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"通过“<xliff:g id="VPN_APP">%1$s</xliff:g>”"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 2e22b0751e47..ddf60fb56e20 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"請再嘗試拍攝螢幕擷取畫面"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"由於儲存空間有限,因此無法儲存螢幕擷取畫面"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"應用程式或您的機構不允許擷取螢幕畫面"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"編輯螢幕截圖"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"關閉螢幕截圖"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"編輯"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"編輯螢幕截圖"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"捲動"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"整頁截圖"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"關閉螢幕截圖"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"螢幕截圖預覽"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"螢幕畫面錄影工具"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在處理螢幕錄影內容"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"電池電量為兩格。"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"電池電量為三格。"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"電池已滿。"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"電量百分比不明。"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"沒有電話訊號。"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"電話訊號強度為一格。"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"電話訊號強度為兩格。"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"通知已關閉。"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"對話氣泡已關閉。"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知欄。"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快速設定。"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"上鎖畫面。"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"要繼續顯示此應用程式的通知嗎?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"靜音"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"預設"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"氣泡"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"自動"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"無音效或震動"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"無音效或震動,並在對話部分的較低位置顯示"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"重要"</string>
<string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"沒有最近曾使用的小視窗"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近使用和關閉的小視窗會在這裡顯示"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"無法在此設定這組通知"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"代理通知"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"裝置服務"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
<string name="restart_button_description" msgid="6916116576177456480">"輕按即可重新開啟此應用程式並放大至全螢幕。"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」小視窗設定"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"顯示更多"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"加回堆疊"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"管理"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"來自「<xliff:g id="APP_NAME">%2$s</xliff:g>」的 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"來自「<xliff:g id="APP_NAME">%2$s</xliff:g>」及另外 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 個應用程式的<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"移動"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"移去左上角"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移去右上角"</string>
- <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="1314082410868930066">"關閉小視窗氣泡"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不要透過小視窗顯示對話"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"使用小視窗進行即時通訊"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"新對話會以浮動圖示 (小視窗) 顯示。輕按即可開啟小視窗。拖曳即可移動小視窗。"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"隨時控制小視窗設定"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"輕按「管理」即可關閉此應用程式的小視窗"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"知道了"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」設定"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"版本號碼已複製到剪貼簿。"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕按即可瞭解詳情"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
index 45d3229cdcb6..858185186365 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"麥克風已啟用"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"「%1$s」已存取您的麥克風"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN 已連線"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN 已中斷連線"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"透過 <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 0cc17efc553b..85aae2e9453b 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"請再次嘗試拍攝螢幕截圖"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"由於儲存空間有限,因此無法儲存螢幕截圖"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"這個應用程式或貴機構不允許擷取螢幕畫面"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"編輯螢幕截圖"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"關閉螢幕截圖"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"編輯"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"編輯螢幕截圖"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"拍攝長截圖"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"以捲動畫面的方式拍攝長截圖"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"關閉螢幕截圖"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"螢幕截圖預覽"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"螢幕錄影器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"處理螢幕錄影內容"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"電池電量兩格。"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"電池電量三格。"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"電池電量已滿。"</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"電池電量不明。"</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"沒有電話訊號。"</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"電話訊號強度一格。"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"電話訊號強度兩格。"</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"已關閉通知。"</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"已關閉泡泡。"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"通知欄。"</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"快捷設定。"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"螢幕鎖定。"</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"要繼續顯示這個應用程式的通知嗎?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"靜音"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"預設"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"泡泡"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"自動"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"不震動或發出聲音"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"不震動或發出聲音,並調整排序到其他對話下方"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
<string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近沒有任何對話框"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近的對話框和已關閉的對話框會顯示在這裡"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"無法在這裡設定這個通知群組"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"經過 Proxy 處理的通知"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"裝置服務"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
<string name="restart_button_description" msgid="6916116576177456480">"輕觸即可重新啟動這個應用程式並進入全螢幕模式。"</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」對話框的設定"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"溢位"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"重新加入堆疊"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"管理"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"<xliff:g id="APP_NAME">%2$s</xliff:g>:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"「<xliff:g id="APP_NAME">%2$s</xliff:g>」和其他 <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> 個應用程式:<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"移動"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"移至左上方"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移至右上方"</string>
- <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="1314082410868930066">"關閉對話框"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不要以對話框形式顯示對話"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"透過對話框來聊天"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"新的對話會以浮動圖示或對話框形式顯示。輕觸即可開啟對話框,拖曳則可移動對話框。"</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"你隨時可以控管對話框的各項設定"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"輕觸 [管理] 即可關閉來自這個應用程式的對話框"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"我知道了"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」設定"</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>
@@ -1094,8 +1074,6 @@
<string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"配對新裝置"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"版本號碼"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"已將版本號碼複製到剪貼簿。"</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"讀取電池計量器時發生問題"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"輕觸即可瞭解詳情"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
index fdd088449567..fcb16b79c3ad 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"麥克風已開啟"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"「%1$s」已存取你的麥克風"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN 已連線"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN 連線已中斷"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"透過「<xliff:g id="VPN_APP">%1$s</xliff:g>」"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 9e85eeddbd96..ca87d975e42e 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -86,8 +86,11 @@
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Zama ukuthatha isithombe-skrini futhi"</string>
<string name="screenshot_failed_to_save_text" msgid="8344173457344027501">"Ayikwazi ukulondoloza isithombe-skrini ngenxa yesikhala sesitoreji esikhawulelwe"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Ukuthatha izithombe-skrini akuvunyelwe uhlelo lokusebenza noma inhlangano yakho"</string>
- <string name="screenshot_edit" msgid="3510496440489019191">"Hlela isithombe-skrini"</string>
- <string name="screenshot_dismiss_ui_description" msgid="934736855340147968">"Cashisa isithombe-skrini"</string>
+ <string name="screenshot_edit_label" msgid="8754981973544133050">"Hlela"</string>
+ <string name="screenshot_edit_description" msgid="3333092254706788906">"Hlela isithombe-skrini"</string>
+ <string name="screenshot_scroll_label" msgid="7682877978685434621">"Skrola"</string>
+ <string name="screenshot_scroll_description" msgid="7855773867093272175">"Isithombe seskrini sokuskrola"</string>
+ <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Cashisa isithombe-skrini"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"Ukubuka kuqala isithombe-skrini"</string>
<string name="screenrecord_name" msgid="2596401223859996572">"Irekhoda yesikrini"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Icubungula okokuqopha iskrini"</string>
@@ -182,8 +185,7 @@
<string name="accessibility_battery_two_bars" msgid="7895789999668425551">"Amabha amabili ebhethri"</string>
<string name="accessibility_battery_three_bars" msgid="118341923832368291">"Amabha amathathu ebhethri"</string>
<string name="accessibility_battery_full" msgid="1480463938961288494">"Ibhethri igcwele."</string>
- <!-- no translation found for accessibility_battery_unknown (1807789554617976440) -->
- <skip />
+ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Iphesenti lebhethri alaziwa."</string>
<string name="accessibility_no_phone" msgid="8828412144430247025">"Ayikho ifoni."</string>
<string name="accessibility_phone_one_bar" msgid="8786055123727785588">"Ibha eyodwa yefoni"</string>
<string name="accessibility_phone_two_bars" msgid="3316909612598670674">"Amabha amabilil efoni."</string>
@@ -257,7 +259,6 @@
<!-- no translation found for accessibility_work_mode (1280025758672376313) -->
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Isaziso sichithiwe."</string>
- <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Ibhamuza licashisiwe."</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Umthunzi wesaziso."</string>
<string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Izilingiselelo ezisheshayo."</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Khiya isikrini."</string>
@@ -714,7 +715,6 @@
<string name="inline_keep_showing_app" msgid="4393429060390649757">"Qhubeka nokubonisa izaziso kusuka kulolu hlelo lokusebenza?"</string>
<string name="notification_silence_title" msgid="8608090968400832335">"Kuthulile"</string>
<string name="notification_alert_title" msgid="3656229781017543655">"Okuzenzekelayo"</string>
- <string name="notification_bubble_title" msgid="8330481035191903164">"Ibhamuza"</string>
<string name="notification_automatic_title" msgid="3745465364578762652">"Okuzenzekelayo"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Awukho umsindo noma ukudlidliza"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Awukho umsindo noma ukudlidliza futhi ivela ngezansi esigabeni sengxoxo"</string>
@@ -726,8 +726,6 @@
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Izilungiselelo"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Okubalulekile"</string>
<string name="no_shortcut" msgid="8257177117568230126">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli izici zengxoxo"</string>
- <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Awekho amabhamuza akamuva"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Amabhamuza akamuva namabhamuza asusiwe azobonakala lapha."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Lezi zaziso azikwazi ukushintshwa."</string>
<string name="notification_multichannel_desc" msgid="7414593090056236179">"Leli qembu lezaziso alikwazi ukulungiselelwa lapha"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"Isaziso sommeli"</string>
@@ -986,25 +984,7 @@
<string name="device_services" msgid="1549944177856658705">"Amasevisi edivayisi"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Asikho isihloko"</string>
<string name="restart_button_description" msgid="6916116576177456480">"Thepha ukuze uqale kabusha lolu hlelo lokusebenza uphinde uye kusikrini esigcwele."</string>
- <string name="bubbles_settings_button_description" msgid="7324245408859877545">"Izilungiselelo zamabhamuza e-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="bubble_overflow_button_content_description" msgid="5523744621434300510">"Ukuphuphuma"</string>
- <string name="bubble_accessibility_action_add_back" msgid="6217995665917123890">"Engeza emuva kusitaki"</string>
- <string name="manage_bubbles_text" msgid="6856830436329494850">"Phatha"</string>
- <string name="bubble_content_description_single" msgid="5175160674436546329">"I-<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kusuka ku-<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
- <string name="bubble_content_description_stack" msgid="7907610717462651870">"I-<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kusukela ku-<xliff:g id="APP_NAME">%2$s</xliff:g> nokungu-<xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> ngaphezulu"</string>
<string name="bubble_accessibility_action_move" msgid="3185080443743819178">"Hambisa"</string>
- <string name="bubble_accessibility_action_move_top_left" msgid="4347227665275929728">"Hambisa phezulu kwesokunxele"</string>
- <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Hambisa phezulu ngakwesokudla"</string>
- <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="1314082410868930066">"Cashisa ibhamuza"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ungayibhamuzi ingxoxo"</string>
- <string name="bubbles_user_education_title" msgid="5547017089271445797">"Xoxa usebenzisa amabhamuza"</string>
- <string name="bubbles_user_education_description" msgid="1160281719576715211">"Izingxoxo ezintsha zivela njengezithonjana ezintantayo, noma amabhamuza. Thepha ukuze uvule ibhamuza. Hudula ukuze ulihambise."</string>
- <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Lawula amabhamuza noma nini"</string>
- <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Thepha okuthi Phatha ukuvala amabhamuza kusuka kulolu hlelo lokusebenza"</string>
- <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Ngiyezwa"</string>
- <string name="bubbles_app_settings" msgid="5779443644062348657">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> izilungiselelo"</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>
@@ -1091,11 +1071,9 @@
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"amadivayisi akhethiwe angu-<xliff:g id="COUNT">%1$d</xliff:g>"</string>
<string name="media_output_dialog_disconnected" msgid="1834473104836986046">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> (inqamukile)"</string>
<string name="media_output_dialog_connect_failed" msgid="3225190634236259010">"Ayikwazanga ukuxhumeka. Zama futhi."</string>
- <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bhanqa idivayisi entsha"</string>
+ <string name="media_output_dialog_pairing_new" msgid="9099497976087485862">"Bhangqa idivayisi entsha"</string>
<string name="build_number_clip_data_label" msgid="3623176728412560914">"Yakha inombolo"</string>
<string name="build_number_copy_toast" msgid="877720921605503046">"Yakha inombolo ekopishelwe kubhodi yokunamathisela."</string>
- <!-- no translation found for battery_state_unknown_notification_title (8464703640483773454) -->
- <skip />
- <!-- no translation found for battery_state_unknown_notification_text (13720937839460899) -->
- <skip />
+ <string name="battery_state_unknown_notification_title" msgid="8464703640483773454">"Kube khona inkinga ngokufunda imitha yakho yebhethri"</string>
+ <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Thepha ukuze uthole olunye ulwazi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings_tv.xml b/packages/SystemUI/res/values-zu/strings_tv.xml
index 4fed753a88ad..5cb6c1d1796e 100644
--- a/packages/SystemUI/res/values-zu/strings_tv.xml
+++ b/packages/SystemUI/res/values-zu/strings_tv.xml
@@ -21,4 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Imakrofoni iyasebenza"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s ifinyelele imakrofoni yakho"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"I-VPN ixhunyiwe"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"I-VPN inqanyuliwe"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Nge-<xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 6df8b4e733bb..be36316d013c 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -204,10 +204,6 @@
<color name="global_screenshot_dismiss_foreground">@color/GM2_grey_500</color>
<color name="global_screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
- <!-- Bubbles -->
- <color name="bubbles_light">#FFFFFF</color>
- <color name="bubbles_dark">@color/GM2_grey_800</color>
-
<!-- GM2 colors -->
<color name="GM2_grey_50">#F8F9FA</color>
<color name="GM2_grey_100">#F1F3F4</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 1a72fc231815..4407d8faeaa6 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -93,10 +93,10 @@
<bool name="config_navigation_bar_enable_auto_dim_no_visible_wallpaper">true</bool>
<!-- The maximum number of tiles in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_columns">6</integer>
+ <integer name="quick_qs_panel_max_columns">4</integer>
<!-- The number of columns in the QuickSettings -->
- <integer name="quick_settings_num_columns">3</integer>
+ <integer name="quick_settings_num_columns">4</integer>
<!-- The number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">3</integer>
@@ -114,7 +114,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse
+ wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 17dc4004ae9b..d946f7cb11c1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -149,7 +149,7 @@
<dimen name="notification_max_heads_up_height_increased">188dp</dimen>
<!-- Side padding on the lockscreen on the side of notifications -->
- <dimen name="notification_side_paddings">4dp</dimen>
+ <dimen name="notification_side_paddings">16dp</dimen>
<!-- padding between the heads up and the statusbar -->
<dimen name="heads_up_status_bar_padding">8dp</dimen>
@@ -170,6 +170,9 @@
<!-- Minimum height of a notification to be interactable -->
<dimen name="notification_min_interaction_height">40dp</dimen>
+ <!-- New radius for notifications. -->
+ <dimen name="notification_corner_radius">20dp</dimen>
+
<!-- the padding of the shelf icon container -->
<dimen name="shelf_icon_container_padding">13dp</dimen>
@@ -427,7 +430,7 @@
<dimen name="notification_panel_width">@dimen/match_parent</dimen>
- <dimen name="brightness_mirror_height">48dp</dimen>
+ <dimen name="brightness_mirror_height">56dp</dimen>
<!-- The width of the panel that holds the quick settings. -->
<dimen name="qs_panel_width">@dimen/notification_panel_width</dimen>
@@ -493,10 +496,10 @@
<dimen name="qs_tile_margin_top_bottom">12dp</dimen>
<dimen name="qs_tile_margin_top_bottom_negative">-12dp</dimen>
<!-- The height of the qs customize header. Should be
- (qs_panel_padding_top (48dp) + brightness_mirror_height (48dp) + qs_tile_margin_top (0dp)) -
+ (qs_panel_padding_top (48dp) + brightness_mirror_height (56dp) + qs_tile_margin_top (0dp)) -
(Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (12dp))
-->
- <dimen name="qs_customize_header_min_height">28dp</dimen>
+ <dimen name="qs_customize_header_min_height">36dp</dimen>
<dimen name="qs_tile_margin_top">0dp</dimen>
<dimen name="qs_tile_icon_background_stroke_width">-1dp</dimen>
<dimen name="qs_tile_background_size">44dp</dimen>
@@ -609,7 +612,7 @@
<dimen name="z_distance_between_notifications">0.5dp</dimen>
<!-- The height of the divider between the individual notifications. -->
- <dimen name="notification_divider_height">0.5dp</dimen>
+ <dimen name="notification_divider_height">4dp</dimen>
<!-- The corner radius of the shadow behind the notification. -->
<dimen name="notification_shadow_radius">0dp</dimen>
@@ -619,9 +622,7 @@
<!-- The height of the divider between the individual notifications in a notification
group. -->
- <dimen name="notification_children_container_divider_height">
- @dimen/notification_divider_height
- </dimen>
+ <dimen name="notification_children_container_divider_height">0.5dp</dimen>
<!-- The horizontal margin of the content in the notification shade -->
<dimen name="notification_shade_content_margin_horizontal">16dp</dimen>
@@ -634,9 +635,6 @@
<!-- The height of a notification header -->
<dimen name="notification_header_height">53dp</dimen>
- <!-- The height of the divider between the individual notifications when the notification wants it to be increased. This is currently the case for notification groups -->
- <dimen name="notification_divider_height_increased">6dp</dimen>
-
<!-- The height of the gap between adjacent notification sections. -->
<dimen name="notification_section_divider_height">@dimen/notification_side_paddings</dimen>
@@ -1159,90 +1157,6 @@
<!-- Radius of Ongoing App Ops chip corners -->
<dimen name="ongoing_appops_chip_bg_corner_radius">16dp</dimen>
-
- <!-- How much each bubble is elevated. -->
- <dimen name="bubble_elevation">1dp</dimen>
- <!-- How much the bubble flyout text container is elevated. -->
- <dimen name="bubble_flyout_elevation">4dp</dimen>
- <!-- How much padding is around the left and right sides of the flyout text. -->
- <dimen name="bubble_flyout_padding_x">12dp</dimen>
- <!-- How much padding is around the top and bottom of the flyout text. -->
- <dimen name="bubble_flyout_padding_y">10dp</dimen>
- <!-- Size of the triangle that points from the flyout to the bubble stack. -->
- <dimen name="bubble_flyout_pointer_size">6dp</dimen>
- <!-- How much space to leave between the flyout (tip of the arrow) and the bubble stack. -->
- <dimen name="bubble_flyout_space_from_bubble">8dp</dimen>
- <!-- How much space to leave between the flyout text and the avatar displayed in the flyout. -->
- <dimen name="bubble_flyout_avatar_message_space">6dp</dimen>
- <!-- Padding between status bar and bubbles when displayed in expanded state -->
- <dimen name="bubble_padding_top">16dp</dimen>
- <!-- Size of individual bubbles. -->
- <dimen name="individual_bubble_size">60dp</dimen>
- <!-- Size of bubble bitmap. -->
- <dimen name="bubble_bitmap_size">52dp</dimen>
- <!-- Size of bubble icon bitmap. -->
- <dimen name="bubble_overflow_icon_bitmap_size">24dp</dimen>
- <!-- Extra padding added to the touchable rect for bubbles so they are easier to grab. -->
- <dimen name="bubble_touch_padding">12dp</dimen>
- <!-- Size of the circle around the bubbles when they're in the dismiss target. -->
- <dimen name="bubble_dismiss_encircle_size">52dp</dimen>
- <!-- Padding around the view displayed when the bubble is expanded -->
- <dimen name="bubble_expanded_view_padding">4dp</dimen>
- <!-- This should be at least the size of bubble_expanded_view_padding; it is used to include
- a slight touch slop around the expanded view. -->
- <dimen name="bubble_expanded_view_slop">8dp</dimen>
- <!-- Default (and minimum) height of the expanded view shown when the bubble is expanded -->
- <dimen name="bubble_expanded_default_height">180dp</dimen>
- <!-- Default height of bubble overflow -->
- <dimen name="bubble_overflow_height">480dp</dimen>
- <!-- Bubble overflow padding when there are no bubbles -->
- <dimen name="bubble_overflow_empty_state_padding">16dp</dimen>
- <!-- Padding of container for overflow bubbles -->
- <dimen name="bubble_overflow_padding">15dp</dimen>
- <!-- Padding of label for bubble overflow view -->
- <dimen name="bubble_overflow_text_padding">7dp</dimen>
- <!-- Height of bubble overflow empty state illustration -->
- <dimen name="bubble_empty_overflow_image_height">200dp</dimen>
- <!-- Padding of bubble overflow empty state subtitle -->
- <dimen name="bubble_empty_overflow_subtitle_padding">50dp</dimen>
- <!-- Height of the triangle that points to the expanded bubble -->
- <dimen name="bubble_pointer_height">8dp</dimen>
- <!-- Width of the triangle that points to the expanded bubble -->
- <dimen name="bubble_pointer_width">12dp</dimen>
- <!-- Extra padding around the dismiss target for bubbles -->
- <dimen name="bubble_dismiss_slop">16dp</dimen>
- <!-- Height of button allowing users to adjust settings for bubbles. -->
- <dimen name="bubble_manage_button_height">48dp</dimen>
- <!-- Max width of the message bubble-->
- <dimen name="bubble_message_max_width">144dp</dimen>
- <!-- Min width of the message bubble -->
- <dimen name="bubble_message_min_width">32dp</dimen>
- <!-- Interior padding of the message bubble -->
- <dimen name="bubble_message_padding">4dp</dimen>
- <!-- Offset between bubbles in their stacked position. -->
- <dimen name="bubble_stack_offset">10dp</dimen>
- <!-- Offset between stack y and animation y for bubble swap. -->
- <dimen name="bubble_swap_animation_offset">15dp</dimen>
- <!-- How far offscreen the bubble stack rests. Cuts off padding and part of icon bitmap. -->
- <dimen name="bubble_stack_offscreen">9dp</dimen>
- <!-- How far down the screen the stack starts. -->
- <dimen name="bubble_stack_starting_offset_y">120dp</dimen>
- <!-- Space between the pointer triangle and the bubble expanded view -->
- <dimen name="bubble_pointer_margin">8dp</dimen>
- <!-- Padding applied to the bubble dismiss target. Touches in this padding cause the bubbles to
- snap to the dismiss target. -->
- <dimen name="bubble_dismiss_target_padding_x">40dp</dimen>
- <dimen name="bubble_dismiss_target_padding_y">20dp</dimen>
- <dimen name="bubble_manage_menu_elevation">4dp</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. -->
- <dimen name="bubbles_manage_education_top_inset">65dp</dimen>
- <!-- Size of padding for the user education cling, this should at minimum be larger than
- individual_bubble_size + some padding. -->
- <dimen name="bubble_stack_user_education_side_inset">72dp</dimen>
-
<!-- Size of the RAT type for CellularTile -->
<dimen name="celltile_rat_type_size">10sp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 7d3135ac1937..5f68bdb4f0c6 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -130,12 +130,6 @@
<item type="id" name="action_snooze_assistant_suggestion_1"/>
<item type="id" name="action_snooze"/>
- <!-- Accessibility actions for bubbles. -->
- <item type="id" name="action_move_top_left"/>
- <item type="id" name="action_move_top_right"/>
- <item type="id" name="action_move_bottom_left"/>
- <item type="id" name="action_move_bottom_right"/>
-
<!-- For StatusIconContainer to tag its icon views -->
<item type="id" name="status_bar_view_state_tag" />
@@ -146,17 +140,6 @@
<!-- Optional cancel button on Keyguard -->
<item type="id" name="cancel_button"/>
- <!-- For saving PhysicsAnimationLayout animations/animators as view tags. -->
- <item type="id" name="translation_x_dynamicanimation_tag"/>
- <item type="id" name="translation_y_dynamicanimation_tag"/>
- <item type="id" name="translation_z_dynamicanimation_tag"/>
- <item type="id" name="alpha_dynamicanimation_tag"/>
- <item type="id" name="scale_x_dynamicanimation_tag"/>
- <item type="id" name="scale_y_dynamicanimation_tag"/>
- <item type="id" name="physics_animator_tag"/>
- <item type="id" name="target_animator_tag" />
- <item type="id" name="reorder_animator_tag"/>
-
<!-- Global Actions Menu -->
<item type="id" name="global_actions_view" />
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index b1e91c8a86c6..b50b5c14b1fa 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -22,17 +22,6 @@
<integer name="qs_footer_actions_width">0</integer>
<integer name="qs_footer_actions_weight">1</integer>
- <!-- Maximum number of bubbles to render and animate at one time. While the animations used are
- lightweight translation animations, this number can be reduced on lower end devices if any
- performance issues arise. -->
- <integer name="bubbles_max_rendered">5</integer>
-
- <!-- Number of columns in bubble overflow. -->
- <integer name="bubbles_overflow_columns">4</integer>
-
- <!-- Maximum number of bubbles we allow in overflow before we dismiss the oldest one. -->
- <integer name="bubbles_max_overflow">16</integer>
-
<integer name="magnification_default_scale">2</integer>
<!-- The position of the volume dialog on the screen.
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d5c98233b952..ea1258f025f7 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -233,10 +233,16 @@
<!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] -->
<string name="screenshot_failed_to_capture_text">Taking screenshots isn\'t allowed by the app or
your organization</string>
+ <!-- Label for UI element which allows editing the screenshot [CHAR LIMIT=30] -->
+ <string name="screenshot_edit_label">Edit</string>
<!-- Content description indicating that tapping the element will allow editing the screenshot [CHAR LIMIT=NONE] -->
- <string name="screenshot_edit">Edit screenshot</string>
+ <string name="screenshot_edit_description">Edit screenshot</string>
+ <!-- Label for UI element which allows scrolling and extending the screenshot to be taller [CHAR LIMIT=30] -->
+ <string name="screenshot_scroll_label">Scroll</string>
+ <!-- Content description UI element which allows scrolling and extending the screenshot to be taller [CHAR LIMIT=NONE] -->
+ <string name="screenshot_scroll_description">Scroll screenshot</string>
<!-- Content description indicating that tapping a button will dismiss the screenshots UI [CHAR LIMIT=NONE] -->
- <string name="screenshot_dismiss_ui_description">Dismiss screenshot</string>
+ <string name="screenshot_dismiss_description">Dismiss screenshot</string>
<!-- Content description indicating that the view is a preview of the screenshot that was just taken [CHAR LIMIT=NONE] -->
<string name="screenshot_preview_description">Screenshot preview</string>
@@ -646,9 +652,6 @@
<!-- Content description to tell the user a notification has been removed from the notification shade -->
<string name="accessibility_notification_dismissed">Notification dismissed.</string>
- <!-- Content description to tell the user a bubble has been dismissed. -->
- <string name="accessibility_bubble_dismissed">Bubble dismissed.</string>
-
<!-- Content description for the notification shade panel (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_desc_notification_shade">Notification shade.</string>
<!-- Content description for the quick settings panel (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -1011,6 +1014,11 @@
<string name="quick_settings_dark_mode_secondary_label_on_at">On at <xliff:g id="time" example="10 pm">%s</xliff:g></string>
<!-- QuickSettings: Secondary text for when the Dark theme or some other tile will be on until some user-selected time. [CHAR LIMIT=20] -->
<string name="quick_settings_dark_mode_secondary_label_until">Until <xliff:g id="time" example="7 am">%s</xliff:g></string>
+ <!-- TODO(b/170970602): remove translatable=false when RBC has official name and strings -->
+ <!-- QuickSettings: Label for the toggle that controls whether Reduce Bright Colors is enabled. [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_reduce_bright_colors_label" translatable="false">Reduce Bright Colors</string>
+ <!-- QuickSettings: Secondary text for intensity level of Reduce Bright Colors. [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_reduce_bright_colors_secondary_label" translatable="false"> <xliff:g id="intensity" example="50">%d</xliff:g>%% reduction</string>
<!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
<string name="quick_settings_nfc_label">NFC</string>
@@ -1846,9 +1854,6 @@
<string name="notification_alert_title">Default</string>
<!-- [CHAR LIMIT=100] Notification Importance title -->
- <string name="notification_bubble_title">Bubble</string>
-
- <!-- [CHAR LIMIT=100] Notification Importance title -->
<string name="notification_automatic_title">Automatic</string>
<!-- [CHAR LIMIT=150] Notification Importance title: low importance level summary -->
@@ -1881,12 +1886,6 @@
<!-- Text shown in notification guts for conversation notifications that don't implement the full feature -->
<string name="no_shortcut"><xliff:g id="app_name" example="YouTube">%1$s</xliff:g> doesn\u2019t support conversation features</string>
- <!-- [CHAR LIMIT=NONE] Empty overflow title -->
- <string name="bubble_overflow_empty_title">No recent bubbles</string>
-
- <!-- [CHAR LIMIT=NONE] Empty overflow subtitle -->
- <string name="bubble_overflow_empty_subtitle">Recent bubbles and dismissed bubbles will appear here</string>
-
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">These notifications can\'t be modified.</string>
@@ -2607,45 +2606,8 @@
<!-- Description of the restart button in the hint of size compatibility mode. [CHAR LIMIT=NONE] -->
<string name="restart_button_description">Tap to restart this app and go full screen.</string>
- <!-- Text used for content description of settings button in the header of expanded bubble
- view. [CHAR_LIMIT=NONE] -->
- <string name="bubbles_settings_button_description">Settings for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> bubbles</string>
- <!-- Content description for button that shows bubble overflow on click [CHAR LIMIT=NONE] -->
- <string name="bubble_overflow_button_content_description">Overflow</string>
- <!-- Action to add overflow bubble back to stack. [CHAR LIMIT=NONE] -->
- <string name="bubble_accessibility_action_add_back">Add back to stack</string>
- <!-- The text for the manage bubbles link. [CHAR LIMIT=NONE] -->
- <string name="manage_bubbles_text">Manage</string>
- <!-- Content description when a bubble is focused. [CHAR LIMIT=NONE] -->
- <string name="bubble_content_description_single"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g></string>
- <!-- Content description when the stack of bubbles is focused. [CHAR LIMIT=NONE] -->
- <string name="bubble_content_description_stack"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g> and <xliff:g id="bubble_count" example="4">%3$d</xliff:g> more</string>
<!-- Action in accessibility menu to move the stack of bubbles [CHAR LIMIT=20] -->
<string name="bubble_accessibility_action_move">Move</string>
- <!-- Action in accessibility menu to move the stack of bubbles to the top left of the screen. [CHAR LIMIT=30] -->
- <string name="bubble_accessibility_action_move_top_left">Move top left</string>
- <!-- Action in accessibility menu to move the stack of bubbles to the top right of the screen. [CHAR LIMIT=30] -->
- <string name="bubble_accessibility_action_move_top_right">Move top right</string>
- <!-- Action in accessibility menu to move the stack of bubbles to the bottom left of the screen. [CHAR LIMIT=30]-->
- <string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string>
- <!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]-->
- <string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string>
- <!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=30] -->
- <string name="bubble_dismiss_text">Dismiss bubble</string>
- <!-- Button text to stop a conversation from bubbling [CHAR LIMIT=60]-->
- <string name="bubbles_dont_bubble_conversation">Don\u2019t bubble conversation</string>
- <!-- Title text for the bubbles feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=60]-->
- <string name="bubbles_user_education_title">Chat using bubbles</string>
- <!-- Descriptive text for the bubble feature education cling shown when a bubble is on screen for the first time. [CHAR LIMIT=NONE] -->
- <string name="bubbles_user_education_description">New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it.</string>
- <!-- Title text for the bubble "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=60]-->
- <string name="bubbles_user_education_manage_title">Control bubbles anytime</string>
- <!-- Descriptive text for the bubble "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=80]-->
- <string name="bubbles_user_education_manage">Tap Manage to turn off bubbles from this app</string>
- <!-- Button text for dismissing the bubble "manage" button tool tip [CHAR LIMIT=20]-->
- <string name="bubbles_user_education_got_it">Got it</string>
- <!-- Label for the button that takes the user to the notification settings for the given app. -->
- <string name="bubbles_app_settings"><xliff:g id="notification_title" example="Android Messages">%1$s</xliff:g> settings</string>
<!-- Notification content text when the system navigation mode changes as a result of changing the default launcher [CHAR LIMIT=NONE] -->
<string name="notification_content_system_nav_changed">System navigation updated. To make changes, go to Settings.</string>
@@ -2859,8 +2821,12 @@
<!-- Text to display when copying the build number off QS [CHAR LIMIT=NONE]-->
<string name="build_number_copy_toast">Build number copied to clipboard.</string>
- <!-- Status for last interaction [CHAR LIMIT=120] -->
+ <!-- Status for last interaction with exact time [CHAR LIMIT=120] -->
<string name="last_interaction_status" translatable="false">You last chatted <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
+ <!-- Status for last interaction when less than a certain time window [CHAR LIMIT=120] -->
+ <string name="last_interaction_status_less_than" translatable="false">You last chatted less than <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
+ <!-- Status for last interaction when over a certain time window [CHAR LIMIT=120] -->
+ <string name="last_interaction_status_over" translatable="false">You last chatted over <xliff:g id="duration" example="1 week">%1$s</xliff:g> ago</string>
<!-- Status for conversation without interaction data [CHAR LIMIT=120] -->
<string name="basic_status" translatable="false">Open conversation</string>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 5d7f08eef0a1..13271d6f7f2e 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -20,4 +20,10 @@
<!-- Title and subtitle for AudioRecordingIndicator -->
<string name="mic_active">Microphone Active</string>
<string name="app_accessed_mic">%1$s accessed your microphone</string>
+
+ <string name="notification_vpn_connected">VPN is connected</string>
+ <string name="notification_vpn_disconnected">VPN is disconnected</string>
+ <!-- Disclosure text in the connected notification that indicates that the device is connected to a VPN. The placeholder is the VPN name. [CHAR LIMIT=40] -->
+ <string name="notification_disclosure_vpn_text">Via <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g></string>
+
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 42380198cf17..dd57af33b4dc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -34,8 +34,6 @@ import android.app.WindowConfiguration;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.graphics.Rect;
@@ -45,7 +43,6 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.view.IRecentsAnimationController;
@@ -58,7 +55,6 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.Future;
import java.util.function.Consumer;
public class ActivityManagerWrapper {
@@ -74,14 +70,7 @@ public class ActivityManagerWrapper {
// Should match the value in AssistManager
private static final String INVOCATION_TIME_MS_KEY = "invocation_time_ms";
- private final PackageManager mPackageManager;
- private final BackgroundExecutor mBackgroundExecutor;
-
- private ActivityManagerWrapper() {
- final Context context = AppGlobals.getInitialApplication();
- mPackageManager = context.getPackageManager();
- mBackgroundExecutor = BackgroundExecutor.get();
- }
+ private ActivityManagerWrapper() { }
public static ActivityManagerWrapper getInstance() {
return sInstance;
@@ -159,60 +148,12 @@ public class ActivityManagerWrapper {
* Removes the outdated snapshot of home task.
*/
public void invalidateHomeTaskSnapshot(final Activity homeActivity) {
- mBackgroundExecutor.submit(new Runnable() {
- @Override
- public void run() {
- try {
- ActivityTaskManager.getService().invalidateHomeTaskSnapshot(
- homeActivity.getActivityToken());
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to invalidate home snapshot", e);
- }
- }
- });
- }
-
- /**
- * @return the activity label, badging if necessary.
- */
- public String getBadgedActivityLabel(ActivityInfo info, int userId) {
- return getBadgedLabel(info.loadLabel(mPackageManager).toString(), userId);
- }
-
- /**
- * @return the application label, badging if necessary.
- */
- public String getBadgedApplicationLabel(ApplicationInfo appInfo, int userId) {
- return getBadgedLabel(appInfo.loadLabel(mPackageManager).toString(), userId);
- }
-
- /**
- * @return the content description for a given task, badging it if necessary. The content
- * description joins the app and activity labels.
- */
- public String getBadgedContentDescription(ActivityInfo info, int userId,
- ActivityManager.TaskDescription td) {
- String activityLabel;
- if (td != null && td.getLabel() != null) {
- activityLabel = td.getLabel();
- } else {
- activityLabel = info.loadLabel(mPackageManager).toString();
- }
- String applicationLabel = info.applicationInfo.loadLabel(mPackageManager).toString();
- String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId);
- return applicationLabel.equals(activityLabel)
- ? badgedApplicationLabel
- : badgedApplicationLabel + " " + activityLabel;
- }
-
- /**
- * @return the given label for a user, badging if necessary.
- */
- private String getBadgedLabel(String label, int userId) {
- if (userId != UserHandle.myUserId()) {
- label = mPackageManager.getUserBadgedLabel(label, new UserHandle(userId)).toString();
+ try {
+ ActivityTaskManager.getService().invalidateHomeTaskSnapshot(
+ homeActivity.getActivityToken());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to invalidate home snapshot", e);
}
- return label;
}
/**
@@ -342,59 +283,33 @@ public class ActivityManagerWrapper {
/**
* Requests that the system close any open system windows (including other SystemUI).
*/
- public Future<?> closeSystemWindows(final String reason) {
- return mBackgroundExecutor.submit(new Runnable() {
- @Override
- public void run() {
- try {
- ActivityManager.getService().closeSystemDialogs(reason);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to close system windows", e);
- }
- }
- });
+ public void closeSystemWindows(final String reason) {
+ try {
+ ActivityManager.getService().closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to close system windows", e);
+ }
}
/**
* Removes a task by id.
*/
public void removeTask(final int taskId) {
- mBackgroundExecutor.submit(new Runnable() {
- @Override
- public void run() {
- try {
- ActivityTaskManager.getService().removeTask(taskId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to remove task=" + taskId, e);
- }
- }
- });
+ try {
+ ActivityTaskManager.getService().removeTask(taskId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to remove task=" + taskId, e);
+ }
}
/**
* Removes all the recent tasks.
*/
public void removeAllRecentTasks() {
- mBackgroundExecutor.submit(new Runnable() {
- @Override
- public void run() {
- try {
- ActivityTaskManager.getService().removeAllVisibleRecentTasks();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to remove all tasks", e);
- }
- }
- });
- }
-
- /**
- * Cancels the current window transtion to/from Recents for the given task id.
- */
- public void cancelWindowTransition(int taskId) {
try {
- ActivityTaskManager.getService().cancelTaskWindowTransition(taskId);
+ ActivityTaskManager.getService().removeAllVisibleRecentTasks();
} catch (RemoteException e) {
- Log.w(TAG, "Failed to cancel window transition for task=" + taskId, e);
+ Log.w(TAG, "Failed to remove all tasks", e);
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java
deleted file mode 100644
index 0bd89a78cfda..000000000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java
+++ /dev/null
@@ -1,61 +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.shared.system;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-/**
- * Offloads work from other threads by running it in a background thread.
- */
-public class BackgroundExecutor {
-
- private static final BackgroundExecutor sInstance = new BackgroundExecutor();
-
- private final ExecutorService mExecutorService = Executors.newFixedThreadPool(2);
-
- /**
- * @return the static instance of the background executor.
- */
- public static BackgroundExecutor get() {
- return sInstance;
- }
-
- /**
- * Runs the given {@param callable} on one of the background executor threads.
- */
- public <T> Future<T> submit(Callable<T> callable) {
- return mExecutorService.submit(callable);
- }
-
- /**
- * Runs the given {@param runnable} on one of the background executor threads.
- */
- public Future<?> submit(Runnable runnable) {
- return mExecutorService.submit(runnable);
- }
-
- /**
- * Runs the given {@param runnable} on one of the background executor threads. Return
- * {@param result} when the future is resolved.
- */
- public <T> Future<T> submit(Runnable runnable, T result) {
- return mExecutorService.submit(runnable, result);
- }
-}
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 27e4c85e1e02..bf23a49df2c3 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
@@ -36,6 +36,7 @@ import java.io.PrintWriter;
/**
* Manages the input consumer that allows the SystemUI to directly receive input.
+ * TODO: Refactor this for the gesture nav case
*/
public class InputConsumerController {
@@ -99,14 +100,6 @@ public class InputConsumerController {
}
/**
- * @return A controller for the pip input consumer.
- */
- public static InputConsumerController getPipInputConsumer() {
- return new InputConsumerController(WindowManagerGlobal.getWindowManagerService(),
- INPUT_CONSUMER_PIP);
- }
-
- /**
* @return A controller for the recents animation input consumer.
*/
public static InputConsumerController getRecentsAnimationInputConsumer() {
@@ -155,7 +148,6 @@ public class InputConsumerController {
if (mInputEventReceiver == null) {
final InputChannel inputChannel = new InputChannel();
try {
- // TODO(b/113087003): Support Picture-in-picture in multi-display.
mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
} catch (RemoteException e) {
@@ -175,7 +167,6 @@ public class InputConsumerController {
public void unregisterInputConsumer() {
if (mInputEventReceiver != null) {
try {
- // TODO(b/113087003): Support Picture-in-picture in multi-display.
mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
} catch (RemoteException e) {
Log.e(TAG, "Failed to destroy input consumer", e);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index adaee5557a8d..065d0841b1a6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -37,7 +37,7 @@ import java.util.List;
/**
* Tracks all the task stack listeners
*/
-public class TaskStackChangeListeners extends TaskStackListener {
+public class TaskStackChangeListeners {
private static final String TAG = TaskStackChangeListeners.class.getSimpleName();
private static final TaskStackChangeListeners INSTANCE = new TaskStackChangeListeners();
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowCallbacksCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowCallbacksCompat.java
deleted file mode 100644
index de2a3e44841e..000000000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowCallbacksCompat.java
+++ /dev/null
@@ -1,109 +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.shared.system;
-
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.RecordingCanvas;
-import android.view.View;
-import android.view.ViewRootImpl;
-import android.view.WindowCallbacks;
-
-public class WindowCallbacksCompat {
-
- private final WindowCallbacks mWindowCallbacks = new WindowCallbacks() {
- @Override
- public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
- Rect stableInsets) {
- WindowCallbacksCompat.this.onWindowSizeIsChanging(newBounds, fullscreen, systemInsets,
- stableInsets);
- }
-
- @Override
- public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen,
- Rect systemInsets, Rect stableInsets, int resizeMode) {
- WindowCallbacksCompat.this.onWindowDragResizeStart(initialBounds, fullscreen,
- systemInsets, stableInsets, resizeMode);
- }
-
- @Override
- public void onWindowDragResizeEnd() {
- WindowCallbacksCompat.this.onWindowDragResizeEnd();
- }
-
- @Override
- public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
- return WindowCallbacksCompat.this.onContentDrawn(offsetX, offsetY, sizeX, sizeY);
- }
-
- @Override
- public void onRequestDraw(boolean reportNextDraw) {
- WindowCallbacksCompat.this.onRequestDraw(reportNextDraw);
- }
-
- @Override
- public void onPostDraw(RecordingCanvas canvas) {
- WindowCallbacksCompat.this.onPostDraw(canvas);
- }
- };
-
- private final View mView;
-
- public WindowCallbacksCompat(View view) {
- mView = view;
- }
-
- public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
- Rect stableInsets) { }
-
- public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
- Rect stableInsets, int resizeMode) { }
-
- public void onWindowDragResizeEnd() { }
-
- public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
- return false;
- }
-
- public void onRequestDraw(boolean reportNextDraw) {
- if (reportNextDraw) {
- reportDrawFinish();
- }
- }
-
- public void onPostDraw(Canvas canvas) { }
-
- public void reportDrawFinish() {
- mView.getViewRootImpl().reportDrawFinish();
- }
-
- public boolean attach() {
- ViewRootImpl root = mView.getViewRootImpl();
- if (root != null) {
- root.addWindowCallbacks(mWindowCallbacks);
- root.requestInvalidateRootRenderNode();
- return true;
- }
- return false;
- }
-
- public void detach() {
- ViewRootImpl root = mView.getViewRootImpl();
- if (root != null) {
- root.removeWindowCallbacks(mWindowCallbacks);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/FontInterpolator.kt b/packages/SystemUI/src/com/android/keyguard/FontInterpolator.kt
new file mode 100644
index 000000000000..962c0023cf3b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/FontInterpolator.kt
@@ -0,0 +1,222 @@
+/*
+ * 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.graphics.fonts.Font
+import android.graphics.fonts.FontVariationAxis
+import android.util.MathUtils
+
+private const val TAG_WGHT = "wght"
+private const val TAG_ITAL = "ital"
+
+private const val FONT_WEIGHT_MAX = 1000f
+private const val FONT_WEIGHT_MIN = 0f
+private const val FONT_WEIGHT_ANIMATION_STEP = 10f
+private const val FONT_WEIGHT_DEFAULT_VALUE = 400f
+
+private const val FONT_ITALIC_MAX = 1f
+private const val FONT_ITALIC_MIN = 0f
+private const val FONT_ITALIC_ANIMATION_STEP = 0.1f
+private const val FONT_ITALIC_DEFAULT_VALUE = 0f
+
+/**
+ * Provide interpolation of two fonts by adjusting font variation settings.
+ */
+class FontInterpolator {
+
+ /**
+ * Cache key for the interpolated font.
+ *
+ * This class is mutable for recycling.
+ */
+ private data class InterpKey(var l: Font?, var r: Font?, var progress: Float) {
+ fun set(l: Font, r: Font, progress: Float) {
+ this.l = l
+ this.r = r
+ this.progress = progress
+ }
+ }
+
+ /**
+ * Cache key for the font that has variable font.
+ *
+ * This class is mutable for recycling.
+ */
+ private data class VarFontKey(
+ var sourceId: Int,
+ var index: Int,
+ val sortedAxes: MutableList<FontVariationAxis>
+ ) {
+ constructor(font: Font, axes: List<FontVariationAxis>):
+ this(font.sourceIdentifier,
+ font.ttcIndex,
+ axes.toMutableList().apply { sortBy { it.tag } }
+ )
+
+ fun set(font: Font, axes: List<FontVariationAxis>) {
+ sourceId = font.sourceIdentifier
+ index = font.ttcIndex
+ sortedAxes.clear()
+ sortedAxes.addAll(axes)
+ sortedAxes.sortBy { it.tag }
+ }
+ }
+
+ // Font interpolator has two level caches: one for input and one for font with different
+ // variation settings. No synchronization is needed since FontInterpolator is not designed to be
+ // thread-safe and can be used only on UI thread.
+ private val interpCache = hashMapOf<InterpKey, Font>()
+ private val verFontCache = hashMapOf<VarFontKey, Font>()
+
+ // Mutable keys for recycling.
+ private val tmpInterpKey = InterpKey(null, null, 0f)
+ private val tmpVarFontKey = VarFontKey(0, 0, mutableListOf())
+
+ /**
+ * Linear interpolate the font variation settings.
+ */
+ fun lerp(start: Font, end: Font, progress: Float): Font {
+ if (progress == 0f) {
+ return start
+ } else if (progress == 1f) {
+ return end
+ }
+
+ val startAxes = start.axes ?: EMPTY_AXES
+ val endAxes = end.axes ?: EMPTY_AXES
+
+ if (startAxes.isEmpty() && endAxes.isEmpty()) {
+ return start
+ }
+
+ // Check we already know the result. This is commonly happens since we draws the different
+ // text chunks with the same font.
+ tmpInterpKey.set(start, end, progress)
+ val cachedFont = interpCache[tmpInterpKey]
+ if (cachedFont != null) {
+ return cachedFont
+ }
+
+ // General axes interpolation takes O(N log N), this is came from sorting the axes. Usually
+ // this doesn't take much time since the variation axes is usually up to 5. If we need to
+ // support more number of axes, we may want to preprocess the font and store the sorted axes
+ // and also pre-fill the missing axes value with default value from 'fvar' table.
+ val newAxes = lerp(startAxes, endAxes) { tag, startValue, endValue ->
+ when (tag) {
+ // TODO: Good to parse 'fvar' table for retrieving default value.
+ TAG_WGHT -> adjustWeight(
+ MathUtils.lerp(
+ startValue ?: FONT_WEIGHT_DEFAULT_VALUE,
+ endValue ?: FONT_WEIGHT_DEFAULT_VALUE,
+ progress))
+ TAG_ITAL -> adjustItalic(
+ MathUtils.lerp(
+ startValue ?: FONT_ITALIC_DEFAULT_VALUE,
+ endValue ?: FONT_ITALIC_DEFAULT_VALUE,
+ progress))
+ else -> {
+ require(startValue != null && endValue != null) {
+ "Unable to interpolate due to unknown default axes value : $tag"
+ }
+ MathUtils.lerp(startValue, endValue, progress)
+ }
+ }
+ }
+
+ // Check if we already make font for this axes. This is typically happens if the animation
+ // happens backward.
+ tmpVarFontKey.set(start, newAxes)
+ val axesCachedFont = verFontCache[tmpVarFontKey]
+ if (axesCachedFont != null) {
+ interpCache[InterpKey(start, end, progress)] = axesCachedFont
+ return axesCachedFont
+ }
+
+ // This is the first time to make the font for the axes. Build and store it to the cache.
+ // Font.Builder#build won't throw IOException since creating fonts from existing fonts will
+ // not do any IO work.
+ val newFont = Font.Builder(start)
+ .setFontVariationSettings(newAxes.toTypedArray())
+ .build()
+ interpCache[InterpKey(start, end, progress)] = newFont
+ verFontCache[VarFontKey(start, newAxes)] = newFont
+ return newFont
+ }
+
+ private fun lerp(
+ start: Array<FontVariationAxis>,
+ end: Array<FontVariationAxis>,
+ filter: (tag: String, left: Float?, right: Float?) -> Float
+ ): List<FontVariationAxis> {
+ // Safe to modify result of Font#getAxes since it returns cloned object.
+ start.sortBy { axis -> axis.tag }
+ end.sortBy { axis -> axis.tag }
+
+ val result = mutableListOf<FontVariationAxis>()
+ var i = 0
+ var j = 0
+ while (i < start.size || j < end.size) {
+ val tagA = if (i < start.size) start[i].tag else null
+ val tagB = if (j < end.size) end[j].tag else null
+
+ val comp = when {
+ tagA == null -> 1
+ tagB == null -> -1
+ else -> tagA.compareTo(tagB)
+ }
+
+ val axis = when {
+ comp == 0 -> {
+ val v = filter(tagA!!, start[i++].styleValue, end[j++].styleValue)
+ FontVariationAxis(tagA, v)
+ }
+ comp < 0 -> {
+ val v = filter(tagA!!, start[i++].styleValue, null)
+ FontVariationAxis(tagA, v)
+ }
+ else -> { // comp > 0
+ val v = filter(tagB!!, null, end[j++].styleValue)
+ FontVariationAxis(tagB, v)
+ }
+ }
+
+ result.add(axis)
+ }
+ return result
+ }
+
+ // For the performance reasons, we animate weight with FONT_WEIGHT_ANIMATION_STEP. This helps
+ // Cache hit ratio in the Skia glyph cache.
+ private fun adjustWeight(value: Float) =
+ coerceInWithStep(value, FONT_WEIGHT_MIN, FONT_WEIGHT_MAX, FONT_WEIGHT_ANIMATION_STEP)
+
+ // For the performance reasons, we animate italic with FONT_ITALIC_ANIMATION_STEP. This helps
+ // Cache hit ratio in the Skia glyph cache.
+ private fun adjustItalic(value: Float) =
+ coerceInWithStep(value, FONT_ITALIC_MIN, FONT_ITALIC_MAX, FONT_ITALIC_ANIMATION_STEP)
+
+ private fun coerceInWithStep(v: Float, min: Float, max: Float, step: Float) =
+ (v.coerceIn(min, max) / step).toInt() * step
+
+ companion object {
+ private val EMPTY_AXES = arrayOf<FontVariationAxis>()
+
+ // Returns true if given two font instance can be interpolated.
+ fun canInterpolate(start: Font, end: Font) =
+ start.ttcIndex == end.ttcIndex && start.sourceIdentifier == end.sourceIdentifier
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/GradientTextClock.java b/packages/SystemUI/src/com/android/keyguard/GradientTextClock.java
index 7cf1bd0b3e79..3942c60a58e9 100644
--- a/packages/SystemUI/src/com/android/keyguard/GradientTextClock.java
+++ b/packages/SystemUI/src/com/android/keyguard/GradientTextClock.java
@@ -16,12 +16,17 @@
package com.android.keyguard;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.widget.TextClock;
+import kotlin.Unit;
+
/**
* Displays the time with the hour positioned above the minutes. (ie: 09 above 30 is 9:30)
* The time's text color is a gradient that changes its colors based on its controller.
@@ -30,6 +35,8 @@ public class GradientTextClock extends TextClock {
private int[] mGradientColors;
private float[] mPositions;
+ private TextAnimator mTextAnimator = null;
+
public GradientTextClock(Context context) {
this(context, null, 0, 0);
}
@@ -74,6 +81,24 @@ public class GradientTextClock extends TextClock {
super.setFormat24Hour(FORMAT_24);
}
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (mTextAnimator == null) {
+ mTextAnimator = new TextAnimator(getLayout(), () -> {
+ invalidate();
+ return Unit.INSTANCE;
+ });
+ } else {
+ mTextAnimator.updateLayout(getLayout());
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ mTextAnimator.draw(canvas);
+ }
+
public void setGradientColors(int[] colors) {
mGradientColors = colors;
updatePaint();
@@ -83,11 +108,33 @@ public class GradientTextClock extends TextClock {
mPositions = positions;
}
+ /**
+ * Set text style with animation.
+ *
+ * By passing -1 to weight, the view preserve the current weight.
+ * By passing -1 to textSize, the view preserve the current text size.
+ *
+ * @param weight text weight.
+ * @param textSize font size.
+ * @param animate true for changing text style with animation, otherwise false.
+ */
+ public void setTextStyle(
+ @IntRange(from = 0, to = 1000) int weight,
+ @FloatRange(from = 0) float textSize,
+ boolean animate) {
+ if (mTextAnimator != null) {
+ mTextAnimator.setTextStyle(weight, textSize, animate, -1, null);
+ }
+ }
+
private void updatePaint() {
- getPaint().setShader(
- new LinearGradient(
- getX(), getY(), getX(), getMeasuredHeight() + getY(),
- mGradientColors, mPositions, Shader.TileMode.REPEAT));
+ Shader shader = new LinearGradient(
+ getX(), getY(), getX(), getMeasuredHeight() + getY(), mGradientColors, mPositions,
+ Shader.TileMode.REPEAT);
+ getPaint().setShader(shader);
+ if (mTextAnimator != null) {
+ mTextAnimator.setShader(shader);
+ }
}
private final OnLayoutChangeListener mOnLayoutChangeListener =
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 628193dc305d..5b89f7f46772 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -22,6 +22,7 @@ import android.text.format.DateFormat;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.FrameLayout;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.clock.ClockManager;
@@ -30,6 +31,9 @@ import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.util.ViewController;
@@ -51,6 +55,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
private final ClockManager mClockManager;
private final KeyguardSliceViewController mKeyguardSliceViewController;
private final NotificationIconAreaController mNotificationIconAreaController;
+ private FrameLayout mNewLockscreenClockFrame;
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
@@ -114,6 +119,7 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
mColorExtractor.addOnColorsChangedListener(mColorsListener);
mView.updateColors(getGradientColors());
updateAodIcons();
+ mNewLockscreenClockFrame = mView.findViewById(R.id.new_lockscreen_clock_view);
}
@Override
@@ -180,6 +186,21 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
/**
+ * Update position of the view, with optional animation. Move the slice view and the clock
+ * slightly towards the center in order to prevent burn-in. Y positioning occurs at the
+ * view parent level.
+ */
+ void updatePosition(int x, AnimationProperties props, boolean animate) {
+ x = Math.abs(x);
+ if (mNewLockscreenClockFrame != null) {
+ PropertyAnimator.setProperty(mNewLockscreenClockFrame, AnimatableProperty.TRANSLATION_X,
+ -x, props, animate);
+ }
+ mKeyguardSliceViewController.updatePosition(x, props, animate);
+ mNotificationIconAreaController.updatePosition(x, props, animate);
+ }
+
+ /**
* Update lockscreen mode that may change clock display.
*/
void updateLockScreenMode(int mode) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index cc8bf4f2d028..2cdd7f117594 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -154,8 +154,8 @@ public class KeyguardSimPinViewController
}
mView.resetPasswordText(true /* animate */,
/* announce */
- result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS);
- if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
+ result.getResult() != PinResult.PIN_RESULT_TYPE_SUCCESS);
+ if (result.getResult() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
mKeyguardUpdateMonitor.reportSimUnlocked(mSubId);
mRemainingAttempts = -1;
mShowDefaultMessage = true;
@@ -163,7 +163,7 @@ public class KeyguardSimPinViewController
true, KeyguardUpdateMonitor.getCurrentUser());
} else {
mShowDefaultMessage = false;
- if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
+ if (result.getResult() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
if (result.getAttemptsRemaining() <= 2) {
// this is getting critical - show dialog
getSimRemainingAttemptsDialog(
@@ -289,20 +289,14 @@ public class KeyguardSimPinViewController
@Override
public void run() {
if (DEBUG) {
- Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")");
+ Log.v(TAG, "call supplyIccLockPin(subid=" + mSubId + ")");
}
- TelephonyManager telephonyManager =
- mTelephonyManager.createForSubscriptionId(mSubId);
- final PinResult result = telephonyManager.supplyPinReportPinResult(mPin);
- if (result == null) {
- Log.e(TAG, "Error result for supplyPinReportResult.");
- mView.post(() -> onSimCheckResponse(PinResult.getDefaultFailedResult()));
- } else {
- if (DEBUG) {
- Log.v(TAG, "supplyPinReportResult returned: " + result.toString());
- }
- mView.post(() -> onSimCheckResponse(result));
+ TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(mSubId);
+ final PinResult result = telephonyManager.supplyIccLockPin(mPin);
+ if (DEBUG) {
+ Log.v(TAG, "supplyIccLockPin returned: " + result.toString());
}
+ mView.post(() -> onSimCheckResponse(result));
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index a87374939ba6..adb4c13b74d5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -267,8 +267,8 @@ public class KeyguardSimPukViewController
}
mView.resetPasswordText(true /* animate */,
/* announce */
- result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS);
- if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
+ result.getResult() != PinResult.PIN_RESULT_TYPE_SUCCESS);
+ if (result.getResult() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
mKeyguardUpdateMonitor.reportSimUnlocked(mSubId);
mRemainingAttempts = -1;
mShowDefaultMessage = true;
@@ -277,7 +277,7 @@ public class KeyguardSimPukViewController
true, KeyguardUpdateMonitor.getCurrentUser());
} else {
mShowDefaultMessage = false;
- if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
+ if (result.getResult() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
// show message
mMessageAreaController.setMessage(mView.getPukPasswordErrorMessage(
result.getAttemptsRemaining(), false,
@@ -390,23 +390,15 @@ public class KeyguardSimPukViewController
@Override
public void run() {
- if (DEBUG) Log.v(TAG, "call supplyPukReportResult()");
+ if (DEBUG) {
+ Log.v(TAG, "call supplyIccLockPuk(subid=" + mSubId + ")");
+ }
TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(mSubId);
- final PinResult result = telephonyManager.supplyPukReportPinResult(mPuk, mPin);
- if (result == null) {
- Log.e(TAG, "Error result for supplyPukReportResult.");
- mView.post(() -> onSimLockChangedResponse(PinResult.getDefaultFailedResult()));
- } else {
- if (DEBUG) {
- Log.v(TAG, "supplyPukReportResult returned: " + result.toString());
- }
- mView.post(new Runnable() {
- @Override
- public void run() {
- onSimLockChangedResponse(result);
- }
- });
+ final PinResult result = telephonyManager.supplyIccLockPuk(mPuk, mPin);
+ if (DEBUG) {
+ Log.v(TAG, "supplyIccLockPuk returned: " + result.toString());
}
+ mView.post(() -> onSimLockChangedResponse(result));
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
index 8b55b06e5e5e..02b18b28a5ea 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
@@ -42,6 +42,9 @@ import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.ViewController;
@@ -199,6 +202,13 @@ public class KeyguardSliceViewController extends ViewController<KeyguardSliceVie
Trace.endSection();
}
+ /**
+ * Update position of the view, with optional animation
+ */
+ void updatePosition(int x, AnimationProperties props, boolean animate) {
+ PropertyAnimator.setProperty(mView, AnimatableProperty.TRANSLATION_X, x, props, animate);
+ }
+
void showSlice(Slice slice) {
Trace.beginSection("KeyguardSliceViewController#showSlice");
if (slice == null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index cc0d1b651aaf..cc7b8322d190 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -186,12 +186,23 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
/**
* Update position of the view with an optional animation
*/
- public void updatePosition(int clockTranslationX, int clockTranslationY,
- boolean animateClock) {
- PropertyAnimator.setProperty(mView, AnimatableProperty.X,
- clockTranslationX, CLOCK_ANIMATION_PROPERTIES, animateClock);
- PropertyAnimator.setProperty(mView, AnimatableProperty.Y,
- clockTranslationY, CLOCK_ANIMATION_PROPERTIES, animateClock);
+ public void updatePosition(int x, int y, boolean animate) {
+ PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, CLOCK_ANIMATION_PROPERTIES,
+ animate);
+
+ if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
+ // reset any prior movement
+ PropertyAnimator.setProperty(mView, AnimatableProperty.X, 0,
+ CLOCK_ANIMATION_PROPERTIES, animate);
+
+ mKeyguardClockSwitchController.updatePosition(x, CLOCK_ANIMATION_PROPERTIES, animate);
+ } else {
+ // reset any prior movement
+ mKeyguardClockSwitchController.updatePosition(0, CLOCK_ANIMATION_PROPERTIES, animate);
+
+ PropertyAnimator.setProperty(mView, AnimatableProperty.X, x,
+ CLOCK_ANIMATION_PROPERTIES, animate);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0e6bc24b02d6..42680e663849 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -238,6 +238,16 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private final boolean mIsAutomotive;
private final AuthController mAuthController;
private final StatusBarStateController mStatusBarStateController;
+ private int mStatusBarState;
+ private final StatusBarStateController.StateListener mStatusBarStateControllerListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ mStatusBarState = newState;
+ updateBiometricListeningState();
+ }
+ };
+
HashMap<Integer, SimData> mSimDatas = new HashMap<>();
HashMap<Integer, ServiceState> mServiceStates = new HashMap<Integer, ServiceState>();
@@ -247,7 +257,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean mCredentialAttempted;
private boolean mKeyguardGoingAway;
private boolean mGoingToSleep;
- private boolean mBouncer;
+ private boolean mBouncer; // true if bouncerIsOrWillBeShowing
private boolean mAuthInterruptActive;
private boolean mNeedsSlowUnlockTransition;
private boolean mHasLockscreenWallpaper;
@@ -289,6 +299,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private final DevicePolicyManager mDevicePolicyManager;
private final BroadcastDispatcher mBroadcastDispatcher;
private boolean mLogoutEnabled;
+ // cached value to avoid IPCs
+ private boolean mIsUdfpsEnrolled;
// If the user long pressed the lock icon, disabling face auth for the current session.
private boolean mLockIconPressed;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -1593,6 +1605,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mBroadcastDispatcher = broadcastDispatcher;
mRingerModeTracker = ringerModeTracker;
mStatusBarStateController = statusBarStateController;
+ mStatusBarStateController.addCallback(mStatusBarStateControllerListener);
+ mStatusBarState = mStatusBarStateController.getState();
mLockPatternUtils = lockPatternUtils;
mAuthController = authController;
dumpManager.registerDumpable(getClass().getName(), this);
@@ -1857,7 +1871,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private void updateLockScreenMode() {
mLockScreenMode = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.SHOW_NEW_LOCKSCREEN, mAuthController.isUdfpsEnrolled() ? 1 : 0);
+ Settings.Global.SHOW_NEW_LOCKSCREEN,
+ isUdfpsEnrolled() ? 1 : 0);
+ }
+
+ private void updateUdfpsEnrolled(int userId) {
+ mIsUdfpsEnrolled = mAuthController.isUdfpsEnrolled(userId);
+ }
+ public boolean isUdfpsEnrolled() {
+ return mIsUdfpsEnrolled;
}
private final UserSwitchObserver mUserSwitchObserver = new UserSwitchObserver() {
@@ -1895,7 +1917,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return;
}
- boolean shouldListenForFingerprint = shouldListenForFingerprint();
+ boolean shouldListenForFingerprint =
+ isUdfpsEnrolled() ? shouldListenForUdfps() : shouldListenForFingerprint();
boolean runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
|| mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING;
if (runningOrRestarting && !shouldListenForFingerprint) {
@@ -1992,12 +2015,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
return shouldListen;
}
+ @VisibleForTesting
+ boolean shouldListenForUdfps() {
+ return shouldListenForFingerprint()
+ && !mBouncer
+ && mStatusBarState != StatusBarState.SHADE_LOCKED
+ && mStatusBarState != StatusBarState.FULLSCREEN_USER_SWITCHER
+ && mStrongAuthTracker.hasUserAuthenticatedSinceBoot();
+ }
+
/**
* If face auth is allows to scan on this exact moment.
*/
public boolean shouldListenForFace() {
- final boolean statusBarShadeLocked =
- mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED;
+ final boolean statusBarShadeLocked = mStatusBarState == StatusBarState.SHADE_LOCKED;
final boolean awakeKeyguard = mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep
&& !statusBarShadeLocked;
final int user = getCurrentUser();
@@ -2098,6 +2129,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
int userId = getCurrentUser();
+ updateUdfpsEnrolled(userId);
if (isUnlockWithFingerprintPossible(userId)) {
if (mFingerprintCancelSignal != null) {
mFingerprintCancelSignal.cancel();
@@ -2582,13 +2614,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
*
* @see #sendKeyguardBouncerChanged(boolean)
*/
- private void handleKeyguardBouncerChanged(int bouncer) {
+ private void handleKeyguardBouncerChanged(int bouncerVisible) {
Assert.isMainThread();
- if (DEBUG) Log.d(TAG, "handleKeyguardBouncerChanged(" + bouncer + ")");
- boolean isBouncer = (bouncer == 1);
- mBouncer = isBouncer;
+ if (DEBUG) Log.d(TAG, "handleKeyguardBouncerChanged(" + bouncerVisible + ")");
+ mBouncer = bouncerVisible == 1;
- if (isBouncer) {
+ if (mBouncer) {
// If the bouncer is shown, always clear this flag. This can happen in the following
// situations: 1) Default camera with SHOW_WHEN_LOCKED is not chosen yet. 2) Secure
// camera requests dismiss keyguard (tapping on photos for example). When these happen,
@@ -2601,7 +2632,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onKeyguardBouncerChanged(isBouncer);
+ cb.onKeyguardBouncerChanged(mBouncer);
}
}
updateBiometricListeningState();
@@ -2734,10 +2765,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
/**
* @see #handleKeyguardBouncerChanged(int)
*/
- public void sendKeyguardBouncerChanged(boolean showingBouncer) {
- if (DEBUG) Log.d(TAG, "sendKeyguardBouncerChanged(" + showingBouncer + ")");
+ public void sendKeyguardBouncerChanged(boolean bouncerIsOrWillBeShowing) {
+ if (DEBUG) Log.d(TAG, "sendKeyguardBouncerChanged(" + bouncerIsOrWillBeShowing + ")");
Message message = mHandler.obtainMessage(MSG_KEYGUARD_BOUNCER_CHANGED);
- message.arg1 = showingBouncer ? 1 : 0;
+ message.arg1 = bouncerIsOrWillBeShowing ? 1 : 0;
message.sendToTarget();
}
@@ -3069,6 +3100,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
+ " expected=" + (shouldListenForFingerprint() ? 1 : 0));
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
+ pw.println(" udfpsEnrolled=" + isUdfpsEnrolled());
+ if (isUdfpsEnrolled()) {
+ pw.println(" shouldListenForUdfps=" + shouldListenForUdfps());
+ pw.println(" bouncerVisible=" + mBouncer);
+ pw.println(" mStatusBarState="
+ + StatusBarState.toShortString(mStatusBarState));
+ }
}
if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
final int userId = ActivityManager.getCurrentUser();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 3c5ecebd5990..b722deab528a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -94,7 +94,8 @@ public class KeyguardUpdateMonitorCallback {
/**
* Called when the keyguard enters or leaves bouncer mode.
- * @param bouncer if true, keyguard is now in bouncer mode.
+ * @param bouncer if true, keyguard is showing the bouncer or transitioning from/to bouncer
+ * mode.
*/
public void onKeyguardBouncerChanged(boolean bouncer) { }
diff --git a/packages/SystemUI/src/com/android/keyguard/TextAnimator.kt b/packages/SystemUI/src/com/android/keyguard/TextAnimator.kt
new file mode 100644
index 000000000000..e4c3dcde3bd4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/TextAnimator.kt
@@ -0,0 +1,141 @@
+/*
+ * 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.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.TimeInterpolator
+import android.animation.ValueAnimator
+import android.graphics.Canvas
+import android.graphics.Shader
+import android.text.Layout
+
+private const val TAG_WGHT = "wght"
+private const val DEFAULT_ANIMATION_DURATION: Long = 1000
+
+/**
+ * This class provides text animation between two styles.
+ *
+ * Currently this class can provide text style animation for text weight and text size. For example
+ * the simple view that draws text with animating text size is like as follows:
+ *
+ * <pre>
+ * <code>
+ * class SimpleTextAnimation : View {
+ * @JvmOverloads constructor(...)
+ *
+ * private val layout: Layout = ... // Text layout, e.g. StaticLayout.
+ *
+ * // TextAnimator tells us when needs to be invalidate.
+ * private val animator = TextAnimator(layout) { invalidate() }
+ *
+ * override fun onDraw(canvas: Canvas) = animator.draw(canvas)
+ *
+ * // Change the text size with animation.
+ * fun setTextSize(sizePx: Float, animate: Boolean) {
+ * animator.setTextStyle(-1 /* unchanged weight */, sizePx, animate)
+ * }
+ * }
+ * </code>
+ * </pre>
+ */
+class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
+ // Following two members are for mutable for testing purposes.
+ internal var textInterpolator: TextInterpolator = TextInterpolator(layout)
+ internal var animator: ValueAnimator = ValueAnimator.ofFloat(1f).apply {
+ duration = DEFAULT_ANIMATION_DURATION
+ addUpdateListener {
+ textInterpolator.progress = it.animatedValue as Float
+ invalidateCallback()
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) = textInterpolator.rebase()
+ override fun onAnimationCancel(animation: Animator?) = textInterpolator.rebase()
+ })
+ }
+
+ fun updateLayout(layout: Layout) {
+ textInterpolator.layout = layout
+ }
+
+ var shader: Shader
+ get() = textInterpolator.basePaint.shader.also {
+ require(it === textInterpolator.targetPaint.shader) {
+ "base and target paint has different shader. Usually shader is not interpolatable."
+ }
+ }
+ set(value) {
+ textInterpolator.basePaint.shader = value
+ textInterpolator.targetPaint.shader = value
+ // Shader doesn't change the text layout, so no need to call onTargetPaintModified or
+ // onBasePaintModified
+ }
+
+ fun draw(c: Canvas) = textInterpolator.draw(c)
+
+ /**
+ * Set text style with animation.
+ *
+ * By passing -1 to weight, the view preserve the current weight.
+ * By passing -1 to textSize, the view preserve the current text size.
+ * Bu passing -1 to duration, the default text animation, 1000ms, is used.
+ * By passing false to animate, the text will be updated without animation.
+ *
+ * @param weight an optional text weight.
+ * @param textSize an optional font size.
+ * @param animate an optional boolean indicating true for showing style transition as animation,
+ * false for immediate style transition. True by default.
+ * @param duration an optional animation duration in milliseconds. This is ignored if animate is
+ * false.
+ * @param interpolator an optional time interpolator. If null is passed, last set interpolator
+ * will be used. This is ignored if animate is false.
+ */
+ fun setTextStyle(
+ weight: Int = -1,
+ textSize: Float = -1f,
+ animate: Boolean = true,
+ duration: Long = -1L,
+ interpolator: TimeInterpolator? = null
+ ) {
+ if (animate) {
+ animator.cancel()
+ textInterpolator.rebase()
+ }
+
+ if (textSize >= 0) {
+ textInterpolator.targetPaint.textSize = textSize
+ }
+ if (weight >= 0) {
+ textInterpolator.targetPaint.fontVariationSettings = "'$TAG_WGHT' $weight"
+ }
+ textInterpolator.onTargetPaintModified()
+
+ if (animate) {
+ animator.duration = if (duration == -1L) {
+ DEFAULT_ANIMATION_DURATION
+ } else {
+ duration
+ }
+ interpolator?.let { animator.interpolator = it }
+ animator.start()
+ } else {
+ // No animation is requested, thus set base and target state to the same state.
+ textInterpolator.progress = 1f
+ textInterpolator.rebase()
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt b/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt
new file mode 100644
index 000000000000..51148f3c93af
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/TextInterpolator.kt
@@ -0,0 +1,417 @@
+/*
+ * 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.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.fonts.Font
+import android.graphics.text.PositionedGlyphs
+import android.graphics.text.TextRunShaper
+import android.text.Layout
+import android.util.MathUtils
+import java.lang.Math.max
+
+/**
+ * Provide text style linear interpolation for plain text.
+ */
+class TextInterpolator(layout: Layout) {
+ /**
+ * Returns base paint used for interpolation.
+ *
+ * Once you modified the style parameters, you have to call reshapeText to recalculate base text
+ * layout.
+ *
+ * @return a paint object.
+ */
+ val basePaint = Paint(layout.paint)
+
+ /**
+ * Returns target paint used for interpolation.
+ *
+ * Once you modified the style parameters, you have to call reshapeText to recalculate target
+ * text layout.
+ *
+ * @return a paint object
+ */
+ val targetPaint = Paint(layout.paint)
+
+ /**
+ * A class represents a single font run.
+ *
+ * A font run is a range that will be drawn with the same font.
+ */
+ private data class FontRun(
+ val start: Int, // inclusive
+ val end: Int, // exclusive
+ var baseFont: Font,
+ var targetFont: Font
+ ) {
+ val length: Int get() = end - start
+ }
+
+ /**
+ * A class represents text layout of a single line.
+ */
+ private class Line(
+ val glyphIds: IntArray,
+ val baseX: FloatArray, // same length as glyphIds
+ val baseY: FloatArray, // same length as glyphIds
+ val targetX: FloatArray, // same length as glyphIds
+ val targetY: FloatArray, // same length as glyphIds
+ val fontRuns: List<FontRun>
+ )
+
+ private var lines = listOf<Line>()
+ private val fontInterpolator = FontInterpolator()
+
+ // Recycling object for glyph drawing. Will be extended for the longest font run if needed.
+ private val tmpDrawPaint = Paint()
+ private var tmpPositionArray = FloatArray(20)
+
+ /**
+ * The progress position of the interpolation.
+ *
+ * The 0f means the start state, 1f means the end state.
+ */
+ var progress: Float = 0f
+
+ /**
+ * The layout used for drawing text.
+ *
+ * Only non-styled text is supported. Even if the given layout is created from Spanned, the
+ * span information is not used.
+ *
+ * The paint objects used for interpolation are not changed by this method call.
+ *
+ * Note: disabling ligature is strongly recommended if you give extra letter spacing since they
+ * may be disjointed based on letter spacing value and cannot be interpolated. Animator will
+ * throw runtime exception if they cannot be interpolated.
+ */
+ var layout: Layout = layout
+ get() = field
+ set(value) {
+ field = value
+ shapeText(value)
+ }
+
+ init {
+ // shapeText needs to be called after all members are initialized.
+ shapeText(layout)
+ }
+
+ /**
+ * Recalculate internal text layout for interpolation.
+ *
+ * Whenever you modifies target paint, you have to call this method to recalculate internal text
+ * layout used for interpolation.
+ */
+ fun onTargetPaintModified() {
+ updatePositionsAndFonts(shapeText(layout, targetPaint), updateBase = false)
+ }
+
+ /**
+ * Recalculate internal text layout for interpolation.
+ *
+ * Whenever you modifies base paint, you have to call this method to recalculate internal text
+ * layout used for interpolation.
+ */
+ fun onBasePaintModified() {
+ updatePositionsAndFonts(shapeText(layout, basePaint), updateBase = true)
+ }
+
+ /**
+ * Rebase the base state to the middle of the interpolation.
+ *
+ * The text interpolator does not calculate all the text position by text shaper due to
+ * performance reasons. Instead, the text interpolator shape the start and end state and
+ * calculate text position of the middle state by linear interpolation. Due to this trick,
+ * the text positions of the middle state is likely different from the text shaper result.
+ * So, if you want to start animation from the middle state, you will see the glyph jumps due to
+ * this trick, i.e. the progress 0.5 of interpolation between weight 400 and 700 is different
+ * from text shape result of weight 550.
+ *
+ * After calling this method, do not call onBasePaintModified() since it reshape the text and
+ * update the base state. As in above notice, the text shaping result at current progress is
+ * different shaped result. By calling onBasePaintModified(), you may see the glyph jump.
+ *
+ * By calling this method, the progress will be reset to 0.
+ *
+ * This API is useful to continue animation from the middle of the state. For example, if you
+ * animate weight from 200 to 400, then if you want to move back to 200 at the half of the
+ * animation, it will look like
+ *
+ * <pre>
+ * <code>
+ * val interp = TextInterpolator(layout)
+ *
+ * // Interpolate between weight 200 to 400.
+ * interp.basePaint.fontVariationSettings = "'wght' 200"
+ * interp.onBasePaintModified()
+ * interp.targetPaint.fontVariationSettings = "'wght' 400"
+ * interp.onTargetPaintModified()
+ *
+ * // animate
+ * val animator = ValueAnimator.ofFloat(1f).apply {
+ * addUpdaterListener {
+ * interp.progress = it.animateValue as Float
+ * }
+ * }.start()
+ *
+ * // Here, assuming you receive some event and want to start new animation from current
+ * // state.
+ * OnSomeEvent {
+ * animator.cancel()
+ *
+ * // start another animation from the current state.
+ * interp.rebase() // Use current state as base state.
+ * interp.targetPaint.fontVariationSettings = "'wght' 200" // set new target
+ * interp.onTargetPaintModified() // reshape target
+ *
+ * // Here the textInterpolator interpolate from 'wght' from 300 to 200 if the current
+ * // progress is 0.5
+ * animator.start()
+ * }
+ * </code>
+ * </pre>
+ *
+ */
+ fun rebase() {
+ if (progress == 0f) {
+ return
+ } else if (progress == 1f) {
+ basePaint.set(targetPaint)
+ } else {
+ lerp(basePaint, targetPaint, progress, tmpDrawPaint)
+ basePaint.set(tmpDrawPaint)
+ }
+
+ lines.forEach { line ->
+ for (i in line.baseX.indices) {
+ line.baseX[i] = MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
+ line.baseY[i] = MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
+ }
+ line.fontRuns.forEach {
+ it.baseFont = fontInterpolator.lerp(it.baseFont, it.targetFont, progress)
+ }
+ }
+
+ progress = 0f
+ }
+
+ /**
+ * Draws interpolated text at the given progress.
+ *
+ * @param canvas a canvas.
+ */
+ fun draw(canvas: Canvas) {
+ lerp(basePaint, targetPaint, progress, tmpDrawPaint)
+ lines.forEachIndexed { lineNo, line ->
+ canvas.save()
+ try {
+ // Move to drawing origin.
+ val origin = layout.getDrawOrigin(lineNo)
+ canvas.translate(origin, layout.getLineBaseline(lineNo).toFloat())
+
+ line.fontRuns.forEach { run ->
+ drawFontRun(canvas, line, run, tmpDrawPaint)
+ }
+ } finally {
+ canvas.restore()
+ }
+ }
+ }
+
+ // Shape text with current paint parameters.
+ private fun shapeText(layout: Layout) {
+ val baseLayout = shapeText(layout, basePaint)
+ val targetLayout = shapeText(layout, targetPaint)
+
+ require(baseLayout.size == targetLayout.size) {
+ "The new layout result has different line count."
+ }
+
+ var maxRunLength = 0
+ lines = baseLayout.zip(targetLayout) { base, target ->
+ require(base.glyphCount() == target.glyphCount()) {
+ "Inconsistent glyph count at line ${lines.size}"
+ }
+
+ val glyphCount = base.glyphCount()
+
+ // Good to recycle the array if the existing array can hold the new layout result.
+ val glyphIds = IntArray(glyphCount) {
+ base.getGlyphId(it).also { baseGlyphId ->
+ require(baseGlyphId == target.getGlyphId(it)) {
+ "Inconsistent glyph ID at $it in line ${lines.size}"
+ }
+ }
+ }
+
+ val baseX = FloatArray(glyphCount) { base.getGlyphX(it) }
+ val baseY = FloatArray(glyphCount) { base.getGlyphY(it) }
+ val targetX = FloatArray(glyphCount) { target.getGlyphX(it) }
+ val targetY = FloatArray(glyphCount) { target.getGlyphY(it) }
+
+ // Calculate font runs
+ val fontRun = mutableListOf<FontRun>()
+ if (glyphCount != 0) {
+ var start = 0
+ var baseFont = base.getFont(start)
+ var targetFont = target.getFont(start)
+ require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
+ "Cannot interpolate font at $start ($baseFont vs $targetFont)"
+ }
+
+ for (i in 1 until glyphCount) {
+ val nextBaseFont = base.getFont(i)
+ val nextTargetFont = target.getFont(i)
+
+ if (baseFont !== nextBaseFont) {
+ require(targetFont !== nextTargetFont) {
+ "Base font has changed at $i but target font has not changed."
+ }
+ // Font transition point. push run and reset context.
+ fontRun.add(FontRun(start, i, baseFont, targetFont))
+ maxRunLength = max(maxRunLength, i - start)
+ baseFont = nextBaseFont
+ targetFont = nextTargetFont
+ start = i
+ require(FontInterpolator.canInterpolate(baseFont, targetFont)) {
+ "Cannot interpolate font at $start ($baseFont vs $targetFont)"
+ }
+ } else { // baseFont === nextBaseFont
+ require(targetFont === nextTargetFont) {
+ "Base font has not changed at $i but target font has changed."
+ }
+ }
+ }
+ fontRun.add(FontRun(start, glyphCount, baseFont, targetFont))
+ maxRunLength = max(maxRunLength, glyphCount - start)
+ }
+ Line(glyphIds, baseX, baseY, targetX, targetY, fontRun)
+ }
+
+ // Update float array used for drawing.
+ if (tmpPositionArray.size < maxRunLength * 2) {
+ tmpPositionArray = FloatArray(maxRunLength * 2)
+ }
+ }
+
+ // Draws single font run.
+ private fun drawFontRun(c: Canvas, line: Line, run: FontRun, paint: Paint) {
+ var arrayIndex = 0
+ for (i in run.start until run.end) {
+ tmpPositionArray[arrayIndex++] =
+ MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
+ tmpPositionArray[arrayIndex++] =
+ MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
+ }
+
+ c.drawGlyphs(
+ line.glyphIds,
+ run.start,
+ tmpPositionArray,
+ 0,
+ run.length,
+ fontInterpolator.lerp(run.baseFont, run.targetFont, progress),
+ paint)
+ }
+
+ private fun updatePositionsAndFonts(
+ layoutResult: List<PositionedGlyphs>,
+ updateBase: Boolean
+ ) {
+ // Update target positions with newly calculated text layout.
+ check(layoutResult.size == lines.size) {
+ "The new layout result has different line count."
+ }
+
+ lines.zip(layoutResult) { line, newGlyphs ->
+ require(newGlyphs.glyphCount() == line.glyphIds.size) {
+ "The new layout has different glyph count."
+ }
+
+ line.fontRuns.forEach { run ->
+ val newFont = newGlyphs.getFont(run.start)
+ for (i in run.start until run.end) {
+ require(newGlyphs.getGlyphId(run.start) == line.glyphIds[run.start]) {
+ "The new layout has different glyph ID at ${run.start}"
+ }
+ require(newFont === newGlyphs.getFont(i)) {
+ "The new layout has different font run." +
+ " $newFont vs ${newGlyphs.getFont(i)} at $i"
+ }
+ }
+
+ // The passing base font and target font is already interpolatable, so just check
+ // new font can be interpolatable with base font.
+ require(FontInterpolator.canInterpolate(newFont, run.baseFont)) {
+ "New font cannot be interpolated with existing font. $newFont, ${run.baseFont}"
+ }
+
+ if (updateBase) {
+ run.baseFont = newFont
+ } else {
+ run.targetFont = newFont
+ }
+ }
+
+ if (updateBase) {
+ for (i in line.baseX.indices) {
+ line.baseX[i] = newGlyphs.getGlyphX(i)
+ line.baseY[i] = newGlyphs.getGlyphY(i)
+ }
+ } else {
+ for (i in line.baseX.indices) {
+ line.targetX[i] = newGlyphs.getGlyphX(i)
+ line.targetY[i] = newGlyphs.getGlyphY(i)
+ }
+ }
+ }
+ }
+
+ // Linear interpolate the paint.
+ private fun lerp(from: Paint, to: Paint, t: Float, out: Paint) {
+ // Currently only font size is interpolated.
+ // TODO(172943390): Add other interpolation or support custom interpolator.
+ out.set(from)
+ out.textSize = MathUtils.lerp(from.textSize, to.textSize, t)
+ }
+
+ // Shape the text and stores the result to out argument.
+ private fun shapeText(layout: Layout, paint: Paint): List<PositionedGlyphs> {
+ val out = mutableListOf<PositionedGlyphs>()
+ for (lineNo in 0 until layout.lineCount) { // Shape all lines.
+ val lineStart = layout.getLineStart(lineNo)
+ val count = layout.getLineEnd(lineNo) - lineStart
+ out.add(TextRunShaper.shapeTextRun(
+ layout.text, // Styles are ignored.
+ lineStart, count, // shape range
+ lineStart, count, // shape context = shape range.
+ 0f, 0f, // the layout offset. Not changed.
+ layout.getParagraphDirection(lineNo) == Layout.DIR_RIGHT_TO_LEFT,
+ paint)) // Use given paint instead of layout's paint for style interpolation.
+ }
+ return out
+ }
+}
+
+private fun Layout.getDrawOrigin(lineNo: Int) =
+ if (getParagraphDirection(lineNo) == Layout.DIR_LEFT_TO_RIGHT) {
+ getLineLeft(lineNo)
+ } else {
+ getLineRight(lineNo)
+ } \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/TimeBasedColorsClockController.java b/packages/SystemUI/src/com/android/keyguard/TimeBasedColorsClockController.java
index 3cbae0a18937..933d338c0736 100644
--- a/packages/SystemUI/src/com/android/keyguard/TimeBasedColorsClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/TimeBasedColorsClockController.java
@@ -71,12 +71,10 @@ public class TimeBasedColorsClockController extends ViewController<GradientTextC
public void setDarkAmount(float darkAmount) {
mDarkAmount = darkAmount;
- // TODO: (b/170228350) currently this relayouts throughout the animation;
- // eventually this should use new Text APIs to animate the variable font weight
refreshTime(System.currentTimeMillis());
int weight = (int) MathUtils.lerp(200, 400, 1f - darkAmount);
- mView.setFontVariationSettings("'wght' " + weight);
+ mView.setTextStyle(weight, -1 /* unchange text size */, true);
}
private int getTimeIndex(long timeInMillis) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index b30103ef9b59..11180d131e70 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -108,18 +108,21 @@ public class SystemUIFactory {
.setPip(mWMComponent.getPip())
.setSplitScreen(mWMComponent.getSplitScreen())
.setOneHanded(mWMComponent.getOneHanded())
- .setShellDump(mWMComponent.getShellDump());
+ .setBubbles(mWMComponent.getBubbles())
+ .setHideDisplayCutout(mWMComponent.getHideDisplayCutout())
+ .setShellDump(mWMComponent.getShellDump())
+ .setAppPairs(mWMComponent.getAppPairs());
} else {
// TODO: Call on prepareSysUIComponentBuilder but not with real components.
builder = builder.setPip(Optional.ofNullable(null))
.setSplitScreen(Optional.ofNullable(null))
.setOneHanded(Optional.ofNullable(null))
- .setShellDump(Optional.ofNullable(null));
+ .setBubbles(Optional.ofNullable(null))
+ .setHideDisplayCutout(Optional.ofNullable(null))
+ .setShellDump(Optional.ofNullable(null))
+ .setAppPairs(Optional.ofNullable(null));
}
- mSysUIComponent = builder
- .setInputConsumerController(mWMComponent.getInputConsumerController())
- .setShellTaskOrganizer(mWMComponent.getShellTaskOrganizer())
- .build();
+ mSysUIComponent = builder.build();
if (initializeComponents) {
mSysUIComponent.init();
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 98424beab14e..c71bb5b0ab22 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -17,20 +17,16 @@
package com.android.systemui.accessibility;
import android.annotation.MainThread;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
-import android.os.RemoteException;
-import android.util.Log;
import android.view.SurfaceControl;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.accessibility.IWindowMagnificationConnection;
-import android.view.accessibility.IWindowMagnificationConnectionCallback;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -146,6 +142,13 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
}
@Override
+ public void onPerformScaleAction(int displayId, float scale) {
+ if (mWindowMagnificationConnectionImpl != null) {
+ mWindowMagnificationConnectionImpl.onPerformScaleAction(displayId, scale);
+ }
+ }
+
+ @Override
public void requestWindowMagnificationConnection(boolean connect) {
if (connect) {
setWindowMagnificationConnection();
@@ -167,85 +170,4 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
mAccessibilityManager.setWindowMagnificationConnection(null);
//TODO: destroy controllers.
}
-
- private static class WindowMagnificationConnectionImpl extends
- IWindowMagnificationConnection.Stub {
-
- private static final String TAG = "WindowMagnificationConnectionImpl";
-
- private IWindowMagnificationConnectionCallback mConnectionCallback;
- private final WindowMagnification mWindowMagnification;
- private final Handler mHandler;
- private final ModeSwitchesController mModeSwitchesController;
-
- WindowMagnificationConnectionImpl(@NonNull WindowMagnification windowMagnification,
- @Main Handler mainHandler, ModeSwitchesController modeSwitchesController) {
- mWindowMagnification = windowMagnification;
- mHandler = mainHandler;
- mModeSwitchesController = modeSwitchesController;
- }
-
- @Override
- public void enableWindowMagnification(int displayId, float scale, float centerX,
- float centerY, IRemoteMagnificationAnimationCallback callback) {
- mHandler.post(
- () -> mWindowMagnification.enableWindowMagnification(displayId, scale, centerX,
- centerY, callback));
- }
-
- @Override
- public void setScale(int displayId, float scale) {
- mHandler.post(() -> mWindowMagnification.setScale(displayId, scale));
- }
-
- @Override
- public void disableWindowMagnification(int displayId,
- IRemoteMagnificationAnimationCallback callback) {
- mHandler.post(() -> mWindowMagnification.disableWindowMagnification(displayId,
- callback));
- }
-
- @Override
- public void moveWindowMagnifier(int displayId, float offsetX, float offsetY) {
- mHandler.post(
- () -> mWindowMagnification.moveWindowMagnifier(displayId, offsetX, offsetY));
- }
-
- @Override
- public void showMagnificationButton(int displayId, int magnificationMode) {
- mHandler.post(
- () -> mModeSwitchesController.showButton(displayId, magnificationMode));
- }
-
- @Override
- public void removeMagnificationButton(int displayId) {
- mHandler.post(
- () -> mModeSwitchesController.removeButton(displayId));
- }
-
- @Override
- public void setConnectionCallback(IWindowMagnificationConnectionCallback callback) {
- mConnectionCallback = callback;
- }
-
- void onWindowMagnifierBoundsChanged(int displayId, Rect frame) {
- if (mConnectionCallback != null) {
- try {
- mConnectionCallback.onWindowMagnifierBoundsChanged(displayId, frame);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to inform bounds changed", e);
- }
- }
- }
-
- void onSourceBoundsChanged(int displayId, Rect sourceBounds) {
- if (mConnectionCallback != null) {
- try {
- mConnectionCallback.onSourceBoundsChanged(displayId, sourceBounds);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to inform source bounds changed", e);
- }
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
new file mode 100644
index 000000000000..be7d75724442
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.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.accessibility;
+
+import android.annotation.NonNull;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.accessibility.IRemoteMagnificationAnimationCallback;
+import android.view.accessibility.IWindowMagnificationConnection;
+import android.view.accessibility.IWindowMagnificationConnectionCallback;
+
+import com.android.systemui.dagger.qualifiers.Main;
+
+/**
+ * Implementation of window magnification connection.
+ *
+ * @see IWindowMagnificationConnection
+ */
+class WindowMagnificationConnectionImpl extends IWindowMagnificationConnection.Stub {
+
+ private static final String TAG = "WindowMagnificationConnectionImpl";
+
+ private IWindowMagnificationConnectionCallback mConnectionCallback;
+ private final WindowMagnification mWindowMagnification;
+ private final Handler mHandler;
+ private final ModeSwitchesController mModeSwitchesController;
+
+ WindowMagnificationConnectionImpl(@NonNull WindowMagnification windowMagnification,
+ @Main Handler mainHandler, ModeSwitchesController modeSwitchesController) {
+ mWindowMagnification = windowMagnification;
+ mHandler = mainHandler;
+ mModeSwitchesController = modeSwitchesController;
+ }
+
+ @Override
+ public void enableWindowMagnification(int displayId, float scale, float centerX,
+ float centerY, IRemoteMagnificationAnimationCallback callback) {
+ mHandler.post(
+ () -> mWindowMagnification.enableWindowMagnification(displayId, scale, centerX,
+ centerY, callback));
+ }
+
+ @Override
+ public void setScale(int displayId, float scale) {
+ mHandler.post(() -> mWindowMagnification.setScale(displayId, scale));
+ }
+
+ @Override
+ public void disableWindowMagnification(int displayId,
+ IRemoteMagnificationAnimationCallback callback) {
+ mHandler.post(() -> mWindowMagnification.disableWindowMagnification(displayId,
+ callback));
+ }
+
+ @Override
+ public void moveWindowMagnifier(int displayId, float offsetX, float offsetY) {
+ mHandler.post(
+ () -> mWindowMagnification.moveWindowMagnifier(displayId, offsetX, offsetY));
+ }
+
+ @Override
+ public void showMagnificationButton(int displayId, int magnificationMode) {
+ mHandler.post(
+ () -> mModeSwitchesController.showButton(displayId, magnificationMode));
+ }
+
+ @Override
+ public void removeMagnificationButton(int displayId) {
+ mHandler.post(
+ () -> mModeSwitchesController.removeButton(displayId));
+ }
+
+ @Override
+ public void setConnectionCallback(IWindowMagnificationConnectionCallback callback) {
+ mConnectionCallback = callback;
+ }
+
+ void onWindowMagnifierBoundsChanged(int displayId, Rect frame) {
+ if (mConnectionCallback != null) {
+ try {
+ mConnectionCallback.onWindowMagnifierBoundsChanged(displayId, frame);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to inform bounds changed", e);
+ }
+ }
+ }
+
+ void onSourceBoundsChanged(int displayId, Rect sourceBounds) {
+ if (mConnectionCallback != null) {
+ try {
+ mConnectionCallback.onSourceBoundsChanged(displayId, sourceBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to inform source bounds changed", e);
+ }
+ }
+ }
+
+ void onPerformScaleAction(int displayId, float scale) {
+ if (mConnectionCallback != null) {
+ try {
+ mConnectionCallback.onPerformScaleAction(displayId, scale);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to inform performing scale action", e);
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index fd89baa61657..87dc6a53a9e2 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -719,12 +719,14 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
private boolean performA11yAction(int action) {
if (action == R.id.accessibility_action_zoom_in) {
final float scale = mScale + A11Y_CHANGE_SCALE_DIFFERENCE;
- setScale(A11Y_ACTION_SCALE_RANGE.clamp(scale));
+ mWindowMagnifierCallback.onPerformScaleAction(mDisplayId,
+ A11Y_ACTION_SCALE_RANGE.clamp(scale));
return true;
}
if (action == R.id.accessibility_action_zoom_out) {
final float scale = mScale - A11Y_CHANGE_SCALE_DIFFERENCE;
- setScale(A11Y_ACTION_SCALE_RANGE.clamp(scale));
+ mWindowMagnifierCallback.onPerformScaleAction(mDisplayId,
+ A11Y_ACTION_SCALE_RANGE.clamp(scale));
return true;
}
if (action == R.id.accessibility_action_move_up) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
index e405a89766e2..fb1d1b6d7816 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
@@ -37,4 +37,13 @@ interface WindowMagnifierCallback {
* @param sourceBounds The magnified bounds in screen coordinates.
*/
void onSourceBoundsChanged(int displayId, Rect sourceBounds);
+
+ /**
+ * Called when the accessibility action of scale requests to be performed.
+ * It is invoked from System UI. And the action is provided by the mirror window.
+ *
+ * @param displayId The logical display id.
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ */
+ void onPerformScaleAction(int displayId, float scale);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
index 1d47fc520ec2..e4f6d6cc6887 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
@@ -184,7 +184,7 @@ public class AuthBiometricFaceView extends AuthBiometricView {
mIconController.updateState(mState, newState);
if (newState == STATE_AUTHENTICATING_ANIMATING_IN ||
- (newState == STATE_AUTHENTICATING && mSize == AuthDialog.SIZE_MEDIUM)) {
+ (newState == STATE_AUTHENTICATING && getSize() == AuthDialog.SIZE_MEDIUM)) {
resetErrorView(mContext, mIndicatorView);
}
@@ -194,9 +194,9 @@ public class AuthBiometricFaceView extends AuthBiometricView {
@Override
public void onAuthenticationFailed(String failureReason) {
- if (mSize == AuthDialog.SIZE_MEDIUM) {
+ if (getSize() == AuthDialog.SIZE_MEDIUM) {
mTryAgainButton.setVisibility(View.VISIBLE);
- mPositiveButton.setVisibility(View.GONE);
+ mConfirmButton.setVisibility(View.GONE);
}
// Do this last since wa want to know if the button is being animated (in the case of
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java
new file mode 100644
index 000000000000..cc608ef87bc6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.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.systemui.biometrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Rect;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+/**
+ * Manages the layout for under-display fingerprint sensors (UDFPS). Ensures that UI elements
+ * do not overlap with
+ */
+public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView {
+
+ private static final String TAG = "AuthBiometricUdfpsView";
+
+ @Nullable private FingerprintSensorPropertiesInternal mSensorProps;
+
+ public AuthBiometricUdfpsView(Context context) {
+ this(context, null /* attrs */);
+ }
+
+ public AuthBiometricUdfpsView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ void setSensorProps(@NonNull FingerprintSensorPropertiesInternal prop) {
+ mSensorProps = prop;
+ }
+
+ /**
+ * For devices where the sensor is too high up, calculates the amount of padding necessary to
+ * move/center the biometric icon within the sensor's physical location.
+ */
+ static int calculateBottomSpacerHeight(int displayHeightPx, int navbarHeightPx,
+ int dialogBottomMarginPx, @NonNull View buttonBar, @NonNull View textIndicator,
+ @NonNull FingerprintSensorPropertiesInternal sensorProperties) {
+ final int sensorDistanceFromBottom = displayHeightPx - sensorProperties.sensorLocationY
+ - sensorProperties.sensorRadius;
+
+ final int spacerHeight = sensorDistanceFromBottom
+ - textIndicator.getMeasuredHeight()
+ - buttonBar.getMeasuredHeight()
+ - dialogBottomMarginPx
+ - navbarHeightPx;
+
+ Log.d(TAG, "Display height: " + displayHeightPx
+ + ", Distance from bottom: " + sensorDistanceFromBottom
+ + ", Bottom margin: " + dialogBottomMarginPx
+ + ", Navbar height: " + navbarHeightPx
+ + ", Spacer height: " + spacerHeight);
+
+ return spacerHeight;
+ }
+
+ @Override
+ AuthDialog.LayoutParams onMeasureInternal(int width, int height) {
+ final View spaceBelowIcon = findViewById(R.id.space_below_icon);
+ spaceBelowIcon.setVisibility(View.VISIBLE);
+
+ // Get the height of the everything below the icon. Currently, that's the indicator and
+ // button bar
+ final View textIndicator = findViewById(R.id.indicator);
+ final View buttonBar = findViewById(R.id.button_bar);
+
+ // Figure out where the bottom of the sensor anim should be.
+ // Navbar + dialogMargin + buttonBar + textIndicator + spacerHeight = sensorDistFromBottom
+ final int dialogBottomMarginPx = getResources()
+ .getDimensionPixelSize(R.dimen.biometric_dialog_border_padding);
+ final WindowManager wm = getContext().getSystemService(WindowManager.class);
+ final Rect bounds = wm.getCurrentWindowMetrics().getBounds();
+ final int navbarHeight = wm.getCurrentWindowMetrics().getWindowInsets()
+ .getInsets(WindowInsets.Type.navigationBars()).toRect().height();
+ final int displayHeight = bounds.height();
+
+ final int spacerHeight = calculateBottomSpacerHeight(displayHeight, navbarHeight,
+ dialogBottomMarginPx, buttonBar, textIndicator, mSensorProps);
+
+ // Go through each of the children and do the custom measurement.
+ int totalHeight = 0;
+ final int numChildren = getChildCount();
+ final int sensorDiameter = mSensorProps.sensorRadius * 2;
+ for (int i = 0; i < numChildren; i++) {
+ final View child = getChildAt(i);
+
+ if (child.getId() == R.id.biometric_icon_frame) {
+ // Create a frame that's exactly the size of the sensor circle
+ child.measure(
+ MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY));
+ } else if (child.getId() == R.id.biometric_icon) {
+ // Icon should never be larger than the circle
+ child.measure(
+ MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST));
+ } else if (child.getId() == R.id.space_above_icon) {
+ child.measure(
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(child.getLayoutParams().height,
+ MeasureSpec.EXACTLY));
+ } else if (child.getId() == R.id.button_bar) {
+ child.measure(
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(child.getLayoutParams().height,
+ MeasureSpec.EXACTLY));
+ } else if (child.getId() == R.id.space_below_icon) {
+ // Set the spacer height so the fingerprint icon is on the physical sensor area
+ child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(spacerHeight, MeasureSpec.EXACTLY));
+ } else {
+ child.measure(
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
+ }
+
+ if (child.getVisibility() != View.GONE) {
+ totalHeight += child.getMeasuredHeight();
+ }
+ }
+
+ return new AuthDialog.LayoutParams(width, totalHeight);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index ee6c465f71cc..c748ab21b822 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -116,8 +116,16 @@ public abstract class AuthBiometricView extends LinearLayout {
return mBiometricView.findViewById(R.id.button_negative);
}
- public Button getPositiveButton() {
- return mBiometricView.findViewById(R.id.button_positive);
+ public Button getCancelButton() {
+ return mBiometricView.findViewById(R.id.button_cancel);
+ }
+
+ public Button getUseCredentialButton() {
+ return mBiometricView.findViewById(R.id.button_use_credential);
+ }
+
+ public Button getConfirmButton() {
+ return mBiometricView.findViewById(R.id.button_confirm);
}
public Button getTryAgainButton() {
@@ -144,6 +152,10 @@ public abstract class AuthBiometricView extends LinearLayout {
return mBiometricView.findViewById(R.id.biometric_icon);
}
+ public View getIconHolderView() {
+ return mBiometricView.findViewById(R.id.biometric_icon_frame);
+ }
+
public int getDelayAfterError() {
return BiometricPrompt.HIDE_DIALOG_DELAY;
}
@@ -164,20 +176,28 @@ public abstract class AuthBiometricView extends LinearLayout {
private boolean mRequireConfirmation;
private int mUserId;
private int mEffectiveUserId;
- @AuthDialog.DialogSize int mSize = AuthDialog.SIZE_UNKNOWN;
+ private @AuthDialog.DialogSize int mSize = AuthDialog.SIZE_UNKNOWN;
private TextView mTitleView;
private TextView mSubtitleView;
private TextView mDescriptionView;
+ private View mIconHolderView;
protected ImageView mIconView;
@VisibleForTesting protected TextView mIndicatorView;
+
+ // Negative button position, exclusively for the app-specified behavior
@VisibleForTesting Button mNegativeButton;
- @VisibleForTesting Button mPositiveButton;
+ // Negative button position, exclusively for cancelling auth after passive auth success
+ @VisibleForTesting Button mCancelButton;
+ // Negative button position, shown if device credentials are allowed
+ @VisibleForTesting Button mUseCredentialButton;
+
+ // Positive button position,
+ @VisibleForTesting Button mConfirmButton;
@VisibleForTesting Button mTryAgainButton;
// Measurements when biometric view is showing text, buttons, etc.
- private int mMediumHeight;
- private int mMediumWidth;
+ @Nullable @VisibleForTesting AuthDialog.LayoutParams mLayoutParams;
private Callback mCallback;
protected @BiometricState int mState;
@@ -299,16 +319,17 @@ public abstract class AuthBiometricView extends LinearLayout {
mDescriptionView.setVisibility(View.GONE);
mIndicatorView.setVisibility(View.GONE);
mNegativeButton.setVisibility(View.GONE);
+ mUseCredentialButton.setVisibility(View.GONE);
final float iconPadding = getResources()
.getDimension(R.dimen.biometric_dialog_icon_padding);
- mIconView.setY(getHeight() - mIconView.getHeight() - iconPadding);
+ mIconHolderView.setY(getHeight() - mIconHolderView.getHeight() - iconPadding);
// Subtract the vertical padding from the new height since it's only used to create
// extra space between the other elements, and not part of the actual icon.
- final int newHeight = mIconView.getHeight() + 2 * (int) iconPadding
- - mIconView.getPaddingTop() - mIconView.getPaddingBottom();
- mPanelController.updateForContentDimensions(mMediumWidth, newHeight,
+ final int newHeight = mIconHolderView.getHeight() + 2 * (int) iconPadding
+ - mIconHolderView.getPaddingTop() - mIconHolderView.getPaddingBottom();
+ mPanelController.updateForContentDimensions(mLayoutParams.mMediumWidth, newHeight,
0 /* animateDurationMs */);
mSize = newSize;
@@ -320,9 +341,9 @@ public abstract class AuthBiometricView extends LinearLayout {
// Animate the icon back to original position
final ValueAnimator iconAnimator =
- ValueAnimator.ofFloat(mIconView.getY(), mIconOriginalY);
+ ValueAnimator.ofFloat(mIconHolderView.getY(), mIconOriginalY);
iconAnimator.addUpdateListener((animation) -> {
- mIconView.setY((float) animation.getAnimatedValue());
+ mIconHolderView.setY((float) animation.getAnimatedValue());
});
// Animate the text
@@ -332,6 +353,7 @@ public abstract class AuthBiometricView extends LinearLayout {
mTitleView.setAlpha(opacity);
mIndicatorView.setAlpha(opacity);
mNegativeButton.setAlpha(opacity);
+ mCancelButton.setAlpha(opacity);
mTryAgainButton.setAlpha(opacity);
if (!TextUtils.isEmpty(mSubtitleView.getText())) {
@@ -351,7 +373,12 @@ public abstract class AuthBiometricView extends LinearLayout {
super.onAnimationStart(animation);
mTitleView.setVisibility(View.VISIBLE);
mIndicatorView.setVisibility(View.VISIBLE);
- mNegativeButton.setVisibility(View.VISIBLE);
+
+ if (isDeviceCredentialAllowed()) {
+ mUseCredentialButton.setVisibility(View.VISIBLE);
+ } else {
+ mNegativeButton.setVisibility(View.VISIBLE);
+ }
mTryAgainButton.setVisibility(View.VISIBLE);
if (!TextUtils.isEmpty(mSubtitleView.getText())) {
@@ -374,10 +401,12 @@ public abstract class AuthBiometricView extends LinearLayout {
as.play(iconAnimator).with(opacityAnimator);
as.start();
// Animate the panel
- mPanelController.updateForContentDimensions(mMediumWidth, mMediumHeight,
+ mPanelController.updateForContentDimensions(mLayoutParams.mMediumWidth,
+ mLayoutParams.mMediumHeight,
AuthDialog.ANIMATE_SMALL_TO_MEDIUM_DURATION_MS);
} else if (newSize == AuthDialog.SIZE_MEDIUM) {
- mPanelController.updateForContentDimensions(mMediumWidth, mMediumHeight,
+ mPanelController.updateForContentDimensions(mLayoutParams.mMediumWidth,
+ mLayoutParams.mMediumHeight,
0 /* animateDurationMs */);
mSize = newSize;
} else if (newSize == AuthDialog.SIZE_LARGE) {
@@ -441,15 +470,17 @@ public abstract class AuthBiometricView extends LinearLayout {
case STATE_AUTHENTICATING:
removePendingAnimations();
if (mRequireConfirmation) {
- mPositiveButton.setEnabled(false);
- mPositiveButton.setVisibility(View.VISIBLE);
+ mConfirmButton.setEnabled(false);
+ mConfirmButton.setVisibility(View.VISIBLE);
}
break;
case STATE_AUTHENTICATED:
if (mSize != AuthDialog.SIZE_SMALL) {
- mPositiveButton.setVisibility(View.GONE);
+ mConfirmButton.setVisibility(View.GONE);
mNegativeButton.setVisibility(View.GONE);
+ mUseCredentialButton.setVisibility(View.GONE);
+ mCancelButton.setVisibility(View.GONE);
mIndicatorView.setVisibility(View.INVISIBLE);
}
announceForAccessibility(getResources()
@@ -460,10 +491,11 @@ public abstract class AuthBiometricView extends LinearLayout {
case STATE_PENDING_CONFIRMATION:
removePendingAnimations();
- mNegativeButton.setText(R.string.cancel);
- mNegativeButton.setContentDescription(getResources().getString(R.string.cancel));
- mPositiveButton.setEnabled(true);
- mPositiveButton.setVisibility(View.VISIBLE);
+ mNegativeButton.setVisibility(View.GONE);
+ mCancelButton.setVisibility(View.VISIBLE);
+ mUseCredentialButton.setVisibility(View.GONE);
+ mConfirmButton.setEnabled(true);
+ mConfirmButton.setVisibility(View.VISIBLE);
mIndicatorView.setTextColor(mTextColorHint);
mIndicatorView.setText(R.string.biometric_dialog_tap_confirm);
mIndicatorView.setVisibility(View.VISIBLE);
@@ -566,6 +598,7 @@ public abstract class AuthBiometricView extends LinearLayout {
mIndicatorView.setText(message);
mIndicatorView.setTextColor(mTextColorError);
mIndicatorView.setVisibility(View.VISIBLE);
+ mIndicatorView.setSelected(true);
mHandler.postDelayed(resetMessageRunnable, BiometricPrompt.HIDE_DIALOG_DELAY);
Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
@@ -586,24 +619,31 @@ public abstract class AuthBiometricView extends LinearLayout {
mSubtitleView = mInjector.getSubtitleView();
mDescriptionView = mInjector.getDescriptionView();
mIconView = mInjector.getIconView();
+ mIconHolderView = mInjector.getIconHolderView();
mIndicatorView = mInjector.getIndicatorView();
+
+ // Negative-side (left) buttons
mNegativeButton = mInjector.getNegativeButton();
- mPositiveButton = mInjector.getPositiveButton();
+ mCancelButton = mInjector.getCancelButton();
+ mUseCredentialButton = mInjector.getUseCredentialButton();
+
+ // Positive-side (right) buttons
+ mConfirmButton = mInjector.getConfirmButton();
mTryAgainButton = mInjector.getTryAgainButton();
mNegativeButton.setOnClickListener((view) -> {
- if (mState == STATE_PENDING_CONFIRMATION) {
- mCallback.onAction(Callback.ACTION_USER_CANCELED);
- } else {
- if (isDeviceCredentialAllowed()) {
- startTransitionToCredentialUI();
- } else {
- mCallback.onAction(Callback.ACTION_BUTTON_NEGATIVE);
- }
- }
+ mCallback.onAction(Callback.ACTION_BUTTON_NEGATIVE);
});
- mPositiveButton.setOnClickListener((view) -> {
+ mCancelButton.setOnClickListener((view) -> {
+ mCallback.onAction(Callback.ACTION_USER_CANCELED);
+ });
+
+ mUseCredentialButton.setOnClickListener((view) -> {
+ startTransitionToCredentialUI();
+ });
+
+ mConfirmButton.setOnClickListener((view) -> {
updateState(STATE_AUTHENTICATED);
});
@@ -637,31 +677,36 @@ public abstract class AuthBiometricView extends LinearLayout {
void onAttachedToWindowInternal() {
setText(mTitleView, mPromptInfo.getTitle());
- final CharSequence negativeText;
if (isDeviceCredentialAllowed()) {
-
+ final CharSequence credentialButtonText;
final @Utils.CredentialType int credentialType =
Utils.getCredentialType(mContext, mEffectiveUserId);
-
switch (credentialType) {
case Utils.CREDENTIAL_PIN:
- negativeText = getResources().getString(R.string.biometric_dialog_use_pin);
+ credentialButtonText =
+ getResources().getString(R.string.biometric_dialog_use_pin);
break;
case Utils.CREDENTIAL_PATTERN:
- negativeText = getResources().getString(R.string.biometric_dialog_use_pattern);
+ credentialButtonText =
+ getResources().getString(R.string.biometric_dialog_use_pattern);
break;
case Utils.CREDENTIAL_PASSWORD:
- negativeText = getResources().getString(R.string.biometric_dialog_use_password);
+ credentialButtonText =
+ getResources().getString(R.string.biometric_dialog_use_password);
break;
default:
- negativeText = getResources().getString(R.string.biometric_dialog_use_password);
+ credentialButtonText =
+ getResources().getString(R.string.biometric_dialog_use_password);
break;
}
+ mNegativeButton.setVisibility(View.GONE);
+
+ mUseCredentialButton.setText(credentialButtonText);
+ mUseCredentialButton.setVisibility(View.VISIBLE);
} else {
- negativeText = mPromptInfo.getNegativeButtonText();
+ setText(mNegativeButton, mPromptInfo.getNegativeButtonText());
}
- setText(mNegativeButton, negativeText);
setTextOrHide(mSubtitleView, mPromptInfo.getSubtitle());
@@ -688,29 +733,45 @@ public abstract class AuthBiometricView extends LinearLayout {
mHandler.removeCallbacksAndMessages(null /* all */);
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int width = MeasureSpec.getSize(widthMeasureSpec);
- final int height = MeasureSpec.getSize(heightMeasureSpec);
- final int newWidth = Math.min(width, height);
-
+ /**
+ * Contains all of the testable logic that should be invoked when {@link #onMeasure(int, int)}
+ * is invoked. In addition, this allows subclasses to implement custom measuring logic while
+ * allowing the base class to have common code to apply the custom measurements.
+ *
+ * @param width Width to constrain the measurements to.
+ * @param height Height to constrain the measurements to.
+ * @return See {@link AuthDialog.LayoutParams}
+ */
+ AuthDialog.LayoutParams onMeasureInternal(int width, int height) {
int totalHeight = 0;
final int numChildren = getChildCount();
for (int i = 0; i < numChildren; i++) {
final View child = getChildAt(i);
- if (child.getId() == R.id.biometric_icon) {
+ if (child.getId() == R.id.space_above_icon) {
+ child.measure(
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(child.getLayoutParams().height,
+ MeasureSpec.EXACTLY));
+ } else if (child.getId() == R.id.biometric_icon_frame) {
+ final View iconView = findViewById(R.id.biometric_icon);
child.measure(
- MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(iconView.getLayoutParams().width,
+ MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(iconView.getLayoutParams().height,
+ MeasureSpec.EXACTLY));
+ } else if (child.getId() == R.id.biometric_icon) {
+ child.measure(
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
- } else if (child.getId() == R.id.button_bar) {
+ } else if (child.getId() == R.id.button_bar) {
child.measure(
- MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(child.getLayoutParams().height,
MeasureSpec.EXACTLY));
} else {
child.measure(
- MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
}
@@ -719,11 +780,19 @@ public abstract class AuthBiometricView extends LinearLayout {
}
}
- // Use the new width so it's centered horizontally
- setMeasuredDimension(newWidth, totalHeight);
+ return new AuthDialog.LayoutParams(width, totalHeight);
+ }
- mMediumHeight = totalHeight;
- mMediumWidth = getMeasuredWidth();
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+ final int height = MeasureSpec.getSize(heightMeasureSpec);
+ final int newWidth = Math.min(width, height);
+
+ // Use "newWidth" instead, so the landscape dialog width is the same as the portrait
+ // width.
+ mLayoutParams = onMeasureInternal(newWidth, height);
+ setMeasuredDimension(mLayoutParams.mMediumWidth, mLayoutParams.mMediumHeight);
}
@Override
@@ -741,7 +810,7 @@ public abstract class AuthBiometricView extends LinearLayout {
// Start with initial size only once. Subsequent layout changes don't matter since we
// only care about the initial icon position.
if (mIconOriginalY == 0) {
- mIconOriginalY = mIconView.getY();
+ mIconOriginalY = mIconHolderView.getY();
if (mSavedState == null) {
updateSize(!mRequireConfirmation && supportsSmallDialog() ? AuthDialog.SIZE_SMALL
: AuthDialog.SIZE_MEDIUM);
@@ -764,4 +833,8 @@ public abstract class AuthBiometricView extends LinearLayout {
private boolean isDeviceCredentialAllowed() {
return Utils.isDeviceCredentialAllowed(mPromptInfo);
}
+
+ @AuthDialog.DialogSize int getSize() {
+ return mSize;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 24ab6355c2bd..2b33f8cd036e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -21,11 +21,9 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.PixelFormat;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.PromptInfo;
import android.hardware.face.FaceSensorPropertiesInternal;
-import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Binder;
import android.os.Bundle;
@@ -286,8 +284,23 @@ public class AuthContainerView extends LinearLayout
if (config.mSensorIds.length == 1) {
final int singleSensorAuthId = config.mSensorIds[0];
if (Utils.containsSensorId(mFpProps, singleSensorAuthId)) {
- mBiometricView = (AuthBiometricFingerprintView)
- factory.inflate(R.layout.auth_biometric_fingerprint_view, null, false);
+ FingerprintSensorPropertiesInternal sensorProps = null;
+ for (FingerprintSensorPropertiesInternal prop : mFpProps) {
+ if (prop.sensorId == singleSensorAuthId) {
+ sensorProps = prop;
+ break;
+ }
+ }
+
+ if (sensorProps.isAnyUdfpsType()) {
+ AuthBiometricUdfpsView udfpsView = (AuthBiometricUdfpsView) factory
+ .inflate(R.layout.auth_biometric_udfps_view, null, false);
+ udfpsView.setSensorProps(sensorProps);
+ mBiometricView = udfpsView;
+ } else {
+ mBiometricView = (AuthBiometricFingerprintView) factory
+ .inflate(R.layout.auth_biometric_fingerprint_view, null, false);
+ }
} else if (Utils.containsSensorId(mFaceProps, singleSensorAuthId)) {
mBiometricView = (AuthBiometricFaceView)
factory.inflate(R.layout.auth_biometric_face_view, null, false);
@@ -627,6 +640,7 @@ public class AuthContainerView extends LinearLayout
}
mContainerState = STATE_SHOWING;
if (mBiometricView != null) {
+ mConfig.mCallback.onDialogAnimatedIn();
mBiometricView.onDialogAnimatedIn();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index c72bc2543b36..ecbe5f4d3ac9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -54,8 +54,8 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
@@ -67,7 +67,7 @@ import javax.inject.Provider;
*/
@SysUISingleton
public class AuthController extends SystemUI implements CommandQueue.Callbacks,
- AuthDialogCallback, DozeReceiver, KeyguardBouncer.BouncerExpansionCallback {
+ AuthDialogCallback, DozeReceiver {
private static final String TAG = "AuthController";
private static final boolean DEBUG = true;
@@ -81,6 +81,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
@Nullable private final List<FingerprintSensorPropertiesInternal> mFpProps;
@Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
+ @Nullable private final List<FingerprintSensorPropertiesInternal> mUdfpsProps;
// TODO: These should just be saved from onSaveState
private SomeArgs mCurrentDialogArgs;
@@ -200,6 +201,20 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
}
@Override
+ public void onDialogAnimatedIn() {
+ if (mReceiver == null) {
+ Log.e(TAG, "onDialogAnimatedIn: Receiver is null");
+ return;
+ }
+
+ try {
+ mReceiver.onDialogAnimatedIn();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException when sending onDialogAnimatedIn", e);
+ }
+ }
+
+ @Override
public void onDismissed(@DismissedReason int reason, @Nullable byte[] credentialAttestation) {
switch (reason) {
case AuthDialogCallback.DISMISSED_USER_CANCELED:
@@ -314,6 +329,16 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
: null;
mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
+ List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>();
+ if (mFpProps != null) {
+ for (FingerprintSensorPropertiesInternal props : mFpProps) {
+ if (props.isAnyUdfpsType()) {
+ udfpsProps.add(props);
+ }
+ }
+ }
+ mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null;
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -326,15 +351,9 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mCommandQueue.addCallback(this);
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
- final List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties =
- mFingerprintManager.getSensorPropertiesInternal();
- for (FingerprintSensorPropertiesInternal props : fingerprintSensorProperties) {
- if (props.isAnyUdfpsType()) {
- mUdfpsController = mUdfpsControllerFactory.get();
- break;
- }
- }
+ if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()
+ && mUdfpsProps != null) {
+ mUdfpsController = mUdfpsControllerFactory.get();
}
try {
@@ -454,42 +473,15 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mCurrentDialog = null;
}
- /** See {@link KeyguardBouncer.BouncerExpansionCallback#onFullyShown}. */
- @Override
- public void onFullyShown() {
- if (mUdfpsController != null) {
- mUdfpsController.setBouncerVisibility(true);
- }
- }
-
- /** See {@link KeyguardBouncer.BouncerExpansionCallback#onStartingToHide}. */
- @Override
- public void onStartingToHide() {
- }
-
- /** See {@link KeyguardBouncer.BouncerExpansionCallback#onStartingToShow}. */
- @Override
- public void onStartingToShow() {
- if (mUdfpsController != null) {
- mUdfpsController.setBouncerVisibility(true);
- }
- }
-
- /** See {@link KeyguardBouncer.BouncerExpansionCallback#onFullyHidden}. */
- @Override
- public void onFullyHidden() {
- if (mUdfpsController != null) {
- mUdfpsController.setBouncerVisibility(false);
- }
- }
-
/**
- * Whether the current user has a UDFP enrolled.
+ * Whether the passed userId has enrolled UDFPS.
*/
- public boolean isUdfpsEnrolled() {
- // TODO: (b/171392825) right now only checks whether the UDFPS sensor exists on this device
- // but not whether user has enrolled or not
- return mUdfpsController != null;
+ public boolean isUdfpsEnrolled(int userId) {
+ if (mUdfpsController == null) {
+ return false;
+ }
+
+ return mFingerprintManager.hasEnrolledTemplatesForAnySensor(userId, mUdfpsProps);
}
private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
index ca95f9d736fc..0f3643c8c359 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
@@ -59,6 +59,20 @@ public interface AuthDialog {
@interface DialogSize {}
/**
+ * Parameters used when laying out {@link AuthBiometricView}, its sublclasses, and
+ * {@link AuthPanelController}.
+ */
+ class LayoutParams {
+ final int mMediumHeight;
+ final int mMediumWidth;
+
+ LayoutParams(int mediumWidth, int mediumHeight) {
+ mMediumWidth = mediumWidth;
+ mMediumHeight = mediumHeight;
+ }
+ }
+
+ /**
* Animation duration, from small to medium dialog, including back panel, icon translation, etc
*/
int ANIMATE_SMALL_TO_MEDIUM_DURATION_MS = 150;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
index d3bd4fbd921c..d8d07e7dd24a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
@@ -65,4 +65,9 @@ public interface AuthDialogCallback {
* @param event
*/
void onSystemEvent(int event);
+
+ /**
+ * Notifies when the dialog has finished animating in.
+ */
+ void onDialogAnimatedIn();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index a4b407d2785d..e43774057e26 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -107,8 +107,6 @@ class UdfpsController implements DozeReceiver {
private boolean mIsOverlayShowing;
// Indicates whether the overlay has been requested.
private boolean mIsOverlayRequested;
- // Indicates whether the bouncer is showing. When it is showing, the overlay needs to be hidden.
- private boolean mIsBouncerShowing;
// The fingerprint AOD trigger doesn't provide an ACTION_UP/ACTION_CANCEL event to tell us when
// to turn off high brightness mode. To get around this limitation, the state of the AOD
@@ -260,21 +258,8 @@ class UdfpsController implements DozeReceiver {
updateOverlay();
}
- /**
- * Call when the visibility of the bouncer changes.
- *
- * @param isShowing Whether or not the bouncer is showing
- */
- void setBouncerVisibility(boolean isShowing) {
- if (isShowing == mIsBouncerShowing) {
- return;
- }
- mIsBouncerShowing = isShowing;
- updateOverlay();
- }
-
private void updateOverlay() {
- if (mIsOverlayRequested && !mIsBouncerShowing) {
+ if (mIsOverlayRequested) {
showUdfpsOverlay();
} else {
hideUdfpsOverlay();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
deleted file mode 100644
index ffb650d62064..000000000000
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ /dev/null
@@ -1,301 +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.systemui.bubbles;
-
-import static android.app.Notification.EXTRA_MESSAGES;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST;
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
-
-import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_EXPERIMENTS;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.Person;
-import android.content.Context;
-import android.content.pm.LauncherApps;
-import android.content.pm.ShortcutInfo;
-import android.graphics.Color;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.Log;
-
-import com.android.internal.graphics.ColorUtils;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.people.PeopleHubNotificationListenerKt;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Common class for experiments controlled via secure settings.
- */
-public class BubbleExperimentConfig {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES;
-
- private static final int BUBBLE_HEIGHT = 10000;
-
- private static final String ALLOW_ANY_NOTIF_TO_BUBBLE = "allow_any_notif_to_bubble";
- private static final boolean ALLOW_ANY_NOTIF_TO_BUBBLE_DEFAULT = false;
-
- private static final String ALLOW_MESSAGE_NOTIFS_TO_BUBBLE = "allow_message_notifs_to_bubble";
- private static final boolean ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT = false;
-
- private static final String ALLOW_SHORTCUTS_TO_BUBBLE = "allow_shortcuts_to_bubble";
- private static final boolean ALLOW_SHORTCUT_TO_BUBBLE_DEFAULT = false;
-
- private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps";
-
- /**
- * 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}
- * object will be created by the system and added to the notification.
- * <p>
- * This does not produce a bubble, only adds the metadata based on the notification info.
- */
- static boolean allowAnyNotifToBubble(Context context) {
- return Settings.Secure.getInt(context.getContentResolver(),
- ALLOW_ANY_NOTIF_TO_BUBBLE,
- ALLOW_ANY_NOTIF_TO_BUBBLE_DEFAULT ? 1 : 0) != 0;
- }
-
- /**
- * Same as {@link #allowAnyNotifToBubble(Context)} except it filters for notifications that
- * are using {@link Notification.MessagingStyle} and have remote input.
- */
- static boolean allowMessageNotifsToBubble(Context context) {
- return Settings.Secure.getInt(context.getContentResolver(),
- ALLOW_MESSAGE_NOTIFS_TO_BUBBLE,
- ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT ? 1 : 0) != 0;
- }
-
- /**
- * When true, if the notification is able to bubble via {@link #allowAnyNotifToBubble(Context)}
- * or {@link #allowMessageNotifsToBubble(Context)} or via normal BubbleMetadata, then a new
- * BubbleMetadata object is constructed based on the shortcut info.
- * <p>
- * This does not produce a bubble, only adds the metadata based on shortcut info.
- */
- static boolean useShortcutInfoToBubble(Context context) {
- return Settings.Secure.getInt(context.getContentResolver(),
- ALLOW_SHORTCUTS_TO_BUBBLE,
- ALLOW_SHORTCUT_TO_BUBBLE_DEFAULT ? 1 : 0) != 0;
- }
-
- /**
- * Returns whether the provided package is whitelisted to bubble.
- */
- static boolean isPackageWhitelistedToAutoBubble(Context context, String packageName) {
- String unsplitList = Settings.Secure.getString(context.getContentResolver(),
- WHITELISTED_AUTO_BUBBLE_APPS);
- if (unsplitList != null) {
- // We expect the list to be separated by commas and no white space (but we trim in case)
- String[] packageList = unsplitList.split(",");
- for (int i = 0; i < packageList.length; i++) {
- if (packageList[i].trim().equals(packageName)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * If {@link #allowAnyNotifToBubble(Context)} is true, this method creates and adds
- * {@link android.app.Notification.BubbleMetadata} to the notification entry as long as
- * the notification has necessary info for BubbleMetadata.
- *
- * @return whether an adjustment was made.
- */
- static boolean adjustForExperiments(Context context, NotificationEntry entry,
- boolean previouslyUserCreated, boolean userBlocked) {
- Notification.BubbleMetadata metadata = null;
- boolean addedMetadata = false;
- boolean whiteListedToAutoBubble =
- isPackageWhitelistedToAutoBubble(context, entry.getSbn().getPackageName());
-
- Notification notification = entry.getSbn().getNotification();
- boolean isMessage = Notification.MessagingStyle.class.equals(
- notification.getNotificationStyle());
- boolean bubbleNotifForExperiment = (isMessage && allowMessageNotifsToBubble(context))
- || allowAnyNotifToBubble(context);
-
- boolean useShortcutInfo = useShortcutInfoToBubble(context);
- String shortcutId = entry.getSbn().getNotification().getShortcutId();
-
- boolean hasMetadata = entry.getBubbleMetadata() != null;
- if ((!hasMetadata && (previouslyUserCreated || bubbleNotifForExperiment))
- || useShortcutInfo) {
- if (DEBUG_EXPERIMENTS) {
- Log.d(TAG, "Adjusting " + entry.getKey() + " for bubble experiment."
- + " allowMessages=" + allowMessageNotifsToBubble(context)
- + " isMessage=" + isMessage
- + " allowNotifs=" + allowAnyNotifToBubble(context)
- + " useShortcutInfo=" + useShortcutInfo
- + " previouslyUserCreated=" + previouslyUserCreated);
- }
- }
-
- if (useShortcutInfo && shortcutId != null) {
- // We don't actually get anything useful from ShortcutInfo so just check existence
- ShortcutInfo info = getShortcutInfo(context, entry.getSbn().getPackageName(),
- entry.getSbn().getUser(), shortcutId);
- if (info != null) {
- metadata = createForShortcut(shortcutId);
- }
-
- // Replace existing metadata with shortcut, or we're bubbling for experiment
- boolean shouldBubble = entry.getBubbleMetadata() != null
- || bubbleNotifForExperiment
- || previouslyUserCreated;
- if (shouldBubble && metadata != null) {
- if (DEBUG_EXPERIMENTS) {
- Log.d(TAG, "Adding experimental shortcut bubble for: " + entry.getKey());
- }
- entry.setBubbleMetadata(metadata);
- addedMetadata = true;
- }
- }
-
- // Didn't get metadata from a shortcut & we're bubbling for experiment
- if (entry.getBubbleMetadata() == null
- && (bubbleNotifForExperiment || previouslyUserCreated)) {
- metadata = createFromNotif(context, entry);
- if (metadata != null) {
- if (DEBUG_EXPERIMENTS) {
- Log.d(TAG, "Adding experimental notification bubble for: " + entry.getKey());
- }
- entry.setBubbleMetadata(metadata);
- addedMetadata = true;
- }
- }
-
- boolean bubbleForWhitelist = !userBlocked
- && whiteListedToAutoBubble
- && (addedMetadata || hasMetadata);
- if ((previouslyUserCreated && addedMetadata) || bubbleForWhitelist) {
- // Update to a previous bubble (or new autobubble), set its flag now.
- if (DEBUG_EXPERIMENTS) {
- Log.d(TAG, "Setting FLAG_BUBBLE for: " + entry.getKey());
- }
- entry.setFlagBubble(true);
- return true;
- }
- return addedMetadata;
- }
-
- static Notification.BubbleMetadata createFromNotif(Context context, NotificationEntry entry) {
- Notification notification = entry.getSbn().getNotification();
- final PendingIntent intent = notification.contentIntent;
- Icon icon = null;
- // Use the icon of the person if available
- List<Person> personList = getPeopleFromNotification(entry);
- if (personList.size() > 0) {
- final Person person = personList.get(0);
- if (person != null) {
- icon = person.getIcon();
- if (icon == null) {
- // Lets try and grab the icon constructed by the layout
- Drawable d = PeopleHubNotificationListenerKt.extractAvatarFromRow(entry);
- if (d instanceof BitmapDrawable) {
- icon = Icon.createWithBitmap(((BitmapDrawable) d).getBitmap());
- }
- }
- }
- }
- if (icon == null) {
- boolean shouldTint = notification.getLargeIcon() == null;
- icon = shouldTint
- ? notification.getSmallIcon()
- : notification.getLargeIcon();
- if (shouldTint) {
- int notifColor = entry.getSbn().getNotification().color;
- notifColor = ColorUtils.setAlphaComponent(notifColor, 255);
- notifColor = ContrastColorUtil.findContrastColor(notifColor, Color.WHITE,
- true /* findFg */, 3f);
- icon.setTint(notifColor);
- }
- }
- if (intent != null) {
- return new Notification.BubbleMetadata.Builder(intent, icon)
- .setDesiredHeight(BUBBLE_HEIGHT)
- .build();
- }
- return null;
- }
-
- static Notification.BubbleMetadata createForShortcut(String shortcutId) {
- return new Notification.BubbleMetadata.Builder(shortcutId)
- .setDesiredHeight(BUBBLE_HEIGHT)
- .build();
- }
-
- static ShortcutInfo getShortcutInfo(Context context, String packageName, UserHandle user,
- String shortcutId) {
- LauncherApps launcherAppService =
- (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
- LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery();
- if (packageName != null) {
- query.setPackage(packageName);
- }
- if (shortcutId != null) {
- query.setShortcutIds(Arrays.asList(shortcutId));
- }
- query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST);
- List<ShortcutInfo> shortcuts = launcherAppService.getShortcuts(query, user);
- return shortcuts != null && shortcuts.size() > 0
- ? shortcuts.get(0)
- : null;
- }
-
- static List<Person> getPeopleFromNotification(NotificationEntry entry) {
- Bundle extras = entry.getSbn().getNotification().extras;
- ArrayList<Person> personList = new ArrayList<>();
- if (extras == null) {
- return personList;
- }
-
- List<Person> p = extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST);
-
- if (p != null) {
- personList.addAll(p);
- }
-
- if (Notification.MessagingStyle.class.equals(
- entry.getSbn().getNotification().getNotificationStyle())) {
- final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
- if (!ArrayUtils.isEmpty(messages)) {
- for (Notification.MessagingStyle.Message message :
- Notification.MessagingStyle.Message
- .getMessagesFromBundleArray(messages)) {
- personList.add(message.getSenderPerson());
- }
- }
- }
- return personList;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubblePositioner.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubblePositioner.java
deleted file mode 100644
index 029caee6364f..000000000000
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubblePositioner.java
+++ /dev/null
@@ -1,89 +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.bubbles;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Insets;
-import android.graphics.Rect;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.view.WindowMetrics;
-
-import androidx.annotation.VisibleForTesting;
-
-/**
- * Keeps track of display size, configuration, and specific bubble sizes. One place for all
- * placement and positioning calculations to refer to.
- */
-public class BubblePositioner {
-
- private WindowManager mWindowManager;
- private Rect mPositionRect;
- private int mOrientation;
- private Insets mInsets;
-
- public BubblePositioner(Context context, WindowManager windowManager) {
- mWindowManager = windowManager;
- update(Configuration.ORIENTATION_UNDEFINED);
- }
-
- public void update(int orientation) {
- WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
- mPositionRect = new Rect(windowMetrics.getBounds());
- WindowInsets metricInsets = windowMetrics.getWindowInsets();
-
- Insets insets = metricInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
- | WindowInsets.Type.statusBars()
- | WindowInsets.Type.displayCutout());
- update(orientation, insets, windowMetrics.getBounds());
- }
-
- @VisibleForTesting
- public void update(int orientation, Insets insets, Rect bounds) {
- mOrientation = orientation;
- mInsets = insets;
-
- mPositionRect = new Rect(bounds);
- mPositionRect.left += mInsets.left;
- mPositionRect.top += mInsets.top;
- mPositionRect.right -= mInsets.right;
- mPositionRect.bottom -= mInsets.bottom;
- }
-
- /**
- * @return a rect of available screen space for displaying bubbles in the correct orientation,
- * accounting for system bars and cutouts.
- */
- public Rect getAvailableRect() {
- return mPositionRect;
- }
-
- /**
- * @return the current orientation.
- */
- public int getOrientation() {
- return mOrientation;
- }
-
- /**
- * @return the relevant insets (status bar, nav bar, cutouts).
- */
- public Insets getInsets() {
- return mInsets;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
deleted file mode 100644
index 5a7e033607f8..000000000000
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.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 com.android.systemui.bubbles.dagger;
-
-import android.app.INotificationManager;
-import android.content.Context;
-import android.content.pm.LauncherApps;
-import android.os.Handler;
-import android.view.WindowManager;
-
-import androidx.annotation.Nullable;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.bubbles.Bubbles;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.model.SysUiState;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.wmshell.BubblesManager;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.WindowManagerShellWrapper;
-import com.android.wm.shell.common.FloatingContentCoordinator;
-
-import java.util.Optional;
-
-import dagger.Module;
-import dagger.Provides;
-
-/** */
-@Module
-public interface BubbleModule {
-
- /**
- */
- @SysUISingleton
- @Provides
- static Bubbles newBubbleController(Context context,
- FloatingContentCoordinator floatingContentCoordinator,
- IStatusBarService statusBarService,
- WindowManager windowManager,
- WindowManagerShellWrapper windowManagerShellWrapper,
- LauncherApps launcherApps,
- UiEventLogger uiEventLogger,
- @Main Handler mainHandler,
- ShellTaskOrganizer organizer) {
- return BubbleController.create(context, null /* synchronizer */, floatingContentCoordinator,
- statusBarService, windowManager, windowManagerShellWrapper, launcherApps,
- uiEventLogger, mainHandler, organizer);
- }
-
- /** Provides Optional of BubbleManager */
- @SysUISingleton
- @Provides
- static Optional<BubblesManager> provideBubblesManager(Context context,
- Optional<Bubbles> bubblesOptional,
- NotificationShadeWindowController notificationShadeWindowController,
- StatusBarStateController statusBarStateController, ShadeController shadeController,
- ConfigurationController configurationController,
- @Nullable IStatusBarService statusBarService, INotificationManager notificationManager,
- NotificationInterruptStateProvider interruptionStateProvider,
- ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager,
- NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager,
- NotifPipeline notifPipeline, SysUiState sysUiState, FeatureFlags featureFlags,
- DumpManager dumpManager) {
- return Optional.ofNullable(BubblesManager.create(context, bubblesOptional,
- notificationShadeWindowController, statusBarStateController, shadeController,
- configurationController, statusBarService, notificationManager,
- interruptionStateProvider, zenModeController, notifUserManager,
- groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager));
- }
-}
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 aa11df41a7b7..a3a937acec76 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -301,7 +301,7 @@ class ToggleRangeBehavior : Behavior {
}
fun findNearestStep(value: Float): Float {
- var minDiff = 1000f
+ var minDiff = Float.MAX_VALUE
var f = rangeTemplate.getMinValue()
while (f <= rangeTemplate.getMaxValue()) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index d13e194a0d44..13ff3f5c4e6c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -21,7 +21,7 @@ import android.app.Activity;
import com.android.systemui.ForegroundServicesDialog;
import com.android.systemui.keyguard.WorkLockActivity;
import com.android.systemui.screenrecord.ScreenRecordDialog;
-import com.android.systemui.settings.BrightnessDialog;
+import com.android.systemui.settings.brightness.BrightnessDialog;
import com.android.systemui.tuner.TunerActivity;
import com.android.systemui.usb.UsbDebuggingActivity;
import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 3aa462657637..7127f26a7ed2 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -23,6 +23,7 @@ import android.annotation.SuppressLint;
import android.app.INotificationManager;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.om.OverlayManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.HandlerThread;
@@ -43,6 +44,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.Prefs;
+import com.android.systemui.R;
import com.android.systemui.accessibility.ModeSwitchesController;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistManager;
@@ -78,7 +80,9 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.theme.ThemeOverlayApplier;
import com.android.systemui.util.leak.LeakDetector;
+import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
@@ -193,6 +197,17 @@ public class DependencyProvider {
}
/** */
+ @SysUISingleton
+ @Provides
+ static ThemeOverlayApplier provideThemeOverlayManager(Context context,
+ @Background Executor bgExecutor, OverlayManager overlayManager,
+ DumpManager dumpManager) {
+ return new ThemeOverlayApplier(overlayManager, bgExecutor,
+ context.getString(R.string.launcher_overlayable_package),
+ context.getString(R.string.themepicker_overlayable_package), dumpManager);
+ }
+
+ /** */
@Provides
@SysUISingleton
public NavigationBarController provideNavigationBarController(Context context,
@@ -208,6 +223,7 @@ public class DependencyProvider {
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
+ Optional<Pip> pipOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional,
Lazy<StatusBar> statusBarLazy,
@@ -230,6 +246,7 @@ public class DependencyProvider {
sysUiFlagsContainer,
broadcastDispatcher,
commandQueue,
+ pipOptional,
splitScreenOptional,
recentsOptional,
statusBarLazy,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 79925bad3cc7..c3f2e1848abd 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -31,6 +31,7 @@ import android.app.role.RoleManager;
import android.app.trust.TrustManager;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.om.OverlayManager;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
@@ -65,6 +66,7 @@ import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.LatencyTracker;
import com.android.systemui.dagger.qualifiers.DisplayId;
@@ -190,6 +192,13 @@ public class FrameworkServicesModule {
@Provides
@Singleton
+ static IAppWidgetService provideIAppWidgetService() {
+ return IAppWidgetService.Stub.asInterface(
+ ServiceManager.getService(Context.APPWIDGET_SERVICE));
+ }
+
+ @Provides
+ @Singleton
static IPackageManager provideIPackageManager() {
return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
}
@@ -343,7 +352,7 @@ public class FrameworkServicesModule {
@Provides
static WallpaperManager provideWallpaperManager(Context context) {
- return (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
+ return context.getSystemService(WallpaperManager.class);
}
@Provides
@@ -355,6 +364,12 @@ public class FrameworkServicesModule {
@Provides
@Singleton
+ static OverlayManager provideOverlayManager(Context context) {
+ return context.getSystemService(OverlayManager.class);
+ }
+
+ @Provides
+ @Singleton
static WindowManager provideWindowManager(Context context) {
return context.getSystemService(WindowManager.class);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index 554d9cbb454f..53383d65e379 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -22,9 +22,7 @@ import android.util.DisplayMetrics;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
-import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.animation.FlingAnimationUtils;
-import com.android.wm.shell.common.FloatingContentCoordinator;
import javax.inject.Singleton;
@@ -51,22 +49,6 @@ import dagger.Provides;
GlobalConcurrencyModule.class})
public class GlobalModule {
- // TODO(b/161980186): Currently only used by Bubbles, can move back to WMShellBaseModule once
- // Bubbles has migrated over
- @Singleton
- @Provides
- static FloatingContentCoordinator provideFloatingContentCoordinator() {
- return new FloatingContentCoordinator();
- }
-
- // TODO(b/161980186): Currently only used by Bubbles, can move back to WMShellBaseModule once
- // Bubbles has migrated over
- @Singleton
- @Provides
- static WindowManagerShellWrapper provideWindowManagerShellWrapper() {
- return new WindowManagerShellWrapper();
- }
-
// TODO(b/162923491): This should not be a singleton at all, the display metrics can change and
// callers should be creating a new builder on demand
@Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index d73633e57c9b..68a28ba63d6f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -22,11 +22,12 @@ import com.android.systemui.InitController;
import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.InjectionInflationController;
import com.android.wm.shell.ShellDump;
-import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.apppairs.AppPairs;
+import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -61,13 +62,16 @@ public interface SysUIComponent {
Builder setSplitScreen(Optional<SplitScreen> s);
@BindsInstance
+ Builder setAppPairs(Optional<AppPairs> s);
+
+ @BindsInstance
Builder setOneHanded(Optional<OneHanded> o);
@BindsInstance
- Builder setInputConsumerController(InputConsumerController i);
+ Builder setBubbles(Optional<Bubbles> b);
@BindsInstance
- Builder setShellTaskOrganizer(ShellTaskOrganizer s);
+ Builder setHideDisplayCutout(Optional<HideDisplayCutout> h);
@BindsInstance
Builder setShellDump(Optional<ShellDump> shellDump);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 1f6288a94ad4..c0013d8cb981 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -24,7 +24,6 @@ import com.android.systemui.SystemUI;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.accessibility.WindowMagnification;
import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.bubbles.dagger.BubbleModule;
import com.android.systemui.globalactions.GlobalActionsComponent;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.dagger.KeyguardModule;
@@ -51,8 +50,7 @@ import dagger.multibindings.IntoMap;
/**
* SystemUI objects that are injectable should go here.
*/
-@Module(includes = {RecentsModule.class, StatusBarModule.class, BubbleModule.class,
- KeyguardModule.class})
+@Module(includes = {RecentsModule.class, StatusBarModule.class, KeyguardModule.class})
public abstract class SystemUIBinder {
/** Inject into AuthController. */
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index a982ec5c0194..780bb5b01103 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -16,32 +16,49 @@
package com.android.systemui.dagger;
+import android.app.INotificationManager;
+import android.content.Context;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.statusbar.IStatusBarService;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.BootCompleteCache;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.controls.dagger.ControlsModule;
import com.android.systemui.demomode.dagger.DemoModeModule;
import com.android.systemui.doze.dagger.DozeComponent;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
import com.android.systemui.model.SysUiState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.dagger.PowerModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.FeatureFlags;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.people.PeopleHubModule;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
+import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule;
import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
import com.android.systemui.tuner.dagger.TunerModule;
@@ -53,6 +70,10 @@ import com.android.systemui.util.settings.SettingsUtilModule;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.util.time.SystemClockImpl;
import com.android.systemui.volume.dagger.VolumeModule;
+import com.android.systemui.wmshell.BubblesManager;
+import com.android.wm.shell.bubbles.Bubbles;
+
+import java.util.Optional;
import dagger.Binds;
import dagger.BindsOptionalOf;
@@ -126,10 +147,28 @@ public abstract class SystemUIModule {
@BindsOptionalOf
abstract StatusBar optionalStatusBar();
- @BindsOptionalOf
- abstract Bubbles optionalBubbles();
-
@SysUISingleton
@Binds
abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
+
+ /** Provides Optional of BubbleManager */
+ @SysUISingleton
+ @Provides
+ static Optional<BubblesManager> provideBubblesManager(Context context,
+ Optional<Bubbles> bubblesOptional,
+ NotificationShadeWindowController notificationShadeWindowController,
+ StatusBarStateController statusBarStateController, ShadeController shadeController,
+ ConfigurationController configurationController,
+ @Nullable IStatusBarService statusBarService, INotificationManager notificationManager,
+ NotificationInterruptStateProvider interruptionStateProvider,
+ ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager,
+ NotificationGroupManagerLegacy groupManager, NotificationEntryManager entryManager,
+ NotifPipeline notifPipeline, SysUiState sysUiState, FeatureFlags featureFlags,
+ DumpManager dumpManager) {
+ return Optional.ofNullable(BubblesManager.create(context, bubblesOptional,
+ notificationShadeWindowController, statusBarStateController, shadeController,
+ configurationController, statusBarService, notificationManager,
+ interruptionStateProvider, zenModeController, notifUserManager,
+ groupManager, entryManager, notifPipeline, sysUiState, featureFlags, dumpManager));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 66352860612b..e634529dcb71 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -16,11 +16,12 @@
package com.android.systemui.dagger;
-import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.wmshell.WMShellModule;
import com.android.wm.shell.ShellDump;
import com.android.wm.shell.ShellInit;
-import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.apppairs.AppPairs;
+import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -59,18 +60,8 @@ public interface WMComponent {
@WMSingleton
Optional<ShellDump> getShellDump();
- // TODO(b/162923491): Refactor this out so Pip doesn't need to inject this
- @WMSingleton
- InputConsumerController getInputConsumerController();
-
- // TODO(b/162923491): To be removed once Bubbles migrates over to the Shell
-
- @WMSingleton
- ShellTaskOrganizer getShellTaskOrganizer();
-
// TODO(b/162923491): We currently pass the instances through to SysUI, but that may change
// depending on the threading mechanism we go with
-
@WMSingleton
Optional<OneHanded> getOneHanded();
@@ -79,4 +70,13 @@ public interface WMComponent {
@WMSingleton
Optional<SplitScreen> getSplitScreen();
+
+ @WMSingleton
+ Optional<AppPairs> getAppPairs();
+
+ @WMSingleton
+ Optional<Bubbles> getBubbles();
+
+ @WMSingleton
+ Optional<HideDisplayCutout> getHideDisplayCutout();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index f07e5afdd887..ebfce661c9af 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -44,6 +44,7 @@ import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.internal.logging.nano.MetricsProto;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -156,7 +157,7 @@ public class DozeSensors {
findSensorWithType(config.udfpsLongPressSensorType()),
"doze_pulse_on_auth",
true /* settingDef */,
- authController.isUdfpsEnrolled() /* configured */,
+ authController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser()),
DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS,
true /* reports touch coordinates */,
true /* touchscreen */,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2705f07069bf..4c68312b9378 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1007,7 +1007,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
intent.putExtra("seq", mDelayedShowingSequence);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
PendingIntent sender = PendingIntent.getBroadcast(mContext,
- 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ 0, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
+ mDelayedShowingSequence);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 4e0df214d884..b6ca77b73df7 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -136,6 +136,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.PrintWriter;
@@ -179,6 +180,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final NavigationModeController mNavigationModeController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
+ private final Optional<Pip> mPipOptional;
private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<Recents> mRecentsOptional;
private final SystemActions mSystemActions;
@@ -406,6 +408,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
+ Optional<Pip> pipOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional, Lazy<StatusBar> statusBarLazy,
ShadeController shadeController,
@@ -430,6 +433,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mNavBarMode = navigationModeController.addListener(this);
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
+ mPipOptional = pipOptional;
mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
mSystemActions = systemActions;
@@ -529,6 +533,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
+ mPipOptional.ifPresent(mNavigationBarView::registerPipExclusionBoundsChangeListener);
prepareNavigationBarView();
checkNavBarModes();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 339e504a3cf1..f7f34003be87 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -64,6 +64,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.FileDescriptor;
@@ -96,6 +97,7 @@ public class NavigationBarController implements Callbacks,
private final SysUiState mSysUiFlagsContainer;
private final BroadcastDispatcher mBroadcastDispatcher;
private final CommandQueue mCommandQueue;
+ private final Optional<Pip> mPipOptional;
private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<Recents> mRecentsOptional;
private final Lazy<StatusBar> mStatusBarLazy;
@@ -130,6 +132,7 @@ public class NavigationBarController implements Callbacks,
SysUiState sysUiFlagsContainer,
BroadcastDispatcher broadcastDispatcher,
CommandQueue commandQueue,
+ Optional<Pip> pipOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<Recents> recentsOptional,
Lazy<StatusBar> statusBarLazy,
@@ -152,6 +155,7 @@ public class NavigationBarController implements Callbacks,
mSysUiFlagsContainer = sysUiFlagsContainer;
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
+ mPipOptional = pipOptional;
mSplitScreenOptional = splitScreenOptional;
mRecentsOptional = recentsOptional;
mStatusBarLazy = statusBarLazy;
@@ -278,6 +282,7 @@ public class NavigationBarController implements Callbacks,
mSysUiFlagsContainer,
mBroadcastDispatcher,
mCommandQueue,
+ mPipOptional,
mSplitScreenOptional,
mRecentsOptional,
mStatusBarLazy,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 37c79ccff927..4c3ac404a49e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -92,6 +92,7 @@ import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.PrintWriter;
@@ -1292,6 +1293,10 @@ public class NavigationBarView extends FrameLayout implements
splitScreen.registerInSplitScreenListener(mDockedListener);
}
+ void registerPipExclusionBoundsChangeListener(Pip pip) {
+ pip.setPipExclusionBoundsChangeListener(mPipListener);
+ }
+
private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) {
pw.print(" " + caption + ": ");
if (button == null) {
@@ -1312,4 +1317,8 @@ public class NavigationBarView extends FrameLayout implements
mDockedStackExists = exists;
updateRecentsIcon();
});
+
+ private final Consumer<Rect> mPipListener = bounds -> post(() -> {
+ mEdgeBackGestureHandler.setPipStashExclusionBounds(bounds);
+ });
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index f9982d04e04b..6dee63cbeecd 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -24,6 +24,7 @@ import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
@@ -160,6 +161,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
private final Executor mMainExecutor;
+ private final Rect mPipExcludedBounds = new Rect();
private final Region mExcludeRegion = new Region();
private final Region mUnrestrictedExcludeRegion = new Region();
@@ -456,6 +458,13 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
return mIsEnabled && mIsBackGestureAllowed;
}
+ /**
+ * Update the PiP bounds, used for exclusion calculation.
+ */
+ public void setPipStashExclusionBounds(Rect bounds) {
+ mPipExcludedBounds.set(bounds);
+ }
+
private WindowManager.LayoutParams createLayoutParams() {
Resources resources = mContext.getResources();
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
@@ -556,6 +565,11 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
return false;
}
+ // If the point is inside the PiP excluded bounds, then drop it.
+ if (mPipExcludedBounds.contains(x, y)) {
+ return false;
+ }
+
if (mUseMLModel && (results = getBackGesturePredictionsCategory(x, y)) != -1) {
withinRange = results == 1 ? true : false;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 6a78c64638aa..c2ba6d5e9b06 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -69,12 +69,10 @@ public class PeopleSpaceActivity extends Activity {
*/
private void setTileViewsWithPriorityConversations() {
try {
- List<ShortcutInfo> shortcutInfos =
- PeopleSpaceUtils.getShortcutInfos(
- mContext, mNotificationManager, mPeopleManager);
+ List<ShortcutInfo> shortcutInfos = PeopleSpaceUtils.getShortcutInfos(mContext,
+ mNotificationManager, mPeopleManager);
for (ShortcutInfo conversation : shortcutInfos) {
- PeopleSpaceTileView tileView = new PeopleSpaceTileView(mContext,
- mPeopleSpaceLayout,
+ PeopleSpaceTileView tileView = new PeopleSpaceTileView(mContext, mPeopleSpaceLayout,
conversation.getId());
setTileView(tileView, conversation);
}
@@ -84,20 +82,14 @@ public class PeopleSpaceActivity extends Activity {
}
/** Sets {@code tileView} with the data in {@code conversation}. */
- private void setTileView(PeopleSpaceTileView tileView,
- ShortcutInfo shortcutInfo) {
+ private void setTileView(PeopleSpaceTileView tileView, ShortcutInfo shortcutInfo) {
try {
- int userId = UserHandle.getUserHandleForUid(
- shortcutInfo.getUserId()).getIdentifier();
+ int userId = UserHandle.getUserHandleForUid(shortcutInfo.getUserId()).getIdentifier();
String pkg = shortcutInfo.getPackage();
- long lastInteraction = mPeopleManager.getLastInteraction(
- pkg, userId,
+ long lastInteraction = mPeopleManager.getLastInteraction(pkg, userId,
shortcutInfo.getId());
- String status = lastInteraction != 0l ? mContext.getString(
- R.string.last_interaction_status,
- PeopleSpaceUtils.getLastInteractionString(
- lastInteraction)) : mContext.getString(R.string.basic_status);
+ String status = PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction);
tileView.setStatus(status);
tileView.setName(shortcutInfo.getLabel().toString());
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 1a9dd712bd0e..c983147961bf 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -31,6 +31,8 @@ import android.icu.util.MeasureUnit;
import android.provider.Settings;
import android.service.notification.ConversationChannelWrapper;
+import com.android.systemui.R;
+
import java.time.Duration;
import java.util.List;
import java.util.Locale;
@@ -38,25 +40,24 @@ import java.util.stream.Collectors;
/** Utils class for People Space. */
public class PeopleSpaceUtils {
- private static final String TAG = "PeopleSpaceUtils";
-
/** Turns on debugging information about People Space. */
public static final boolean DEBUG = true;
+ private static final String TAG = "PeopleSpaceUtils";
+ private static final int DAYS_IN_A_WEEK = 7;
+ private static final int MIN_HOUR = 1;
+ private static final int ONE_DAY = 1;
/** Returns a list of {@link ShortcutInfo} corresponding to user's conversations. */
- public static List<ShortcutInfo> getShortcutInfos(
- Context context,
- INotificationManager notificationManager,
- IPeopleManager peopleManager
- ) throws Exception {
+ public static List<ShortcutInfo> getShortcutInfos(Context context,
+ INotificationManager notificationManager, IPeopleManager peopleManager)
+ throws Exception {
boolean showAllConversations = Settings.Global.getInt(context.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
- List<ConversationChannelWrapper> conversations =
- notificationManager.getConversations(
- !showAllConversations /* priority only */).getList();
+ List<ConversationChannelWrapper> conversations = notificationManager.getConversations(
+ !showAllConversations /* priority only */).getList();
List<ShortcutInfo> shortcutInfos = conversations.stream().filter(
- c -> shouldKeepConversation(c)).map(
- c -> c.getShortcutInfo()).collect(Collectors.toList());
+ c -> shouldKeepConversation(c)).map(c -> c.getShortcutInfo()).collect(
+ Collectors.toList());
if (showAllConversations) {
List<ConversationChannel> recentConversations =
peopleManager.getRecentConversations().getList();
@@ -85,11 +86,8 @@ public class PeopleSpaceUtils {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
// Single color bitmap will be created of 1x1 pixel
} else {
- bitmap = Bitmap.createBitmap(
- drawable.getIntrinsicWidth(),
- drawable.getIntrinsicHeight(),
- Bitmap.Config.ARGB_8888
- );
+ bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
@@ -98,28 +96,31 @@ public class PeopleSpaceUtils {
return bitmap;
}
- /** Returns a readable representation of {@code lastInteraction}. */
- public static String getLastInteractionString(long lastInteraction) {
+ /** Returns a readable status describing the {@code lastInteraction}. */
+ public static String getLastInteractionString(Context context, long lastInteraction) {
+ if (lastInteraction == 0L) {
+ return context.getString(R.string.basic_status);
+ }
long now = System.currentTimeMillis();
- Duration durationSinceLastInteraction = Duration.ofMillis(
- now - lastInteraction);
+ Duration durationSinceLastInteraction = Duration.ofMillis(now - lastInteraction);
MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(),
MeasureFormat.FormatWidth.WIDE);
- if (durationSinceLastInteraction.toDays() >= 1) {
- return
- formatter
- .formatMeasures(new Measure(durationSinceLastInteraction.toDays(),
- MeasureUnit.DAY));
- } else if (durationSinceLastInteraction.toHours() >= 1) {
- return formatter.formatMeasures(new Measure(durationSinceLastInteraction.toHours(),
- MeasureUnit.HOUR));
- } else if (durationSinceLastInteraction.toMinutes() >= 1) {
- return formatter.formatMeasures(new Measure(durationSinceLastInteraction.toMinutes(),
- MeasureUnit.MINUTE));
+ if (durationSinceLastInteraction.toHours() < MIN_HOUR) {
+ return context.getString(R.string.last_interaction_status_less_than,
+ formatter.formatMeasures(new Measure(MIN_HOUR, MeasureUnit.HOUR)));
+ } else if (durationSinceLastInteraction.toDays() < ONE_DAY) {
+ return context.getString(R.string.last_interaction_status, formatter.formatMeasures(
+ new Measure(durationSinceLastInteraction.toHours(), MeasureUnit.HOUR)));
+ } else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK) {
+ return context.getString(R.string.last_interaction_status, formatter.formatMeasures(
+ new Measure(durationSinceLastInteraction.toDays(), MeasureUnit.DAY)));
} else {
- return formatter.formatMeasures(
- new Measure(durationSinceLastInteraction.toMillis() / 1000,
- MeasureUnit.SECOND));
+ return context.getString(durationSinceLastInteraction.toDays() == DAYS_IN_A_WEEK
+ ? R.string.last_interaction_status :
+ R.string.last_interaction_status_over,
+ formatter.formatMeasures(
+ new Measure(durationSinceLastInteraction.toDays() / DAYS_IN_A_WEEK,
+ MeasureUnit.WEEK)));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
new file mode 100644
index 000000000000..9b7cf6e85ada
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -0,0 +1,149 @@
+/*
+ * 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.people.widget;
+
+import android.app.NotificationChannel;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.appwidget.IAppWidgetService;
+import com.android.systemui.R;
+import com.android.systemui.people.PeopleSpaceUtils;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Manager for People Space widget. */
+@Singleton
+public class PeopleSpaceWidgetManager {
+ private static final String TAG = "PeopleSpaceWidgetMgr";
+ private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
+
+ private final Context mContext;
+ private IAppWidgetService mAppWidgetManager;
+
+ @Inject
+ public PeopleSpaceWidgetManager(Context context, IAppWidgetService appWidgetService) {
+ if (DEBUG) Log.d(TAG, "constructor");
+ mContext = context;
+ mAppWidgetManager = appWidgetService;
+ }
+
+ /** Constructor used for testing. */
+ @VisibleForTesting
+ protected PeopleSpaceWidgetManager(Context context) {
+ if (DEBUG) Log.d(TAG, "constructor");
+ mContext = context;
+ mAppWidgetManager = IAppWidgetService.Stub.asInterface(
+ ServiceManager.getService(Context.APPWIDGET_SERVICE));
+ }
+
+ /** AppWidgetManager setter used for testing. */
+ @VisibleForTesting
+ protected void setAppWidgetManager(IAppWidgetService appWidgetService) {
+ mAppWidgetManager = appWidgetService;
+ }
+
+ /** Updates People Space widgets. */
+ public void updateWidgets() {
+ try {
+ if (DEBUG) Log.d(TAG, "updateWidgets called");
+ int[] widgetIds = mAppWidgetManager.getAppWidgetIds(
+ new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
+ );
+
+ if (widgetIds.length == 0) {
+ if (DEBUG) Log.d(TAG, "no widgets to update");
+ return;
+ }
+
+ if (DEBUG) Log.d(TAG, "updating " + widgetIds.length + " widgets");
+ mAppWidgetManager
+ .notifyAppWidgetViewDataChanged(mContext.getOpPackageName(), widgetIds,
+ R.id.widget_list_view);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception: " + e);
+ }
+ }
+
+ /**
+ * Attaches the manager to the pipeline, making it ready to receive events. Should only be
+ * called once.
+ */
+ public void attach(NotificationListener listenerService) {
+ if (DEBUG) Log.d(TAG, "attach");
+ listenerService.addNotificationHandler(mListener);
+ }
+
+ private final NotificationHandler mListener = new NotificationHandler() {
+ @Override
+ public void onNotificationPosted(
+ StatusBarNotification sbn, NotificationListenerService.RankingMap rankingMap) {
+ if (DEBUG) Log.d(TAG, "onNotificationPosted");
+ updateWidgets();
+ }
+
+ @Override
+ public void onNotificationRemoved(
+ StatusBarNotification sbn,
+ NotificationListenerService.RankingMap rankingMap
+ ) {
+ if (DEBUG) Log.d(TAG, "onNotificationRemoved");
+ updateWidgets();
+ }
+
+ @Override
+ public void onNotificationRemoved(
+ StatusBarNotification sbn,
+ NotificationListenerService.RankingMap rankingMap,
+ int reason) {
+ if (DEBUG) Log.d(TAG, "onNotificationRemoved with reason " + reason);
+ updateWidgets();
+ }
+
+ @Override
+ public void onNotificationRankingUpdate(
+ NotificationListenerService.RankingMap rankingMap) { }
+
+ @Override
+ public void onNotificationsInitialized() {
+ if (DEBUG) Log.d(TAG, "onNotificationsInitialized");
+ updateWidgets();
+ }
+
+ @Override
+ public void onNotificationChannelModified(
+ String pkgName,
+ UserHandle user,
+ NotificationChannel channel,
+ int modificationType) {
+ if (DEBUG) Log.d(TAG, "onNotificationChannelModified");
+ if (channel.isConversation()) {
+ updateWidgets();
+ }
+ }
+ };
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
index c68c30632b6c..d86998604559 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
@@ -46,7 +46,7 @@ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.R
private PackageManager mPackageManager;
private LauncherApps mLauncherApps;
private List<ShortcutInfo> mShortcutInfos = new ArrayList<>();
- private Context mContext;
+ private final Context mContext;
public PeopleSpaceWidgetRemoteViewsFactory(Context context, Intent intent) {
this.mContext = context;
@@ -55,9 +55,8 @@ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.R
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "onCreate called");
- mNotificationManager =
- INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ mNotificationManager = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
mPackageManager = mContext.getPackageManager();
mPeopleManager = IPeopleManager.Stub.asInterface(
ServiceManager.getService(Context.PEOPLE_SERVICE));
@@ -71,9 +70,8 @@ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.R
*/
private void setTileViewsWithPriorityConversations() {
try {
- mShortcutInfos =
- PeopleSpaceUtils.getShortcutInfos(
- mContext, mNotificationManager, mPeopleManager);
+ mShortcutInfos = PeopleSpaceUtils.getShortcutInfos(mContext, mNotificationManager,
+ mPeopleManager);
} catch (Exception e) {
Log.e(TAG, "Couldn't retrieve conversations", e);
}
@@ -99,21 +97,16 @@ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.R
public RemoteViews getViewAt(int i) {
if (DEBUG) Log.d(TAG, "getViewAt called, index: " + i);
- RemoteViews personView =
- new RemoteViews(mContext.getPackageName(), R.layout.people_space_widget_item);
+ RemoteViews personView = new RemoteViews(mContext.getPackageName(),
+ R.layout.people_space_widget_item);
try {
ShortcutInfo shortcutInfo = mShortcutInfos.get(i);
- int userId = UserHandle.getUserHandleForUid(
- shortcutInfo.getUserId()).getIdentifier();
+ int userId = UserHandle.getUserHandleForUid(shortcutInfo.getUserId()).getIdentifier();
String pkg = shortcutInfo.getPackage();
- long lastInteraction = mPeopleManager.getLastInteraction(
- pkg, userId,
+ long lastInteraction = mPeopleManager.getLastInteraction(pkg, userId,
shortcutInfo.getId());
- String status = lastInteraction != 0L ? mContext.getString(
- R.string.last_interaction_status,
- PeopleSpaceUtils.getLastInteractionString(
- lastInteraction)) : mContext.getString(R.string.basic_status);
+ String status = PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction);
personView.setTextViewText(R.id.status, status);
personView.setTextViewText(R.id.name, shortcutInfo.getLabel().toString());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 3062a77bcbe1..8c7d4596cc0a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -63,7 +63,6 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
private int mPageToRestore = -1;
private int mLayoutOrientation;
private int mLayoutDirection;
- private int mHorizontalClipBound;
private final Rect mClippingRect;
private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger();
private int mExcessHeight;
@@ -333,7 +332,6 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
// Update bottom padding, useful for removing extra space once the panel page indicator is
// hidden.
Resources res = getContext().getResources();
- mHorizontalClipBound = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
setPadding(0, 0, 0,
getContext().getResources().getDimensionPixelSize(
R.dimen.qs_paged_tile_layout_padding_bottom));
@@ -351,7 +349,8 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
- mClippingRect.set(mHorizontalClipBound, 0, (r - l) - mHorizontalClipBound, b - t);
+ // Clip to margins
+ mClippingRect.set(0, 0, (r - l), b - t);
setClipBounds(mClippingRect);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 4d4195063227..e9207f1feff3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -19,7 +19,7 @@ import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnLayoutChangeListener;
-import com.android.systemui.Dependency;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTileView;
@@ -34,6 +34,7 @@ import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -57,7 +58,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
*/
private final ArrayList<View> mQuickQsViews = new ArrayList<>();
private final QuickQSPanel mQuickQsPanel;
- private final QSPanel mQsPanel;
private final QSPanelController mQsPanelController;
private final QuickQSPanelController mQuickQSPanelController;
private final QSSecurityFooter mSecurityFooter;
@@ -83,34 +83,36 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
private boolean mFullRows;
private int mNumQuickTiles;
private float mLastPosition;
- private QSTileHost mHost;
+ private final QSTileHost mHost;
+ private final Executor mExecutor;
+ private final TunerService mTunerService;
private boolean mShowCollapsedOnKeyguard;
@Inject
- public QSAnimator(QS qs, QuickQSPanel quickPanel, QSPanel panel,
- QSPanelController qsPanelController, QuickQSPanelController quickQSPanelController,
- QSTileHost qsTileHost,
- QSSecurityFooter securityFooter) {
+ public QSAnimator(QS qs, QuickQSPanel quickPanel, QSPanelController qsPanelController,
+ QuickQSPanelController quickQSPanelController, QSTileHost qsTileHost,
+ QSSecurityFooter securityFooter, @Main Executor executor, TunerService tunerService) {
mQs = qs;
mQuickQsPanel = quickPanel;
- mQsPanel = panel;
mQsPanelController = qsPanelController;
mQuickQSPanelController = quickQSPanelController;
mSecurityFooter = securityFooter;
mHost = qsTileHost;
+ mExecutor = executor;
+ mTunerService = tunerService;
mHost.addCallback(this);
- mQsPanel.addOnAttachStateChangeListener(this);
+ mQsPanelController.addOnAttachStateChangeListener(this);
qs.getView().addOnLayoutChangeListener(this);
- if (mQsPanel.isAttachedToWindow()) {
+ if (mQsPanelController.isAttachedToWindow()) {
onViewAttachedToWindow(null);
}
- QSTileLayout tileLayout = mQsPanel.getTileLayout();
+ QSTileLayout tileLayout = mQsPanelController.getTileLayout();
if (tileLayout instanceof PagedTileLayout) {
mPagedLayout = ((PagedTileLayout) tileLayout);
} else {
Log.w(TAG, "QS Not using page layout");
}
- panel.setPageListener(this);
+ mQsPanelController.setPageListener(this);
}
public void onRtlChanged() {
@@ -153,14 +155,14 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
@Override
public void onViewAttachedToWindow(View v) {
- Dependency.get(TunerService.class).addTunable(this, ALLOW_FANCY_ANIMATION,
+ mTunerService.addTunable(this, ALLOW_FANCY_ANIMATION,
MOVE_FULL_ROWS, QuickQSPanel.NUM_QUICK_TILES);
}
@Override
public void onViewDetachedFromWindow(View v) {
mHost.removeCallback(this);
- Dependency.get(TunerService.class).removeTunable(this);
+ mTunerService.removeTunable(this);
}
@Override
@@ -198,14 +200,12 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
int count = 0;
int[] loc1 = new int[2];
int[] loc2 = new int[2];
- int lastXDiff = 0;
- int lastX = 0;
clearAnimationState();
mAllViews.clear();
mQuickQsViews.clear();
- QSTileLayout tileLayout = mQsPanel.getTileLayout();
+ QSTileLayout tileLayout = mQsPanelController.getTileLayout();
mAllViews.add((View) tileLayout);
int height = mQs.getView() != null ? mQs.getView().getMeasuredHeight() : 0;
int width = mQs.getView() != null ? mQs.getView().getMeasuredWidth() : 0;
@@ -223,17 +223,17 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
View view = mQs.getView();
// This case: less tiles to animate in small displays.
- if (count < mQuickQsPanel.getTileLayout().getNumVisibleTiles() && mAllowFancy) {
+ if (count < mQuickQSPanelController.getTileLayout().getNumVisibleTiles()
+ && mAllowFancy) {
// Quick tiles.
QSTileView quickTileView = mQuickQSPanelController.getTileView(tile);
if (quickTileView == null) continue;
- lastX = loc1[0];
getRelativePosition(loc1, quickTileView.getIcon().getIconView(), view);
getRelativePosition(loc2, tileIcon, view);
final int xDiff = loc2[0] - loc1[0];
final int yDiff = loc2[1] - loc1[1];
- lastXDiff = loc1[0] - lastX;
+
if (count < tileLayout.getNumVisibleTiles()) {
// Move the quick tile right from its location to the new one.
@@ -254,7 +254,8 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
// xDiff is negative here and this makes it "more" negative
- final int translationX = mQsPanel.isLayoutRtl() ? xDiff - width : xDiff + width;
+ final int translationX =
+ mQsPanelController.isLayoutRtl() ? xDiff - width : xDiff + width;
translationXBuilder.addFloat(quickTileView, "translationX", 0,
translationX);
}
@@ -263,19 +264,8 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
mAllViews.add(tileView.getIcon());
mAllViews.add(quickTileView);
} else if (mFullRows && isIconInAnimatedRow(count)) {
- // TODO: Refactor some of this, it shares a lot with the above block.
- // Move the last tile position over by the last difference between quick tiles.
- // This makes the extra icons seems as if they are coming from positions in the
- // quick panel.
- loc1[0] += lastXDiff;
- getRelativePosition(loc2, tileIcon, view);
- final int xDiff = loc2[0] - loc1[0];
- final int yDiff = loc2[1] - loc1[1];
- firstPageBuilder.addFloat(tileView, "translationY", heightDiff, 0);
- translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
- translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
- translationYBuilder.addFloat(tileIcon, "translationY", -yDiff, 0);
+ firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
mAllViews.add(tileIcon);
} else {
@@ -288,7 +278,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
if (mAllowFancy) {
// Make brightness appear static position and alpha in through second half.
- View brightness = mQsPanel.getBrightnessView();
+ View brightness = mQsPanelController.getBrightnessView();
if (brightness != null) {
firstPageBuilder.addFloat(brightness, "translationY", heightDiff, 0);
mBrightnessAnimator = new TouchAnimator.Builder()
@@ -311,13 +301,13 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
// Fade in the security footer and the divider as we reach the final position
builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
builder.addFloat(mSecurityFooter.getView(), "alpha", 0, 1);
- if (mQsPanel.getDivider() != null) {
- builder.addFloat(mQsPanel.getDivider(), "alpha", 0, 1);
+ if (mQsPanelController.getDivider() != null) {
+ builder.addFloat(mQsPanelController.getDivider(), "alpha", 0, 1);
}
mAllPagesDelayedAnimator = builder.build();
mAllViews.add(mSecurityFooter.getView());
- if (mQsPanel.getDivider() != null) {
- mAllViews.add(mQsPanel.getDivider());
+ if (mQsPanelController.getDivider() != null) {
+ mAllViews.add(mQsPanelController.getDivider());
}
float px = 0;
@@ -447,14 +437,14 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
- mQsPanel.post(mUpdateAnimators);
+ mExecutor.execute(mUpdateAnimators);
}
@Override
public void onTilesChanged() {
// Give the QS panels a moment to generate their new tiles, then create all new animators
// hooked up to the new views.
- mQsPanel.post(mUpdateAnimators);
+ mExecutor.execute(mUpdateAnimators);
}
private final TouchAnimator.Listener mNonFirstPageListener =
@@ -470,11 +460,8 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
}
};
- private Runnable mUpdateAnimators = new Runnable() {
- @Override
- public void run() {
- updateAnimators();
- setCurrentPosition();
- }
+ private final Runnable mUpdateAnimators = () -> {
+ updateAnimators();
+ setCurrentPosition();
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index a35151068bee..f4571d7d3609 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -35,7 +35,7 @@ import com.android.systemui.qs.customize.QSCustomizer;
import com.android.wm.shell.animation.PhysicsAnimator;
/**
- * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
+ * Wrapper view with background which contains {@link QSPanel} and {@link QuickStatusBarHeader}
*/
public class QSContainerImpl extends FrameLayout {
@@ -57,7 +57,6 @@ public class QSContainerImpl extends FrameLayout {
SpringForce.DAMPING_RATIO_LOW_BOUNCY);
private int mBackgroundBottom = -1;
private int mHeightOverride = -1;
- private QSPanel mQSPanel;
private View mQSDetail;
private QuickStatusBarHeader mHeader;
private float mQsExpansion;
@@ -66,8 +65,6 @@ public class QSContainerImpl extends FrameLayout {
private View mQSPanelContainer;
private View mBackground;
- private View mBackgroundGradient;
- private View mStatusBarBackground;
private int mSideMargins;
private boolean mQsDisabled;
@@ -81,31 +78,24 @@ public class QSContainerImpl extends FrameLayout {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mQSPanel = findViewById(R.id.quick_settings_panel);
mQSPanelContainer = findViewById(R.id.expanded_qs_scroll_view);
mQSDetail = findViewById(R.id.qs_detail);
mHeader = findViewById(R.id.header);
mQSCustomizer = findViewById(R.id.qs_customize);
mDragHandle = findViewById(R.id.qs_drag_handle_view);
mBackground = findViewById(R.id.quick_settings_background);
- mStatusBarBackground = findViewById(R.id.quick_settings_status_bar_background);
- mBackgroundGradient = findViewById(R.id.quick_settings_gradient_view);
- updateResources();
mHeader.getHeaderQsPanel().setMediaVisibilityChangedListener((visible) -> {
if (mHeader.getHeaderQsPanel().isShown()) {
mAnimateBottomOnNextLayout = true;
}
});
- mQSPanel.setMediaVisibilityChangedListener((visible) -> {
- if (mQSPanel.isShown()) {
- mAnimateBottomOnNextLayout = true;
- }
- });
-
-
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
}
+ void onMediaVisibilityChanged(boolean qsVisible) {
+ mAnimateBottomOnNextLayout = qsVisible;
+ }
+
private void setBackgroundBottom(int value) {
// We're saving the bottom separately since otherwise the bottom would be overridden in
// the layout and the animation wouldn't properly start at the old position.
@@ -123,8 +113,6 @@ public class QSContainerImpl extends FrameLayout {
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- setBackgroundGradientVisibility(newConfig);
- updateResources();
mSizePoint.set(0, 0); // Will be retrieved on next measure pass.
}
@@ -193,11 +181,10 @@ public class QSContainerImpl extends FrameLayout {
final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
if (disabled == mQsDisabled) return;
mQsDisabled = disabled;
- setBackgroundGradientVisibility(getResources().getConfiguration());
mBackground.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE);
}
- private void updateResources() {
+ void updateResources(QSPanelController qsPanelController) {
LayoutParams layoutParams = (LayoutParams) mQSPanelContainer.getLayoutParams();
layoutParams.topMargin = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
@@ -209,7 +196,7 @@ public class QSContainerImpl extends FrameLayout {
boolean marginsChanged = padding != mContentPadding;
mContentPadding = padding;
if (marginsChanged) {
- updatePaddingsAndMargins();
+ updatePaddingsAndMargins(qsPanelController);
}
}
@@ -259,27 +246,16 @@ public class QSContainerImpl extends FrameLayout {
+ mHeader.getHeight();
}
- private void setBackgroundGradientVisibility(Configuration newConfig) {
- if (newConfig.orientation == ORIENTATION_LANDSCAPE) {
- mBackgroundGradient.setVisibility(View.INVISIBLE);
- mStatusBarBackground.setVisibility(View.INVISIBLE);
- } else {
- mBackgroundGradient.setVisibility(mQsDisabled ? View.INVISIBLE : View.VISIBLE);
- mStatusBarBackground.setVisibility(View.VISIBLE);
- }
- }
-
public void setExpansion(float expansion) {
mQsExpansion = expansion;
mDragHandle.setAlpha(1.0f - expansion);
updateExpansion();
}
- private void updatePaddingsAndMargins() {
+ private void updatePaddingsAndMargins(QSPanelController qsPanelController) {
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
- if (view == mStatusBarBackground || view == mBackgroundGradient
- || view == mQSCustomizer) {
+ if (view == mQSCustomizer) {
// Some views are always full width or have dependent padding
continue;
}
@@ -288,8 +264,8 @@ public class QSContainerImpl extends FrameLayout {
lp.leftMargin = mSideMargins;
if (view == mQSPanelContainer) {
// QS panel lays out some of its content full width
- mQSPanel.setContentMargins(mContentPadding, mContentPadding);
- Pair<Integer, Integer> margins = mQSPanel.getVisualSideMargins();
+ qsPanelController.setContentMargins(mContentPadding, mContentPadding);
+ Pair<Integer, Integer> margins = qsPanelController.getVisualSideMargins();
// Apply paddings based on QSPanel
mQSCustomizer.setContentPaddings(margins.first, margins.second);
} else if (view == mHeader) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
index 4b9f4316f2bf..27d3221b8e98 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImplController.java
@@ -16,7 +16,10 @@
package com.android.systemui.qs;
+import android.content.res.Configuration;
+
import com.android.systemui.qs.dagger.QSScope;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
@@ -24,13 +27,26 @@ import javax.inject.Inject;
/** */
@QSScope
public class QSContainerImplController extends ViewController<QSContainerImpl> {
+ private final QSPanelController mQsPanelController;
private final QuickStatusBarHeaderController mQuickStatusBarHeaderController;
+ private final ConfigurationController mConfigurationController;
+
+ private final ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ mView.updateResources(mQsPanelController);
+ }
+ };
@Inject
- QSContainerImplController(QSContainerImpl view,
- QuickStatusBarHeaderController quickStatusBarHeaderController) {
+ QSContainerImplController(QSContainerImpl view, QSPanelController qsPanelController,
+ QuickStatusBarHeaderController quickStatusBarHeaderController,
+ ConfigurationController configurationController) {
super(view);
+ mQsPanelController = qsPanelController;
mQuickStatusBarHeaderController = quickStatusBarHeaderController;
+ mConfigurationController = configurationController;
}
@Override
@@ -44,10 +60,19 @@ public class QSContainerImplController extends ViewController<QSContainerImpl> {
@Override
protected void onViewAttached() {
+ mView.updateResources(mQsPanelController);
+ mQsPanelController.setMediaVisibilityChangedListener((visible) -> {
+ if (mQsPanelController.isShown()) {
+ mView.onMediaVisibilityChanged(true);
+ }
+ });
+
+ mConfigurationController.addCallback(mConfigurationListener);
}
@Override
protected void onViewDetached() {
+ mConfigurationController.removeCallback(mConfigurationListener);
}
public QSContainerImpl getView() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index cfcceb2b2951..619729e55314 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -57,7 +57,7 @@ public class QSDetail extends LinearLayout {
protected TextView mDetailDoneButton;
private QSDetailClipper mClipper;
private DetailAdapter mDetailAdapter;
- private QSPanel mQsPanel;
+ private QSPanelController mQsPanelController;
protected View mQsDetailHeader;
protected TextView mQsDetailHeaderTitle;
@@ -114,19 +114,20 @@ public class QSDetail extends LinearLayout {
public void onClick(View v) {
announceForAccessibility(
mContext.getString(R.string.accessibility_desc_quick_settings));
- mQsPanel.closeDetail();
+ mQsPanelController.closeDetail();
}
};
mDetailDoneButton.setOnClickListener(doneListener);
}
/** */
- public void setQsPanel(QSPanel panel, QuickStatusBarHeader header, QSFooter footer) {
- mQsPanel = panel;
+ public void setQsPanel(QSPanelController panelController, QuickStatusBarHeader header,
+ QSFooter footer) {
+ mQsPanelController = panelController;
mHeader = header;
mFooter = footer;
mHeader.setCallback(mQsPanelCallback);
- mQsPanel.setCallback(mQsPanelCallback);
+ mQsPanelController.setCallback(mQsPanelCallback);
}
public void setHost(QSTileHost host) {
@@ -221,7 +222,7 @@ public class QSDetail extends LinearLayout {
listener = mTeardownDetailWhenDone;
mHeader.setVisibility(View.VISIBLE);
mFooter.setVisibility(View.VISIBLE);
- mQsPanel.setGridContentVisibility(true);
+ mQsPanelController.setGridContentVisibility(true);
mQsPanelCallback.onScanStateChanged(false);
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
@@ -362,7 +363,7 @@ public class QSDetail extends LinearLayout {
public void onAnimationEnd(Animator animation) {
// Only hide content if still in detail state.
if (mDetailAdapter != null) {
- mQsPanel.setGridContentVisibility(false);
+ mQsPanelController.setGridContentVisibility(false);
mHeader.setVisibility(View.INVISIBLE);
mFooter.setVisibility(View.INVISIBLE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java
new file mode 100644
index 000000000000..7d87e174d95d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailDisplayer.java
@@ -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.
+ */
+
+package com.android.systemui.qs;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.plugins.qs.DetailAdapter;
+
+import javax.inject.Inject;
+
+/**
+ * Proxy class for talking with the QSPanel and showing custom content within it.
+ */
+@SysUISingleton
+public class QSDetailDisplayer {
+ private QSPanelController mQsPanelController;
+
+ @Inject
+ public QSDetailDisplayer() {
+ }
+
+ public void setQsPanelController(QSPanelController qsPanelController) {
+ mQsPanelController = qsPanelController;
+ }
+
+ /** Show the supplied DetailAdapter in the Quick Settings. */
+ public void showDetailAdapter(DetailAdapter detailAdapter, int x, int y) {
+ if (mQsPanelController != null) {
+ mQsPanelController.showDetailDapater(detailAdapter, x, y);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 0a2533a8426e..e38bd4bd9a38 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -17,23 +17,11 @@ package com.android.systemui.qs;
import android.view.View;
-import androidx.annotation.Nullable;
-
/**
* The bottom footer of the quick settings panel.
*/
public interface QSFooter {
/**
- * Sets the given {@link QSPanel} to be the one that will display the quick settings.
- */
- void setQSPanel(@Nullable QSPanel panel);
-
- /**
- * Sets the given {@link QuickQSPanel} to be the one associated with quick settings.
- */
- default void setQQSPanel(@Nullable QuickQSPanel panel) {};
-
- /**
* Sets whether or not the footer should be visible.
*
* @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE} or {@link View#GONE}.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
index 8b9dae14c809..7e20be6826dc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
@@ -59,7 +59,6 @@ public class QSFooterView extends FrameLayout {
private boolean mShouldShowBuildText;
private boolean mQsDisabled;
- private QuickQSPanel mQuickQsPanel;
private boolean mExpanded;
@@ -115,8 +114,6 @@ public class QSFooterView extends FrameLayout {
updateResources();
- addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight,
- oldBottom) -> updateAnimator(right - left));
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
setBuildText();
}
@@ -139,9 +136,7 @@ public class QSFooterView extends FrameLayout {
}
}
- private void updateAnimator(int width) {
- int numTiles = mQuickQsPanel != null ? mQuickQsPanel.getNumQuickTiles()
- : QuickQSPanel.getDefaultMaxTiles();
+ void updateAnimator(int width, int numTiles) {
int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size)
- mContext.getResources().getDimensionPixelSize(dimen.qs_quick_tile_padding);
int remaining = (width - numTiles * size) / (numTiles - 1);
@@ -289,19 +284,6 @@ public class QSFooterView extends FrameLayout {
return mExpanded && mMultiUserSwitch.isMultiUserEnabled();
}
- /** */
- public void setQSPanel(final QSPanel qsPanel) {
- if (qsPanel != null) {
- mMultiUserSwitch.setQsPanel(qsPanel);
- qsPanel.setFooterPageIndicator(mPageIndicator);
- }
- }
-
- public void setQQSPanel(@Nullable QuickQSPanel panel) {
- mQuickQsPanel = panel;
- }
-
-
void onUserInfoChanged(Drawable picture, boolean isGuestUser) {
if (picture != null && isGuestUser && !(picture instanceof UserIconDrawable)) {
picture = picture.getConstantState().newDrawable(getResources()).mutate();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index e3af04bdc31e..8110fda1330c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -26,8 +26,6 @@ import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
-import androidx.annotation.Nullable;
-
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -35,6 +33,7 @@ import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.phone.MultiUserSwitch;
import com.android.systemui.statusbar.phone.SettingsButton;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.UserInfoController;
@@ -55,11 +54,15 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
private final DeviceProvisionedController mDeviceProvisionedController;
private final UserTracker mUserTracker;
private final QSPanelController mQsPanelController;
+ private final QSDetailDisplayer mQsDetailDisplayer;
+ private final QuickQSPanelController mQuickQSPanelController;
private final TunerService mTunerService;
private final MetricsLogger mMetricsLogger;
private final SettingsButton mSettingsButton;
private final TextView mBuildText;
private final View mEdit;
+ private final MultiUserSwitch mMultiUserSwitch;
+ private final PageIndicator mPageIndicator;
private final UserInfoController.OnUserInfoChangedListener mOnUserInfoChangedListener =
new UserInfoController.OnUserInfoChangedListener() {
@@ -119,8 +122,9 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
QSFooterViewController(QSFooterView view, UserManager userManager,
UserInfoController userInfoController, ActivityStarter activityStarter,
DeviceProvisionedController deviceProvisionedController, UserTracker userTracker,
- QSPanelController qsPanelController, TunerService tunerService,
- MetricsLogger metricsLogger) {
+ QSPanelController qsPanelController, QSDetailDisplayer qsDetailDisplayer,
+ QuickQSPanelController quickQSPanelController,
+ TunerService tunerService, MetricsLogger metricsLogger) {
super(view);
mUserManager = userManager;
mUserInfoController = userInfoController;
@@ -128,17 +132,24 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
mDeviceProvisionedController = deviceProvisionedController;
mUserTracker = userTracker;
mQsPanelController = qsPanelController;
+ mQsDetailDisplayer = qsDetailDisplayer;
+ mQuickQSPanelController = quickQSPanelController;
mTunerService = tunerService;
mMetricsLogger = metricsLogger;
mSettingsButton = mView.findViewById(R.id.settings_button);
mBuildText = mView.findViewById(R.id.build);
mEdit = mView.findViewById(android.R.id.edit);
+ mMultiUserSwitch = mView.findViewById(R.id.multi_user_switch);
+ mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
}
-
@Override
protected void onViewAttached() {
+ mView.addOnLayoutChangeListener(
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
+ mView.updateAnimator(
+ right - left, mQuickQSPanelController.getNumQuickTiles()));
mSettingsButton.setOnClickListener(mSettingsOnClickListener);
mBuildText.setOnLongClickListener(view -> {
CharSequence buildText = mBuildText.getText();
@@ -158,6 +169,8 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
mActivityStarter.postQSRunnableDismissingKeyguard(() ->
mQsPanelController.showEdit(view)));
+ mMultiUserSwitch.setQSDetailDisplayer(mQsDetailDisplayer);
+ mQsPanelController.setFooterPageIndicator(mPageIndicator);
mView.updateEverything(isTunerEnabled());
}
@@ -166,12 +179,6 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
setListening(false);
}
-
- @Override
- public void setQSPanel(@Nullable QSPanel panel) {
- mView.setQSPanel(panel);
- }
-
@Override
public void setVisibility(int visibility) {
mView.setVisibility(visibility);
@@ -220,11 +227,6 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
}
@Override
- public void setQQSPanel(@Nullable QuickQSPanel panel) {
- mView.setQQSPanel(panel);
- }
-
- @Override
public void disable(int state1, int state2, boolean animate) {
mView.disable(state2, isTunerEnabled());
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 1a7d366d84b4..043f5f1610a6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -16,6 +16,9 @@ package com.android.systemui.qs;
import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
+import static com.android.systemui.media.dagger.MediaModule.QS_PANEL;
+import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.res.Configuration;
@@ -38,7 +41,7 @@ import com.android.systemui.R;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSFragmentComponent;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarState;
@@ -50,6 +53,7 @@ import com.android.systemui.util.LifecycleFragment;
import com.android.systemui.util.Utils;
import javax.inject.Inject;
+import javax.inject.Named;
public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Callbacks,
StatusBarStateController.StateListener {
@@ -69,7 +73,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private QSAnimator mQSAnimator;
private HeightListener mPanelView;
protected QuickStatusBarHeader mHeader;
- private QSCustomizer mQSCustomizer;
protected NonInterceptingScrollView mQSPanelScrollView;
private QSDetail mQSDetail;
private boolean mListening;
@@ -81,6 +84,10 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private final InjectionInflationController mInjectionInflater;
+ private final CommandQueue mCommandQueue;
+ private final QSDetailDisplayer mQsDetailDisplayer;
+ private final MediaHost mQsMediaHost;
+ private final MediaHost mQqsMediaHost;
private final QSFragmentComponent.Factory mQsComponentFactory;
private final QSTileHost mHost;
private boolean mShowCollapsedOnKeyguard;
@@ -97,14 +104,21 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private float mLastHeaderTranslation;
private QSPanelController mQSPanelController;
private QuickQSPanelController mQuickQSPanelController;
+ private QSCustomizerController mQSCustomizerController;
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
InjectionInflationController injectionInflater, QSTileHost qsTileHost,
StatusBarStateController statusBarStateController, CommandQueue commandQueue,
+ QSDetailDisplayer qsDetailDisplayer, @Named(QS_PANEL) MediaHost qsMediaHost,
+ @Named(QUICK_QS_PANEL) MediaHost qqsMediaHost,
QSFragmentComponent.Factory qsComponentFactory) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
mInjectionInflater = injectionInflater;
+ mCommandQueue = commandQueue;
+ mQsDetailDisplayer = qsDetailDisplayer;
+ mQsMediaHost = qsMediaHost;
+ mQqsMediaHost = qqsMediaHost;
mQsComponentFactory = qsComponentFactory;
commandQueue.observe(getLifecycle(), this);
mHost = qsTileHost;
@@ -144,20 +158,23 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mQSPanelController.setHeaderContainer(view.findViewById(R.id.header_text_container));
mFooter = qsFragmentComponent.getQSFooter();
+ mQsDetailDisplayer.setQsPanelController(mQSPanelController);
+
mQSContainerImplController = qsFragmentComponent.getQSContainerImplController();
mQSContainerImplController.init();
mContainer = mQSContainerImplController.getView();
- mQSDetail.setQsPanel(mQSPanelController.getView(), mHeader, mFooter);
+ mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter);
mQSAnimator = qsFragmentComponent.getQSAnimator();
- mQSCustomizer = view.findViewById(R.id.qs_customize);
- mQSCustomizer.setQs(this);
+ mQSCustomizerController = qsFragmentComponent.getQSCustomizerController();
+ mQSCustomizerController.init();
+ mQSCustomizerController.setQs(this);
if (savedInstanceState != null) {
setExpanded(savedInstanceState.getBoolean(EXTRA_EXPANDED));
setListening(savedInstanceState.getBoolean(EXTRA_LISTENING));
setEditLocation(view);
- mQSCustomizer.restoreInstanceState(savedInstanceState);
+ mQSCustomizerController.restoreInstanceState(savedInstanceState);
if (mQsExpanded) {
mQSPanelController.getTileLayout().restoreInstanceState(savedInstanceState);
}
@@ -181,7 +198,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
if (mListening) {
setListening(false);
}
- mQSCustomizer.setQs(null);
+ mQSCustomizerController.setQs(null);
+ mQsDetailDisplayer.setQsPanelController(null);
}
@Override
@@ -189,7 +207,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_EXPANDED, mQsExpanded);
outState.putBoolean(EXTRA_LISTENING, mListening);
- mQSCustomizer.saveInstanceState(outState);
+ mQSCustomizerController.saveInstanceState(outState);
if (mQsExpanded) {
mQSPanelController.getTileLayout().saveInstanceState(outState);
}
@@ -236,25 +254,22 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
int[] loc = edit.getLocationOnScreen();
int x = loc[0] + edit.getWidth() / 2;
int y = loc[1] + edit.getHeight() / 2;
- mQSCustomizer.setEditLocation(x, y);
+ mQSCustomizerController.setEditLocation(x, y);
}
@Override
public void setContainer(ViewGroup container) {
if (container instanceof NotificationsQuickSettingsContainer) {
- mQSCustomizer.setContainer((NotificationsQuickSettingsContainer) container);
+ mQSCustomizerController.setContainer((NotificationsQuickSettingsContainer) container);
}
}
@Override
public boolean isCustomizing() {
- return mQSCustomizer.isCustomizing();
+ return mQSCustomizerController.isCustomizing();
}
public void setHost(QSTileHost qsh) {
- mQSPanelController.setCustomizer(mQSCustomizer);
- mHeader.setQSPanel(mQSPanelController.getView());
- mFooter.setQSPanel(mQSPanelController.getView());
mQSDetail.setHost(qsh);
}
@@ -321,17 +336,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
return mQSPanelController;
}
- public QSPanel getQsPanel() {
- return mQSPanelController.getView();
- }
-
- public QSCustomizer getCustomizer() {
- return mQSCustomizer;
- }
-
@Override
public boolean isShowingDetail() {
- return mQSPanelController.isShowingCustomize() || mQSDetail.isShowingDetail();
+ return mQSCustomizerController.isCustomizing() || mQSDetail.isShowingDetail();
}
@Override
@@ -417,7 +424,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
}
}
mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
- mQSPanelController.getQsTileRevealController().setExpansion(expansion);
+ mQSPanelController.setRevealExpansion(expansion);
mQSPanelController.getTileLayout().setExpansion(expansion);
mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff);
if (fullyCollapsed) {
@@ -456,11 +463,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
float expandedMediaPosition = absoluteBottomPosition - mQSPanelScrollView.getScrollY()
+ mQSPanelScrollView.getScrollRange();
// The expanded media host should never move below the laid out position
- pinToBottom(
- expandedMediaPosition, mQSPanelController.getMediaHost(), true /* expanded */);
+ pinToBottom(expandedMediaPosition, mQsMediaHost, true /* expanded */);
// The expanded media host should never move above the laid out position
- pinToBottom(absoluteBottomPosition, mHeader.getHeaderQsPanel().getMediaHost(),
- false /* expanded */);
+ pinToBottom(absoluteBottomPosition, mQqsMediaHost, false /* expanded */);
}
}
@@ -553,9 +558,10 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
public void notifyCustomizeChanged() {
// The customize state changed, so our height changed.
mContainer.updateExpansion();
- mQSPanelScrollView.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE
+ mQSPanelScrollView.setVisibility(!mQSCustomizerController.isCustomizing() ? View.VISIBLE
: View.INVISIBLE);
- mFooter.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+ mFooter.setVisibility(
+ !mQSCustomizerController.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
// Let the panel know the position changed and it needs to update where notifications
// and whatnot are.
mPanelView.onQsHeightChanged();
@@ -567,7 +573,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
*/
@Override
public int getDesiredHeight() {
- if (mQSCustomizer.isCustomizing()) {
+ if (mQSCustomizerController.isCustomizing()) {
return getView().getHeight();
}
if (mQSDetail.isClosingDetail()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 76f244652cd9..8955a7e27dee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -46,17 +46,14 @@ import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
-import com.android.systemui.settings.ToggleSliderView;
+import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
-import com.android.systemui.statusbar.policy.BrightnessMirrorController.BrightnessMirrorListener;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.animation.DisappearParameters;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
@@ -64,7 +61,7 @@ import javax.inject.Inject;
import javax.inject.Named;
/** View that represents the quick settings tile panel (when expanded/pulled down). **/
-public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorListener {
+public class QSPanel extends LinearLayout implements Tunable {
public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
public static final String QS_SHOW_HEADER = "qs_show_header";
@@ -77,14 +74,15 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
/**
* The index where the content starts that needs to be moved between parents
*/
- private final int mMovableContentStartIndex;
+ private int mMovableContentStartIndex;
@Nullable
protected View mBrightnessView;
+ @Nullable
+ protected BrightnessSlider mToggleSliderController;
private final H mHandler = new H();
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
- private QSTileRevealController mQsTileRevealController;
/** Whether or not the QS media player feature is enabled. */
protected boolean mUsingMediaPlayer;
private int mVisualMarginStart;
@@ -117,7 +115,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
private int mVisualTilePadding;
private boolean mUsingHorizontalLayout;
- private QSCustomizer mCustomizePanel;
private Record mDetailRecord;
private BrightnessMirrorController mBrightnessMirrorController;
@@ -157,7 +154,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
setOrientation(VERTICAL);
- addViewsAboveTiles();
mMovableContentStartIndex = getChildCount();
mRegularTileLayout = createRegularTileLayout();
mTileLayout = mRegularTileLayout;
@@ -186,10 +182,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
initMediaHostState();
}
- if (mRegularTileLayout instanceof PagedTileLayout) {
- mQsTileRevealController = new QSTileRevealController(mContext, this,
- (PagedTileLayout) mRegularTileLayout);
- }
mQSLogger.logAllTilesChangeListening(mListening, getDumpableTag(), "");
}
@@ -199,10 +191,19 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
}
}
- protected void addViewsAboveTiles() {
- mBrightnessView = LayoutInflater.from(mContext).inflate(
- R.layout.quick_settings_brightness_dialog, this, false);
- addView(mBrightnessView);
+ /**
+ * Add brightness view above the tile layout.
+ *
+ * Used to add the brightness slider after construction.
+ */
+ public void setBrightnessView(@NonNull View view) {
+ if (mBrightnessView != null) {
+ removeView(mBrightnessView);
+ mMovableContentStartIndex--;
+ }
+ addView(view, 0);
+ mBrightnessView = view;
+ mMovableContentStartIndex++;
}
/** */
@@ -297,14 +298,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
setMeasuredDimension(getMeasuredWidth(), height);
}
- public QSTileRevealController getQsTileRevealController() {
- return mQsTileRevealController;
- }
-
- public boolean isShowingCustomize() {
- return mCustomizePanel != null && mCustomizePanel.isCustomizing();
- }
-
@Override
protected void onDetachedFromWindow() {
if (mTileLayout != null) {
@@ -337,22 +330,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
}
}
- public void setBrightnessMirror(BrightnessMirrorController c) {
- if (mBrightnessMirrorController != null) {
- mBrightnessMirrorController.removeCallback(this);
- }
- mBrightnessMirrorController = c;
- if (mBrightnessMirrorController != null) {
- mBrightnessMirrorController.addCallback(this);
- }
- updateBrightnessMirror();
- }
-
- @Override
- public void onBrightnessMirrorReinflated(View brightnessMirror) {
- updateBrightnessMirror();
- }
-
@Nullable
View getBrightnessView() {
return mBrightnessView;
@@ -362,10 +339,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
mCallback = callback;
}
- void setCustomizer(QSCustomizer customizer) {
- mCustomizePanel = customizer;
- }
-
/**
* Links the footer's page indicator, which is used in landscape orientation to save space.
*
@@ -435,8 +408,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
super.onConfigurationChanged(newConfig);
mOnConfigurationChangedListeners.forEach(
listener -> listener.onConfigurationChange(newConfig));
-
- updateBrightnessMirror();
}
@Override
@@ -579,6 +550,7 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
}
boolean horizontal = shouldUseHorizontalLayout();
ViewGroup host = mMediaHost.getHostView();
+
ViewGroup newParent = horizontal ? mHorizontalLinearLayout : this;
ViewGroup currentParent = (ViewGroup) host.getParent();
if (currentParent != newParent) {
@@ -598,22 +570,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
}
}
- public void updateBrightnessMirror() {
- if (mBrightnessMirrorController != null) {
- ToggleSliderView brightnessSlider = findViewById(R.id.brightness_slider);
- ToggleSliderView mirrorSlider = mBrightnessMirrorController.getMirror()
- .findViewById(R.id.brightness_slider);
- brightnessSlider.setMirror(mirrorSlider);
- brightnessSlider.setMirrorController(mBrightnessMirrorController);
- }
- }
-
- public void onCollapse() {
- if (mCustomizePanel != null && mCustomizePanel.isShown()) {
- mCustomizePanel.hide();
- }
- }
-
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mQSLogger.logPanelExpanded(expanded, getDumpableTag());
@@ -684,10 +640,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
return mExpanded;
}
- void updateRevealedTiles(Collection<QSTile> tiles) {
- mQsTileRevealController.updateRevealedTiles(tiles);
- }
-
void addTile(QSPanelControllerBase.TileRecord tileRecord) {
final QSTile.Callback callback = new QSTile.Callback() {
@Override
@@ -742,29 +694,7 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
mTileLayout.removeTile(tileRecord);
}
- public void showEdit(final View v) {
- v.post(new Runnable() {
- @Override
- public void run() {
- if (mCustomizePanel != null) {
- if (!mCustomizePanel.isCustomizing()) {
- int[] loc = v.getLocationOnScreen();
- int x = loc[0] + v.getWidth() / 2;
- int y = loc[1] + v.getHeight() / 2;
- mCustomizePanel.show(x, y);
- }
- }
-
- }
- });
- }
-
- public void closeDetail() {
- if (mCustomizePanel != null && mCustomizePanel.isShown()) {
- // Treat this as a detail panel for now, to make things easy.
- mCustomizePanel.hide();
- return;
- }
+ void closeDetail() {
showDetail(false, mDetailRecord);
}
@@ -936,10 +866,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
}
}
- public MediaHost getMediaHost() {
- return mMediaHost;
- }
-
/**
* Set the header container of quick settings.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index f222b0d1ccc0..32c81af00870 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -16,26 +16,32 @@
package com.android.systemui.qs;
+import static com.android.systemui.media.dagger.MediaModule.QS_PANEL;
import static com.android.systemui.qs.QSPanel.QS_SHOW_BRIGHTNESS;
import android.annotation.NonNull;
import android.content.res.Configuration;
+import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
+import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile;
-import com.android.systemui.qs.customize.QSCustomizer;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
-import com.android.systemui.settings.BrightnessController;
+import com.android.systemui.settings.brightness.BrightnessController;
+import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.tuner.TunerService;
+import java.util.function.Consumer;
+
import javax.inject.Inject;
+import javax.inject.Named;
/**
* Controller for {@link QSPanel}.
@@ -44,7 +50,11 @@ import javax.inject.Inject;
public class QSPanelController extends QSPanelControllerBase<QSPanel> {
private final QSSecurityFooter mQsSecurityFooter;
private final TunerService mTunerService;
+ private final QSCustomizerController mQsCustomizerController;
+ private final QSTileRevealController.Factory mQsTileRevealControllerFactory;
private final BrightnessController mBrightnessController;
+ private final BrightnessSlider.Factory mBrightnessSliderFactory;
+ private final BrightnessSlider mBrightnessSlider;
private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
new QSPanel.OnConfigurationChangedListener() {
@@ -55,21 +65,42 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
if (mView.isListening()) {
refreshAllTiles();
}
+ updateBrightnessMirror();
}
};
private BrightnessMirrorController mBrightnessMirrorController;
+ private final BrightnessMirrorController.BrightnessMirrorListener mBrightnessMirrorListener =
+ mirror -> updateBrightnessMirror();
+
@Inject
QSPanelController(QSPanel view, QSSecurityFooter qsSecurityFooter, TunerService tunerService,
- QSTileHost qstileHost, DumpManager dumpManager,
- MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
- BrightnessController.Factory brightnessControllerFactory) {
- super(view, qstileHost, metricsLogger, uiEventLogger, dumpManager);
+ QSTileHost qstileHost, QSCustomizerController qsCustomizerController,
+ @Named(QS_PANEL) MediaHost mediaHost,
+ QSTileRevealController.Factory qsTileRevealControllerFactory,
+ DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
+ BrightnessController.Factory brightnessControllerFactory,
+ BrightnessSlider.Factory brightnessSliderFactory) {
+ super(view, qstileHost, qsCustomizerController, mediaHost, metricsLogger, uiEventLogger,
+ dumpManager);
mQsSecurityFooter = qsSecurityFooter;
mTunerService = tunerService;
+ mQsCustomizerController = qsCustomizerController;
+ mQsTileRevealControllerFactory = qsTileRevealControllerFactory;
mQsSecurityFooter.setHostEnvironment(qstileHost);
- mBrightnessController = brightnessControllerFactory.create(
- mView.findViewById(R.id.brightness_slider));
+ mBrightnessSliderFactory = brightnessSliderFactory;
+
+ mBrightnessSlider = mBrightnessSliderFactory.create(getContext(), mView);
+ mView.setBrightnessView(mBrightnessSlider.getRootView());
+
+ mBrightnessController = brightnessControllerFactory.create(mBrightnessSlider);
+ }
+
+ @Override
+ public void onInit() {
+ super.onInit();
+ mQsCustomizerController.init();
+ mBrightnessSlider.init();
}
@Override
@@ -84,16 +115,22 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
mView.setSecurityFooter(mQsSecurityFooter.getView());
switchTileLayout(true);
if (mBrightnessMirrorController != null) {
- mBrightnessMirrorController.addCallback(mView);
+ mBrightnessMirrorController.addCallback(mBrightnessMirrorListener);
}
}
@Override
+ protected QSTileRevealController createTileRevealController() {
+ return mQsTileRevealControllerFactory.create(
+ this, (PagedTileLayout) mView.createRegularTileLayout());
+ }
+
+ @Override
protected void onViewDetached() {
mTunerService.removeTunable(mView);
mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener);
if (mBrightnessMirrorController != null) {
- mBrightnessMirrorController.removeCallback(mView);
+ mBrightnessMirrorController.removeCallback(mBrightnessMirrorListener);
}
super.onViewDetached();
}
@@ -110,20 +147,6 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
mView.setHeaderContainer(headerContainer);
}
- public QSPanel.QSTileLayout getTileLayout() {
- return mView.getTileLayout();
- }
-
- /** */
- public void setCustomizer(QSCustomizer customizer) {
- mView.setCustomizer(customizer);
- }
-
- /** */
- public boolean isShowingCustomize() {
- return mView.isShowingCustomize();
- }
-
/** */
public void setVisibility(int visibility) {
mView.setVisibility(visibility);
@@ -148,19 +171,22 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
}
/** */
- public QSTileRevealController getQsTileRevealController() {
- return mView.getQsTileRevealController();
- }
-
- /** */
- public MediaHost getMediaHost() {
- return mView.getMediaHost();
- }
-
- /** */
public void setBrightnessMirror(BrightnessMirrorController brightnessMirrorController) {
mBrightnessMirrorController = brightnessMirrorController;
- mView.setBrightnessMirror(brightnessMirrorController);
+ if (mBrightnessMirrorController != null) {
+ mBrightnessMirrorController.removeCallback(mBrightnessMirrorListener);
+ }
+ mBrightnessMirrorController = brightnessMirrorController;
+ if (mBrightnessMirrorController != null) {
+ mBrightnessMirrorController.addCallback(mBrightnessMirrorListener);
+ }
+ updateBrightnessMirror();
+ }
+
+ private void updateBrightnessMirror() {
+ if (mBrightnessMirrorController != null) {
+ mBrightnessSlider.setMirrorControllerAndMirror(mBrightnessMirrorController);
+ }
}
/** Get the QSTileHost this panel uses. */
@@ -196,6 +222,75 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
/** Start customizing the Quick Settings. */
public void showEdit(View view) {
- mView.showEdit(view);
+ view.post(() -> {
+ if (!mQsCustomizerController.isCustomizing()) {
+ int[] loc = view.getLocationOnScreen();
+ int x = loc[0] + view.getWidth() / 2;
+ int y = loc[1] + view.getHeight() / 2;
+ mQsCustomizerController.show(x, y, false);
+ }
+ });
+ }
+
+ /** */
+ public void setCallback(QSDetail.Callback qsPanelCallback) {
+ mView.setCallback(qsPanelCallback);
+ }
+
+ /** */
+ public void setGridContentVisibility(boolean visible) {
+ mView.setGridContentVisibility(visible);
+ }
+
+ public boolean isLayoutRtl() {
+ return mView.isLayoutRtl();
+ }
+
+ public View getBrightnessView() {
+ return mView.getBrightnessView();
+ }
+
+ public View getDivider() {
+ return mView.getDivider();
+ }
+
+ /** */
+ public void setPageListener(PagedTileLayout.PageListener listener) {
+ mView.setPageListener(listener);
+ }
+
+ /** */
+ public void setMediaVisibilityChangedListener(Consumer<Boolean> visibilityChangedListener) {
+ mView.setMediaVisibilityChangedListener(visibilityChangedListener);
+ }
+
+ public boolean isShown() {
+ return mView.isShown();
+ }
+
+ /** */
+ public void setContentMargins(int startMargin, int endMargin) {
+ mView.setContentMargins(startMargin, endMargin);
+ }
+
+ /** */
+ public Pair<Integer, Integer> getVisualSideMargins() {
+ return mView.getVisualSideMargins();
+ }
+
+ /** */
+ public void showDetailDapater(DetailAdapter detailAdapter, int x, int y) {
+ mView.showDetailAdapter(true, detailAdapter, new int[]{x, y});
+ }
+
+ /** */
+ public void setFooterPageIndicator(PageIndicator pageIndicator) {
+ mView.setFooterPageIndicator(pageIndicator);
+ }
+
+ /** */
+ public boolean isExpanded() {
+ return mView.isExpanded();
}
}
+
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 68a6cdcbd289..06bf9acb64f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -29,6 +29,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTileView;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.util.ViewController;
@@ -46,6 +47,7 @@ import java.util.stream.Collectors;
public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewController<T>
implements Dumpable{
protected final QSTileHost mHost;
+ private final QSCustomizerController mQsCustomizerController;
private final MediaHost mMediaHost;
private final MetricsLogger mMetricsLogger;
private final UiEventLogger mUiEventLogger;
@@ -53,6 +55,9 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
private int mLastOrientation;
+ private String mCachedSpecs = "";
+ private QSTileRevealController mQsTileRevealController;
+ private float mRevealExpansion;
private final QSHost.Callback mQSHostCallback = this::setTiles;
@@ -66,13 +71,14 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
}
}
};
- private String mCachedSpecs = "";
protected QSPanelControllerBase(T view, QSTileHost host,
+ QSCustomizerController qsCustomizerController, MediaHost mediaHost,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, DumpManager dumpManager) {
super(view);
mHost = host;
- mMediaHost = mView.getMediaHost();
+ mQsCustomizerController = qsCustomizerController;
+ mMediaHost = mediaHost;
mMetricsLogger = metricsLogger;
mUiEventLogger = uiEventLogger;
mDumpManager = dumpManager;
@@ -80,6 +86,11 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
@Override
protected void onViewAttached() {
+ mQsTileRevealController = createTileRevealController();
+ if (mQsTileRevealController != null) {
+ mQsTileRevealController.setExpansion(mRevealExpansion);
+ }
+
mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
mHost.addCallback(mQSHostCallback);
mMediaHost.addVisibilityChangeListener(aBoolean -> {
@@ -103,6 +114,10 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
mDumpManager.unregisterDumpable(mView.getDumpableTag());
}
+ protected QSTileRevealController createTileRevealController() {
+ return null;
+ }
+
/** */
public void setTiles() {
setTiles(mHost.getTiles(), false);
@@ -110,9 +125,11 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
/** */
public void setTiles(Collection<QSTile> tiles, boolean collapsedView) {
- if (!collapsedView) {
- mView.updateRevealedTiles(tiles);
+ // TODO(b/168904199): move this logic into QSPanelController.
+ if (!collapsedView && mQsTileRevealController != null) {
+ mQsTileRevealController.updateRevealedTiles(tiles);
}
+
for (QSPanelControllerBase.TileRecord record : mRecords) {
mView.removeTile(record);
record.tile.removeCallback(record.callback);
@@ -176,7 +193,6 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
.collect(Collectors.joining(","));
}
-
/** */
public void setExpanded(boolean expanded) {
mView.setExpanded(expanded);
@@ -192,6 +208,10 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
/** */
public void closeDetail() {
+ if (mQsCustomizerController.isShown()) {
+ mQsCustomizerController.hide();
+ return;
+ }
mView.closeDetail();
}
@@ -214,7 +234,6 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
boolean switchTileLayout(boolean force) {
if (mView.switchTileLayout(force, mRecords)) {
setTiles();
- mView.reSetLayoutListening();
return true;
}
return false;
@@ -228,6 +247,13 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
}
}
+ /** Set the expansion on the associated {@link QSTileRevealController}. */
+ public void setRevealExpansion(float expansion) {
+ mRevealExpansion = expansion;
+ if (mQsTileRevealController != null) {
+ mQsTileRevealController.setExpansion(expansion);
+ }
+ }
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -241,6 +267,10 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
}
}
+ public QSPanel.QSTileLayout getTileLayout() {
+ return mView.getTileLayout();
+ }
+
/** */
public static final class TileRecord extends QSPanel.Record {
public QSTile tile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 270fcbffbd71..478923994af8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -15,6 +15,8 @@
*/
package com.android.systemui.qs;
+import static com.android.systemui.qs.dagger.QSFragmentModule.QS_SECURITY_FOOTER_VIEW;
+
import android.app.AlertDialog;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyEventLogger;
@@ -44,9 +46,10 @@ import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.settings.UserTracker;
@@ -54,6 +57,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.SecurityController;
import javax.inject.Inject;
+import javax.inject.Named;
@QSScope
class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListener {
@@ -81,18 +85,19 @@ class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListen
private int mFooterIconId;
@Inject
- public QSSecurityFooter(QSPanel qsPanel, Context context, UserTracker userTracker) {
- mRootView = LayoutInflater.from(context)
- .inflate(R.layout.quick_settings_footer, qsPanel, false);
+ QSSecurityFooter(@Named(QS_SECURITY_FOOTER_VIEW) View rootView, Context context,
+ UserTracker userTracker, @Main Handler mainHandler, ActivityStarter activityStarter,
+ SecurityController securityController, @Background Looper bgLooper) {
+ mRootView = rootView;
mRootView.setOnClickListener(this);
mFooterText = mRootView.findViewById(R.id.footer_text);
mFooterIcon = mRootView.findViewById(R.id.footer_icon);
mFooterIconId = R.drawable.ic_info_outline;
mContext = context;
- mMainHandler = new Handler(Looper.myLooper());
- mActivityStarter = Dependency.get(ActivityStarter.class);
- mSecurityController = Dependency.get(SecurityController.class);
- mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
+ mMainHandler = mainHandler;
+ mActivityStarter = activityStarter;
+ mSecurityController = securityController;
+ mHandler = new H(bgLooper);
mUserTracker = userTracker;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java
index 3d4a417abf2e..3f931088ec83 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java
@@ -8,6 +8,7 @@ import android.util.ArraySet;
import com.android.systemui.Prefs;
import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
import java.util.Collection;
@@ -17,13 +18,13 @@ import java.util.Set;
import javax.inject.Inject;
/** */
-@QSScope
public class QSTileRevealController {
private static final long QS_REVEAL_TILES_DELAY = 500L;
private final Context mContext;
- private final QSPanel mQSPanel;
+ private final QSPanelController mQSPanelController;
private final PagedTileLayout mPagedTileLayout;
+ private final QSCustomizerController mQsCustomizerController;
private final ArraySet<String> mTilesToReveal = new ArraySet<>();
private final Handler mHandler = new Handler();
@@ -31,19 +32,19 @@ public class QSTileRevealController {
@Override
public void run() {
mPagedTileLayout.startTileReveal(mTilesToReveal, () -> {
- if (mQSPanel.isExpanded()) {
+ if (mQSPanelController.isExpanded()) {
addTileSpecsToRevealed(mTilesToReveal);
mTilesToReveal.clear();
}
});
}
};
-
- @Inject
- QSTileRevealController(Context context, QSPanel qsPanel, PagedTileLayout pagedTileLayout) {
+ QSTileRevealController(Context context, QSPanelController qsPanelController,
+ PagedTileLayout pagedTileLayout, QSCustomizerController qsCustomizerController) {
mContext = context;
- mQSPanel = qsPanel;
+ mQSPanelController = qsPanelController;
mPagedTileLayout = pagedTileLayout;
+ mQsCustomizerController = qsCustomizerController;
}
public void setExpansion(float expansion) {
@@ -62,7 +63,7 @@ public class QSTileRevealController {
final Set<String> revealedTiles = Prefs.getStringSet(
mContext, QS_TILE_SPECS_REVEALED, Collections.EMPTY_SET);
- if (revealedTiles.isEmpty() || mQSPanel.isShowingCustomize()) {
+ if (revealedTiles.isEmpty() || mQsCustomizerController.isCustomizing()) {
// Do not reveal QS tiles the user has upon first load or those that they directly
// added through customization.
addTileSpecsToRevealed(tileSpecs);
@@ -79,4 +80,23 @@ public class QSTileRevealController {
revealedTiles.addAll(specs);
Prefs.putStringSet(mContext, QS_TILE_SPECS_REVEALED, revealedTiles);
}
+
+ /** TODO(b/168904199): Remove this once QSPanel has its rejection removed. */
+ @QSScope
+ static class Factory {
+ private final Context mContext;
+ private final QSCustomizerController mQsCustomizerController;
+
+ @Inject
+ Factory(Context context, QSCustomizerController qsCustomizerController) {
+ mContext = context;
+ mQsCustomizerController = qsCustomizerController;
+ }
+
+ QSTileRevealController create(QSPanelController qsPanelController,
+ PagedTileLayout pagedTileLayout) {
+ return new QSTileRevealController(mContext, qsPanelController, pagedTileLayout,
+ mQsCustomizerController);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index ed0900d07b56..06e8634a0d1f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -46,12 +46,11 @@ public class QuickQSPanel extends QSPanel {
public static final String NUM_QUICK_TILES = "sysui_qqs_count";
private static final String TAG = "QuickQSPanel";
- // Start it at 6 so a non-zero value can be obtained statically.
- private static int sDefaultMaxTiles = 6;
+ // A default value so that we never return 0.
+ public static final int DEFAULT_MAX_TILES = 6;
private boolean mDisabledByPolicy;
private int mMaxTiles;
- protected QSPanel mFullPanel;
@Inject
@@ -62,7 +61,8 @@ public class QuickQSPanel extends QSPanel {
@Named(QUICK_QS_PANEL) MediaHost mediaHost,
UiEventLogger uiEventLogger) {
super(context, attrs, qsLogger, mediaHost, uiEventLogger);
- sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
+ mMaxTiles = Math.min(DEFAULT_MAX_TILES,
+ getResources().getInteger(R.integer.quick_qs_panel_max_columns));
applyBottomMargin((View) mRegularTileLayout);
}
@@ -74,8 +74,8 @@ public class QuickQSPanel extends QSPanel {
}
@Override
- protected void addViewsAboveTiles() {
- // Nothing to add above the tiles
+ public void setBrightnessView(View view) {
+ // Don't add brightness view
}
@Override
@@ -117,10 +117,6 @@ public class QuickQSPanel extends QSPanel {
return TAG;
}
- public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
- mFullPanel = fullPanel;
- }
-
@Override
protected boolean shouldShowDetail() {
return !mExpanded;
@@ -140,7 +136,7 @@ public class QuickQSPanel extends QSPanel {
}
public void setMaxTiles(int maxTiles) {
- mMaxTiles = maxTiles;
+ mMaxTiles = Math.min(maxTiles, DEFAULT_MAX_TILES);
}
@Override
@@ -166,14 +162,10 @@ public class QuickQSPanel extends QSPanel {
return Integer.parseInt(numTilesValue);
} catch (NumberFormatException e) {
// Couldn't read an int from the new setting value. Use default.
- return sDefaultMaxTiles;
+ return DEFAULT_MAX_TILES;
}
}
- public static int getDefaultMaxTiles() {
- return sDefaultMaxTiles;
- }
-
void setDisabledByPolicy(boolean disabled) {
if (disabled != mDisabledByPolicy) {
mDisabledByPolicy = disabled;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 97b6e99a0390..7f50eef019a9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -16,48 +16,57 @@
package com.android.systemui.qs;
-import static com.android.systemui.qs.QuickQSPanel.NUM_QUICK_TILES;
-import static com.android.systemui.qs.QuickQSPanel.parseNumTiles;
+import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
+import java.util.List;
import javax.inject.Inject;
+import javax.inject.Named;
/** Controller for {@link QuickQSPanel}. */
@QSScope
public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel> {
- private final Tunable mNumTiles =
- (key, newValue) -> setMaxTiles(parseNumTiles(newValue));
- private final TunerService mTunerService;
+ private List<QSTile> mAllTiles = new ArrayList<>();
+
+ private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
+ newConfig -> {
+ int newMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
+ if (newMaxTiles != mView.getNumQuickTiles()) {
+ setMaxTiles(newMaxTiles);
+ }
+ };
@Inject
- QuickQSPanelController(QuickQSPanel view, TunerService tunerService, QSTileHost qsTileHost,
+ QuickQSPanelController(QuickQSPanel view, QSTileHost qsTileHost,
+ QSCustomizerController qsCustomizerController,
+ @Named(QUICK_QS_PANEL) MediaHost mediaHost,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
DumpManager dumpManager) {
- super(view, qsTileHost, metricsLogger, uiEventLogger, dumpManager);
- mTunerService = tunerService;
+ super(view, qsTileHost, qsCustomizerController, mediaHost, metricsLogger, uiEventLogger,
+ dumpManager);
}
@Override
protected void onViewAttached() {
super.onViewAttached();
- mTunerService.addTunable(mNumTiles, NUM_QUICK_TILES);
-
+ mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
}
@Override
protected void onViewDetached() {
super.onViewDetached();
- mTunerService.removeTunable(mNumTiles);
+ mView.removeOnConfigurationChangedListener(mOnConfigurationChangedListener);
}
public boolean isListening() {
@@ -71,13 +80,17 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>
@Override
public void setTiles() {
- ArrayList<QSTile> quickTiles = new ArrayList<>();
+ mAllTiles.clear();
for (QSTile tile : mHost.getTiles()) {
- quickTiles.add(tile);
- if (quickTiles.size() == mView.getNumQuickTiles()) {
+ mAllTiles.add(tile);
+ if (mAllTiles.size() == QuickQSPanel.DEFAULT_MAX_TILES) {
break;
}
}
- super.setTiles(quickTiles, true);
+ super.setTiles(mAllTiles.subList(0, mView.getNumQuickTiles()), true);
+ }
+
+ public int getNumQuickTiles() {
+ return mView.getNumQuickTiles();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 5757602b9d0f..09894e58231a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -137,10 +137,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
updateResources();
- Rect tintArea = new Rect(0, 0, 0, 0);
- // Set light text on the header icons because they will always be on a black background
- applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
-
mClockView = findViewById(R.id.clock);
mSpace = findViewById(R.id.space);
@@ -153,6 +149,19 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
mRingerModeTextView.setSelected(true);
mNextAlarmTextView.setSelected(true);
+
+ int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
+ android.R.attr.colorForeground);
+ float intensity = getColorIntensity(colorForeground);
+ int fillColor = mDualToneHandler.getSingleColor(intensity);
+
+ Rect tintArea = new Rect(0, 0, 0, 0);
+ mBatteryRemainingIcon.onDarkChanged(tintArea, intensity, fillColor);
+
+ // The quick settings status bar clock depends on the color of the background scrim and
+ // can be different from the status bar clock color.
+ mClockView.setTextColor(
+ Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor));
}
void onAttach(TintedIconManager iconManager) {
@@ -225,13 +234,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
!Objects.equals(originalAlarmText, mNextAlarmTextView.getText());
}
- private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
- View v = findViewById(id);
- if (v instanceof DarkReceiver) {
- ((DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
- }
- }
-
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -439,18 +441,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
post(() -> setClickable(!mExpanded));
}
- public void setQSPanel(final QSPanel qsPanel) {
- //host.setHeaderView(mExpandIndicator);
- mHeaderQsPanel.setQSPanelAndHeader(qsPanel, this);
-
- Rect tintArea = new Rect(0, 0, 0, 0);
- int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
- android.R.attr.colorForeground);
- float intensity = getColorIntensity(colorForeground);
- int fillColor = mDualToneHandler.getSingleColor(intensity);
- mBatteryRemainingIcon.onDarkChanged(tintArea, intensity, fillColor);
- }
-
public void setCallback(Callback qsPanelCallback) {
mHeaderQsPanel.setCallback(qsPanelCallback);
}
@@ -475,6 +465,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements LifecycleOwn
return mLifecycle;
}
+ /** */
public void setContentMargins(int marginStart, int marginEnd) {
mContentMarginStart = marginStart;
mContentMarginEnd = marginEnd;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 32904a21cd3c..5ee9df478342 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -34,8 +34,10 @@ import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
+import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.plugins.ActivityStarter;
@@ -99,6 +101,9 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
private boolean mMicCameraIndicatorsEnabled;
private boolean mLocationIndicatorsEnabled;
private boolean mPrivacyChipLogged;
+
+ private SysuiColorExtractor mColorExtractor;
+ private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener;
private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
private final ZenModeController.Callback mZenModeControllerCallback = new Callback() {
@@ -216,7 +221,8 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
CommandQueue commandQueue, DemoModeController demoModeController,
UserTracker userTracker, QuickQSPanelController quickQSPanelController,
QSCarrierGroupController.Builder qsCarrierGroupControllerBuilder,
- PrivacyLogger privacyLogger) {
+ PrivacyLogger privacyLogger,
+ SysuiColorExtractor colorExtractor) {
super(view);
mZenModeController = zenModeController;
mNextAlarmController = nextAlarmController;
@@ -246,6 +252,12 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, mCommandQueue);
mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
+ mColorExtractor = colorExtractor;
+ mOnColorsChangedListener = (extractor, which) -> {
+ final boolean lightTheme = mColorExtractor.getNeutralColors().supportsDarkText();
+ mClockView.onColorsChanged(lightTheme);
+ };
+ mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
}
@Override
@@ -281,6 +293,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
protected void onViewDetached() {
mRingerModeTracker.getRingerModeInternal().removeObservers(mLifecycleOwner);
mClockView.setOnClickListener(null);
+ mColorExtractor.removeOnColorsChangedListener(mOnColorsChangedListener);
mNextAlarmContainer.setOnClickListener(null);
mRingerContainer.setOnClickListener(null);
mPrivacyChip.setOnClickListener(null);
@@ -366,7 +379,6 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mZenModeController.getConsolidatedPolicy());
}
-
private static class ClockDemoModeReceiver implements DemoMode {
private Clock mClockView;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 8097958fac39..3291aa0e2099 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -20,41 +20,23 @@ import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Configuration;
-import android.os.Bundle;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toolbar;
-import android.widget.Toolbar.OnMenuItemClickListener;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.recyclerview.widget.DefaultItemAnimator;
-import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.R;
-import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.qs.QS;
-import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSDetailClipper;
-import com.android.systemui.qs.QSEditEvent;
-import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.KeyguardStateController.Callback;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
/**
* Allows full-screen customization of QS, through show() and hide().
@@ -62,24 +44,16 @@ import javax.inject.Inject;
* This adds itself to the status bar window, so it can appear on top of quick settings and
* *someday* do fancy animations to get into/out of it.
*/
-public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener {
+public class QSCustomizer extends LinearLayout {
- private static final int MENU_RESET = Menu.FIRST;
- private static final String EXTRA_QS_CUSTOMIZING = "qs_customizing";
- private static final String TAG = "QSCustomizer";
+ static final int MENU_RESET = Menu.FIRST;
+ static final String EXTRA_QS_CUSTOMIZING = "qs_customizing";
private final QSDetailClipper mClipper;
- private final LightBarController mLightBarController;
- private KeyguardStateController mKeyguardStateController;
- private final ScreenLifecycle mScreenLifecycle;
- private final TileQueryHelper mTileQueryHelper;
private final View mTransparentView;
- private final QSTileHost mHost;
private boolean isShown;
- private RecyclerView mRecyclerView;
- private TileAdapter mTileAdapter;
- private Toolbar mToolbar;
+ private final RecyclerView mRecyclerView;
private boolean mCustomizing;
private NotificationsQuickSettingsContainer mNotifQsContainer;
private QS mQs;
@@ -87,90 +61,47 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
private int mY;
private boolean mOpening;
private boolean mIsShowingNavBackdrop;
- private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
-
- @Inject
- public QSCustomizer(Context context, AttributeSet attrs,
- LightBarController lightBarController,
- KeyguardStateController keyguardStateController,
- ScreenLifecycle screenLifecycle,
- TileQueryHelper tileQueryHelper,
- QSTileHost qsTileHost,
- UiEventLogger uiEventLogger) {
+
+ public QSCustomizer(Context context, AttributeSet attrs) {
super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
LayoutInflater.from(getContext()).inflate(R.layout.qs_customize_panel_content, this);
mClipper = new QSDetailClipper(findViewById(R.id.customize_container));
- mToolbar = findViewById(com.android.internal.R.id.action_bar);
+ Toolbar toolbar = findViewById(com.android.internal.R.id.action_bar);
TypedValue value = new TypedValue();
mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
- mToolbar.setNavigationIcon(
+ toolbar.setNavigationIcon(
getResources().getDrawable(value.resourceId, mContext.getTheme()));
- mToolbar.setNavigationOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- hide();
- }
- });
- mToolbar.setOnMenuItemClickListener(this);
- mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
+
+ toolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
mContext.getString(com.android.internal.R.string.reset));
- mToolbar.setTitle(R.string.qs_edit);
+ toolbar.setTitle(R.string.qs_edit);
mRecyclerView = findViewById(android.R.id.list);
mTransparentView = findViewById(R.id.customizer_transparent_view);
- mTileAdapter = new TileAdapter(getContext(), uiEventLogger);
- mTileQueryHelper = tileQueryHelper;
- mTileQueryHelper.setListener(mTileAdapter);
- mRecyclerView.setAdapter(mTileAdapter);
- mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView);
- GridLayoutManager layout = new GridLayoutManager(getContext(), 3) {
- @Override
- public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
- RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
- // Do not read row and column every time it changes.
- }
- };
- layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
- mRecyclerView.setLayoutManager(layout);
- mRecyclerView.addItemDecoration(mTileAdapter.getItemDecoration());
- mRecyclerView.addItemDecoration(mTileAdapter.getMarginItemDecoration());
DefaultItemAnimator animator = new DefaultItemAnimator();
animator.setMoveDuration(TileAdapter.MOVE_DURATION);
mRecyclerView.setItemAnimator(animator);
- mLightBarController = lightBarController;
- mKeyguardStateController = keyguardStateController;
- mScreenLifecycle = screenLifecycle;
- mHost = qsTileHost;
- mTileAdapter.setHost(mHost);
- updateNavBackDrop(getResources().getConfiguration());
}
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- updateNavBackDrop(newConfig);
- updateResources();
- }
-
- private void updateResources() {
+ void updateResources() {
LayoutParams lp = (LayoutParams) mTransparentView.getLayoutParams();
lp.height = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
mTransparentView.setLayoutParams(lp);
}
- private void updateNavBackDrop(Configuration newConfig) {
+ void updateNavBackDrop(Configuration newConfig, LightBarController lightBarController) {
View navBackdrop = findViewById(R.id.nav_bar_background);
mIsShowingNavBackdrop = newConfig.smallestScreenWidthDp >= 600
|| newConfig.orientation != Configuration.ORIENTATION_LANDSCAPE;
if (navBackdrop != null) {
navBackdrop.setVisibility(mIsShowingNavBackdrop ? View.VISIBLE : View.GONE);
}
- updateNavColors();
+ updateNavColors(lightBarController);
}
- private void updateNavColors() {
- mLightBarController.setQsCustomizing(mIsShowingNavBackdrop && isShown);
+ void updateNavColors(LightBarController lightBarController) {
+ lightBarController.setQsCustomizing(mIsShowingNavBackdrop && isShown);
}
public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) {
@@ -184,39 +115,30 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
/** Animate and show QSCustomizer panel.
* @param x,y Location on screen of {@code edit} button to determine center of animation.
*/
- public void show(int x, int y) {
+ void show(int x, int y, TileAdapter tileAdapter) {
if (!isShown) {
- int containerLocation[] = findViewById(R.id.customize_container).getLocationOnScreen();
+ int[] containerLocation = findViewById(R.id.customize_container).getLocationOnScreen();
mX = x - containerLocation[0];
mY = y - containerLocation[1];
- mUiEventLogger.log(QSEditEvent.QS_EDIT_OPEN);
isShown = true;
mOpening = true;
- setTileSpecs();
setVisibility(View.VISIBLE);
- mClipper.animateCircularClip(mX, mY, true, mExpandAnimationListener);
- queryTiles();
+ mClipper.animateCircularClip(mX, mY, true, new ExpandAnimatorListener(tileAdapter));
mNotifQsContainer.setCustomizerAnimating(true);
mNotifQsContainer.setCustomizerShowing(true);
- mKeyguardStateController.addCallback(mKeyguardCallback);
- updateNavColors();
}
}
- public void showImmediately() {
+ void showImmediately() {
if (!isShown) {
setVisibility(VISIBLE);
mClipper.cancelAnimator();
mClipper.showBackground();
isShown = true;
- setTileSpecs();
setCustomizing(true);
- queryTiles();
mNotifQsContainer.setCustomizerAnimating(false);
mNotifQsContainer.setCustomizerShowing(true);
- mKeyguardStateController.addCallback(mKeyguardCallback);
- updateNavColors();
}
}
@@ -225,9 +147,6 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
* {@link TileAdapter}.
*/
public void setContentPaddings(int paddingStart, int paddingEnd) {
- int halfMargin = mContext.getResources()
- .getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) / 2;
- mTileAdapter.changeHalfMargin(halfMargin);
mRecyclerView.setPaddingRelative(
paddingStart,
mRecyclerView.getPaddingTop(),
@@ -236,22 +155,14 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
);
}
- private void queryTiles() {
- mTileQueryHelper.queryTiles(mHost);
- }
-
- public void hide() {
- final boolean animate = mScreenLifecycle.getScreenState() != ScreenLifecycle.SCREEN_OFF;
+ /** Hide the customizer. */
+ public void hide(boolean animate) {
if (isShown) {
- mUiEventLogger.log(QSEditEvent.QS_EDIT_CLOSED);
isShown = false;
- mToolbar.dismissPopupMenus();
mClipper.cancelAnimator();
// Make sure we're not opening (because we're closing). Nobody can think we are
// customizing after the next two lines.
mOpening = false;
- setCustomizing(false);
- save();
if (animate) {
mClipper.animateCircularClip(mX, mY, false, mCollapseAnimationListener);
} else {
@@ -259,8 +170,6 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
}
mNotifQsContainer.setCustomizerAnimating(animate);
mNotifQsContainer.setCustomizerShowing(false);
- mKeyguardStateController.removeCallback(mKeyguardCallback);
- updateNavColors();
}
}
@@ -268,7 +177,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
return isShown;
}
- private void setCustomizing(boolean customizing) {
+ void setCustomizing(boolean customizing) {
mCustomizing = customizing;
mQs.notifyCustomizeChanged();
}
@@ -277,78 +186,21 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
return mCustomizing || mOpening;
}
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- switch (item.getItemId()) {
- case MENU_RESET:
- mUiEventLogger.log(QSEditEvent.QS_EDIT_RESET);
- reset();
- break;
- }
- return false;
- }
-
- private void reset() {
- mTileAdapter.resetTileSpecs(mHost, QSTileHost.getDefaultSpecs(mContext));
- }
-
- private void setTileSpecs() {
- List<String> specs = new ArrayList<>();
- for (QSTile tile : mHost.getTiles()) {
- specs.add(tile.getTileSpec());
- }
- mTileAdapter.setTileSpecs(specs);
- mRecyclerView.setAdapter(mTileAdapter);
- }
-
- private void save() {
- if (mTileQueryHelper.isFinished()) {
- mTileAdapter.saveSpecs(mHost);
- }
- }
-
-
- public void saveInstanceState(Bundle outState) {
- if (isShown) {
- mKeyguardStateController.removeCallback(mKeyguardCallback);
- }
- outState.putBoolean(EXTRA_QS_CUSTOMIZING, mCustomizing);
- }
-
- public void restoreInstanceState(Bundle savedInstanceState) {
- boolean customizing = savedInstanceState.getBoolean(EXTRA_QS_CUSTOMIZING);
- if (customizing) {
- setVisibility(VISIBLE);
- addOnLayoutChangeListener(new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft,
- int oldTop, int oldRight, int oldBottom) {
- removeOnLayoutChangeListener(this);
- showImmediately();
- }
- });
- }
- }
/** @param x,y Location on screen of animation center.
*/
public void setEditLocation(int x, int y) {
- int containerLocation[] = findViewById(R.id.customize_container).getLocationOnScreen();
+ int[] containerLocation = findViewById(R.id.customize_container).getLocationOnScreen();
mX = x - containerLocation[0];
mY = y - containerLocation[1];
}
- private final Callback mKeyguardCallback = new Callback() {
- @Override
- public void onKeyguardShowingChanged() {
- if (!isAttachedToWindow()) return;
- if (mKeyguardStateController.isShowing() && !mOpening) {
- hide();
- }
+ class ExpandAnimatorListener extends AnimatorListenerAdapter {
+ private final TileAdapter mTileAdapter;
+
+ ExpandAnimatorListener(TileAdapter tileAdapter) {
+ mTileAdapter = tileAdapter;
}
- };
- private final AnimatorListener mExpandAnimationListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (isShown) {
@@ -356,6 +208,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
}
mOpening = false;
mNotifQsContainer.setCustomizerAnimating(false);
+ mRecyclerView.setAdapter(mTileAdapter);
}
@Override
@@ -363,7 +216,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
mOpening = false;
mNotifQsContainer.setCustomizerAnimating(false);
}
- };
+ }
private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() {
@Override
@@ -372,7 +225,6 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
setVisibility(View.GONE);
}
mNotifQsContainer.setCustomizerAnimating(false);
- mRecyclerView.setAdapter(mTileAdapter);
}
@Override
@@ -383,4 +235,12 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
mNotifQsContainer.setCustomizerAnimating(false);
}
};
-}
+
+ public RecyclerView getRecyclerView() {
+ return mRecyclerView;
+ }
+
+ public boolean isOpening() {
+ return mOpening;
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
new file mode 100644
index 000000000000..7ba51e5e7128
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
@@ -0,0 +1,247 @@
+/*
+ * 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.qs.customize;
+
+import static com.android.systemui.qs.customize.QSCustomizer.EXTRA_QS_CUSTOMIZING;
+import static com.android.systemui.qs.customize.QSCustomizer.MENU_RESET;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Toolbar;
+import android.widget.Toolbar.OnMenuItemClickListener;
+
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.QSEditEvent;
+import com.android.systemui.qs.QSFragment;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.dagger.QSScope;
+import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.ViewController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+/** {@link ViewController} for {@link QSCustomizer}. */
+@QSScope
+public class QSCustomizerController extends ViewController<QSCustomizer> {
+ private final TileQueryHelper mTileQueryHelper;
+ private final QSTileHost mQsTileHost;
+ private final TileAdapter mTileAdapter;
+ private final ScreenLifecycle mScreenLifecycle;
+ private final KeyguardStateController mKeyguardStateController;
+ private final LightBarController mLightBarController;
+ private final ConfigurationController mConfigurationController;
+ private final UiEventLogger mUiEventLogger;
+ private final Toolbar mToolbar;
+
+ private final OnMenuItemClickListener mOnMenuItemClickListener = new OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ if (item.getItemId() == MENU_RESET) {
+ mUiEventLogger.log(QSEditEvent.QS_EDIT_RESET);
+ reset();
+ }
+ return false;
+ }
+ };
+
+ private final KeyguardStateController.Callback mKeyguardCallback =
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ if (!mView.isAttachedToWindow()) return;
+ if (mKeyguardStateController.isShowing() && !mView.isOpening()) {
+ hide();
+ }
+ }
+ };
+
+ private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ mView.updateNavBackDrop(newConfig, mLightBarController);
+ mView.updateResources();
+ }
+ };
+
+ @Inject
+ protected QSCustomizerController(QSCustomizer view, TileQueryHelper tileQueryHelper,
+ QSTileHost qsTileHost, TileAdapter tileAdapter, ScreenLifecycle screenLifecycle,
+ KeyguardStateController keyguardStateController, LightBarController lightBarController,
+ ConfigurationController configurationController, UiEventLogger uiEventLogger) {
+ super(view);
+ mTileQueryHelper = tileQueryHelper;
+ mQsTileHost = qsTileHost;
+ mTileAdapter = tileAdapter;
+ mScreenLifecycle = screenLifecycle;
+ mKeyguardStateController = keyguardStateController;
+ mLightBarController = lightBarController;
+ mConfigurationController = configurationController;
+ mUiEventLogger = uiEventLogger;
+
+ mToolbar = mView.findViewById(com.android.internal.R.id.action_bar);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mView.updateNavBackDrop(getResources().getConfiguration(), mLightBarController);
+
+ mConfigurationController.addCallback(mConfigurationListener);
+
+ mTileQueryHelper.setListener(mTileAdapter);
+ int halfMargin =
+ getResources().getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) / 2;
+ mTileAdapter.changeHalfMargin(halfMargin);
+
+ RecyclerView recyclerView = mView.getRecyclerView();
+ recyclerView.setAdapter(mTileAdapter);
+ mTileAdapter.getItemTouchHelper().attachToRecyclerView(recyclerView);
+ GridLayoutManager layout = new GridLayoutManager(getContext(), TileAdapter.NUM_COLUMNS) {
+ @Override
+ public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
+ RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
+ // Do not read row and column every time it changes.
+ }
+ };
+ layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
+ recyclerView.setLayoutManager(layout);
+ recyclerView.addItemDecoration(mTileAdapter.getItemDecoration());
+ recyclerView.addItemDecoration(mTileAdapter.getMarginItemDecoration());
+
+ mToolbar.setOnMenuItemClickListener(mOnMenuItemClickListener);
+ mToolbar.setNavigationOnClickListener(v -> hide());
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mTileQueryHelper.setListener(null);
+ mToolbar.setOnMenuItemClickListener(null);
+ mConfigurationController.removeCallback(mConfigurationListener);
+ }
+
+
+ private void reset() {
+ mTileAdapter.resetTileSpecs(QSTileHost.getDefaultSpecs(getContext()));
+ }
+
+ public boolean isCustomizing() {
+ return mView.isCustomizing();
+ }
+
+ /** */
+ public void show(int x, int y, boolean immediate) {
+ if (!mView.isShown()) {
+ setTileSpecs();
+ if (immediate) {
+ mView.showImmediately();
+ } else {
+ mView.show(x, y, mTileAdapter);
+ mUiEventLogger.log(QSEditEvent.QS_EDIT_OPEN);
+ }
+ mTileQueryHelper.queryTiles(mQsTileHost);
+ mKeyguardStateController.addCallback(mKeyguardCallback);
+ mView.updateNavColors(mLightBarController);
+ }
+ }
+
+ /** */
+ public void setQs(QSFragment qsFragment) {
+ mView.setQs(qsFragment);
+ }
+
+ /** */
+ public void restoreInstanceState(Bundle savedInstanceState) {
+ boolean customizing = savedInstanceState.getBoolean(EXTRA_QS_CUSTOMIZING);
+ if (customizing) {
+ mView.setVisibility(View.VISIBLE);
+ mView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ mView.removeOnLayoutChangeListener(this);
+ show(0, 0, true);
+ }
+ });
+ }
+ }
+
+ /** */
+ public void saveInstanceState(Bundle outState) {
+ if (mView.isShown()) {
+ mKeyguardStateController.removeCallback(mKeyguardCallback);
+ }
+ outState.putBoolean(EXTRA_QS_CUSTOMIZING, mView.isCustomizing());
+ }
+
+ /** */
+ public void setEditLocation(int x, int y) {
+ mView.setEditLocation(x, y);
+ }
+
+ /** */
+ public void setContainer(NotificationsQuickSettingsContainer container) {
+ mView.setContainer(container);
+ }
+
+ public boolean isShown() {
+ return mView.isShown();
+ }
+
+ /** Hice the customizer. */
+ public void hide() {
+ final boolean animate = mScreenLifecycle.getScreenState() != ScreenLifecycle.SCREEN_OFF;
+ if (mView.isShown()) {
+ mUiEventLogger.log(QSEditEvent.QS_EDIT_CLOSED);
+ mToolbar.dismissPopupMenus();
+ mView.setCustomizing(false);
+ save();
+ mView.hide(animate);
+ mView.updateNavColors(mLightBarController);
+ mKeyguardStateController.removeCallback(mKeyguardCallback);
+ }
+ }
+
+ private void save() {
+ if (mTileQueryHelper.isFinished()) {
+ mTileAdapter.saveSpecs(mQsTileHost);
+ }
+ }
+
+ private void setTileSpecs() {
+ List<String> specs = new ArrayList<>();
+ for (QSTile tile : mQsTileHost.getTiles()) {
+ specs.add(tile.getTileSpec());
+ }
+ mTileAdapter.setTileSpecs(specs);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index b471dfae02d1..036fa8667c6f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -46,16 +46,22 @@ import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.customize.TileAdapter.Holder;
import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
+import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSIconViewImpl;
import java.util.ArrayList;
import java.util.List;
+import javax.inject.Inject;
+
+/** */
+@QSScope
public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileStateListener {
private static final long DRAG_LENGTH = 100;
private static final float DRAG_SCALE = 1.2f;
public static final long MOVE_DURATION = 150;
+ public static final int NUM_COLUMNS = 4;
private static final int TYPE_TILE = 0;
private static final int TYPE_EDIT = 1;
@@ -78,6 +84,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
private final ItemDecoration mDecoration;
private final MarginTileDecoration mMarginDecoration;
private final int mMinNumTiles;
+ private final QSTileHost mHost;
private int mEditIndex;
private int mTileDividerIndex;
private int mFocusIndex;
@@ -89,13 +96,14 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
private Holder mCurrentDrag;
private int mAccessibilityAction = ACTION_NONE;
private int mAccessibilityFromIndex;
- private QSTileHost mHost;
private final UiEventLogger mUiEventLogger;
private final AccessibilityDelegateCompat mAccessibilityDelegate;
private RecyclerView mRecyclerView;
- public TileAdapter(Context context, UiEventLogger uiEventLogger) {
+ @Inject
+ public TileAdapter(Context context, QSTileHost qsHost, UiEventLogger uiEventLogger) {
mContext = context;
+ mHost = qsHost;
mUiEventLogger = uiEventLogger;
mItemTouchHelper = new ItemTouchHelper(mCallbacks);
mDecoration = new TileItemDecoration(context);
@@ -114,10 +122,6 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
mRecyclerView = null;
}
- public void setHost(QSTileHost host) {
- mHost = host;
- }
-
public ItemTouchHelper getItemTouchHelper() {
return mItemTouchHelper;
}
@@ -154,9 +158,10 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
mAccessibilityAction = ACTION_NONE;
}
- public void resetTileSpecs(QSTileHost host, List<String> specs) {
+ /** */
+ public void resetTileSpecs(List<String> specs) {
// Notify the host so the tiles get removed callbacks.
- host.changeTiles(mCurrentSpecs, specs);
+ mHost.changeTiles(mCurrentSpecs, specs);
setTileSpecs(specs);
}
@@ -596,7 +601,11 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
@Override
public int getSpanSize(int position) {
final int type = getItemViewType(position);
- return type == TYPE_EDIT || type == TYPE_DIVIDER || type == TYPE_HEADER ? 3 : 1;
+ if (type == TYPE_EDIT || type == TYPE_DIVIDER || type == TYPE_HEADER) {
+ return NUM_COLUMNS;
+ } else {
+ return 1;
+ }
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index b795a5f5ea19..59490c666a83 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -37,6 +37,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
import com.android.systemui.settings.UserTracker;
@@ -50,6 +51,8 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
+/** */
+@QSScope
public class TileQueryHelper {
private static final String TAG = "TileQueryHelper";
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
index 51b2c8dfffbd..8cc05026e1f1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
@@ -22,6 +22,7 @@ import com.android.systemui.qs.QSFooter;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.qs.QuickQSPanelController;
+import com.android.systemui.qs.customize.QSCustomizerController;
import dagger.BindsInstance;
import dagger.Subcomponent;
@@ -32,6 +33,7 @@ import dagger.Subcomponent;
@Subcomponent(modules = {QSFragmentModule.class})
@QSScope
public interface QSFragmentComponent {
+
/** Factory for building a {@link QSFragmentComponent}. */
@Subcomponent.Factory
interface Factory {
@@ -52,4 +54,7 @@ public interface QSFragmentComponent {
/** Construct a {@link QSFooter} */
QSFooter getQSFooter();
+
+ /** Construct a {@link QSCustomizerController}. */
+ QSCustomizerController getQSCustomizerController();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 4bf4eff4c27e..f3bf306642f6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.dagger;
+import android.view.LayoutInflater;
import android.view.View;
import com.android.systemui.R;
@@ -29,6 +30,9 @@ import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QuickQSPanel;
import com.android.systemui.qs.QuickStatusBarHeader;
+import com.android.systemui.qs.customize.QSCustomizer;
+
+import javax.inject.Named;
import dagger.Binds;
import dagger.Module;
@@ -39,6 +43,8 @@ import dagger.Provides;
*/
@Module
public interface QSFragmentModule {
+ String QS_SECURITY_FOOTER_VIEW = "qs_security_footer";
+
/** */
@Provides
@RootView
@@ -87,4 +93,19 @@ public interface QSFragmentModule {
qsFooterViewController.init();
return qsFooterViewController;
}
-}
+
+ /** */
+ @Provides
+ @QSScope
+ static QSCustomizer providesQSCutomizer(@RootView View view) {
+ return view.findViewById(R.id.qs_customize);
+ }
+
+ /** */
+ @Provides
+ @QSScope
+ @Named(QS_SECURITY_FOOTER_VIEW)
+ static View providesQSSecurityFooterView(LayoutInflater layoutInflater, QSPanel qsPanel) {
+ return layoutInflater.inflate(R.layout.quick_settings_footer, qsPanel, false);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 8e33496e73af..24c0fd76d827 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -40,6 +40,7 @@ import com.android.systemui.qs.tiles.HotspotTile;
import com.android.systemui.qs.tiles.LocationTile;
import com.android.systemui.qs.tiles.NfcTile;
import com.android.systemui.qs.tiles.NightDisplayTile;
+import com.android.systemui.qs.tiles.ReduceBrightColorsTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.qs.tiles.ScreenRecordTile;
import com.android.systemui.qs.tiles.UiModeNightTile;
@@ -78,6 +79,7 @@ public class QSFactoryImpl implements QSFactory {
private final Provider<GarbageMonitor.MemoryTile> mMemoryTileProvider;
private final Provider<UiModeNightTile> mUiModeNightTileProvider;
private final Provider<ScreenRecordTile> mScreenRecordTileProvider;
+ private final Provider<ReduceBrightColorsTile> mReduceBrightColorsTileProvider;
private final Lazy<QSHost> mQsHostLazy;
private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
@@ -105,7 +107,8 @@ public class QSFactoryImpl implements QSFactory {
Provider<NfcTile> nfcTileProvider,
Provider<GarbageMonitor.MemoryTile> memoryTileProvider,
Provider<UiModeNightTile> uiModeNightTileProvider,
- Provider<ScreenRecordTile> screenRecordTileProvider) {
+ Provider<ScreenRecordTile> screenRecordTileProvider,
+ Provider<ReduceBrightColorsTile> reduceBrightColorsTileProvider) {
mQsHostLazy = qsHostLazy;
mCustomTileBuilderProvider = customTileBuilderProvider;
@@ -129,6 +132,7 @@ public class QSFactoryImpl implements QSFactory {
mMemoryTileProvider = memoryTileProvider;
mUiModeNightTileProvider = uiModeNightTileProvider;
mScreenRecordTileProvider = screenRecordTileProvider;
+ mReduceBrightColorsTileProvider = reduceBrightColorsTileProvider;
}
public QSTile createTile(String tileSpec) {
@@ -180,6 +184,8 @@ public class QSFactoryImpl implements QSFactory {
return mUiModeNightTileProvider.get();
case "screenrecord":
return mScreenRecordTileProvider.get();
+ case "reduce_brightness":
+ return mReduceBrightColorsTileProvider.get();
}
// Custom tiles
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 5e6a6ce45b46..f742752d80be 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -25,6 +25,7 @@ import android.content.Intent;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Looper;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.telephony.SubscriptionManager;
@@ -244,7 +245,8 @@ public class CellularTile extends QSTileImpl<SignalState> {
@Override
public boolean isAvailable() {
- return mController.hasMobileDataFeature();
+ return mController.hasMobileDataFeature()
+ && mHost.getUserContext().getUserId() == UserHandle.USER_SYSTEM;
}
private static final class CallbackInfo {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 39952488799a..a6d96042d5af 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -70,7 +70,7 @@ public class ColorInversionTile extends QSTileImpl<BooleanState> {
super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
activityStarter, qsLogger);
- mSetting = new SecureSetting(secureSettings, mainHandler,
+ mSetting = new SecureSetting(secureSettings, mHandler,
Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, userTracker.getUserId()) {
@Override
protected void handleValueChanged(int value, boolean observedChange) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
new file mode 100644
index 000000000000..84c7611478cd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -0,0 +1,139 @@
+/*
+ * 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.qs.tiles;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.service.quicksettings.Tile;
+import android.text.TextUtils;
+import android.widget.Switch;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.settings.SecureSettings;
+
+import javax.inject.Inject;
+
+/** Quick settings tile: Reduce Bright Colors **/
+public class ReduceBrightColorsTile extends QSTileImpl<QSTile.BooleanState> {
+
+ //TODO(b/170973645): get icon drawable
+ private final Icon mIcon = null;
+ private final SecureSetting mActivatedSetting;
+
+ @Inject
+ public ReduceBrightColorsTile(
+ QSHost host,
+ @Background Looper backgroundLooper,
+ @Main Handler mainHandler,
+ MetricsLogger metricsLogger,
+ StatusBarStateController statusBarStateController,
+ ActivityStarter activityStarter,
+ QSLogger qsLogger,
+ UserTracker userTracker,
+ SecureSettings secureSettings
+ ) {
+ super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+ activityStarter, qsLogger);
+
+ mActivatedSetting = new SecureSetting(secureSettings, mainHandler,
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, userTracker.getUserId()) {
+ @Override
+ protected void handleValueChanged(int value, boolean observedChange) {
+ refreshState();
+ }
+ };
+ }
+ @Override
+ public boolean isAvailable() {
+ // TODO(b/170970675): Call into ColorDisplayService to get availability/config status
+ return true;
+ }
+
+ @Override
+ protected void handleDestroy() {
+ super.handleDestroy();
+ mActivatedSetting.setListening(false);
+ }
+
+ @Override
+ public BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ public void handleSetListening(boolean listening) {
+ super.handleSetListening(listening);
+ mActivatedSetting.setListening(listening);
+ }
+
+ @Override
+ protected void handleUserSwitch(int newUserId) {
+ mActivatedSetting.setUserId(newUserId);
+ refreshState();
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_REDUCE_BRIGHT_COLORS_SETTINGS);
+ }
+
+ @Override
+ protected void handleClick() {
+ mActivatedSetting.setValue(mState.value ? 0 : 1);
+ }
+
+ @Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_reduce_bright_colors_label);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ state.value = mActivatedSetting.getValue() == 1;
+ state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ state.label = mContext.getString(R.string.quick_settings_reduce_bright_colors_label);
+ state.expandedAccessibilityClassName = Switch.class.getName();
+ state.contentDescription = state.label;
+
+ final int intensity = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0, mActivatedSetting.getCurrentUser());
+ state.secondaryLabel = state.value ? mContext.getString(
+ R.string.quick_settings_reduce_bright_colors_secondary_label, intensity) : "";
+
+ state.contentDescription = TextUtils.isEmpty(state.secondaryLabel)
+ ? state.label
+ : TextUtils.concat(state.label, ", ", state.secondaryLabel);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return 0;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index ddf30ad663dd..c27b0473f16c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -207,8 +207,9 @@ public class OverviewProxyService extends CurrentUserTracker implements
try {
// TODO move this logic to message queue
mStatusBarOptionalLazy.ifPresent(statusBarLazy -> {
+ StatusBar statusBar = statusBarLazy.get();
+ statusBar.getPanelController().startExpandLatencyTracking();
mHandler.post(()-> {
- StatusBar statusBar = statusBarLazy.get();
int action = event.getActionMasked();
if (action == ACTION_DOWN) {
mInputFocusTransferStarted = true;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
index 5c26d9400c9f..df9fc63a33f0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
@@ -35,9 +35,6 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.phone.StatusBar;
import java.util.Optional;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import javax.inject.Inject;
@@ -48,7 +45,6 @@ import javax.inject.Inject;
public class ActionProxyReceiver extends BroadcastReceiver {
private static final String TAG = "ActionProxyReceiver";
- private static final int CLOSE_WINDOWS_TIMEOUT_MILLIS = 3000;
private final StatusBar mStatusBar;
private final ActivityManagerWrapper mActivityManagerWrapper;
private final ScreenshotSmartActions mScreenshotSmartActions;
@@ -65,14 +61,7 @@ public class ActionProxyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, final Intent intent) {
Runnable startActivityRunnable = () -> {
- try {
- mActivityManagerWrapper.closeSystemWindows(
- SYSTEM_DIALOG_REASON_SCREENSHOT).get(
- CLOSE_WINDOWS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException | InterruptedException | ExecutionException e) {
- Log.e(TAG, "Unable to share screenshot", e);
- return;
- }
+ mActivityManagerWrapper.closeSystemWindows(SYSTEM_DIALOG_REASON_SCREENSHOT);
PendingIntent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT);
ActivityOptions opts = ActivityOptions.makeBasic();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 260f55799e0b..35874cd8bb28 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -27,7 +27,6 @@ import android.animation.AnimatorListenerAdapter;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.Notification;
-import android.app.WindowContext;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
@@ -43,6 +42,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -58,8 +58,10 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
+import com.android.systemui.util.DeviceConfigProxy;
import java.util.List;
import java.util.function.Consumer;
@@ -143,6 +145,8 @@ public class ScreenshotController {
private final DisplayMetrics mDisplayMetrics;
private final AccessibilityManager mAccessibilityManager;
private final MediaActionSound mCameraSound;
+ private final ScrollCaptureClient mScrollCaptureClient;
+ private final DeviceConfigProxy mConfigProxy;
private final Binder mWindowToken;
private ScreenshotView mScreenshotView;
@@ -150,7 +154,6 @@ public class ScreenshotController {
private SaveImageInBackgroundTask mSaveInBgTask;
private Animator mScreenshotAnimation;
- private Animator mDismissAnimation;
private Runnable mOnCompleteRunnable;
private boolean mInDarkMode;
@@ -164,7 +167,6 @@ public class ScreenshotController {
case MESSAGE_CORNER_TIMEOUT:
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT);
ScreenshotController.this.dismissScreenshot(false);
- mOnCompleteRunnable.run();
break;
default:
break;
@@ -173,11 +175,16 @@ public class ScreenshotController {
};
@Inject
- ScreenshotController(Context context, ScreenshotSmartActions screenshotSmartActions,
+ ScreenshotController(
+ Context context,
+ ScreenshotSmartActions screenshotSmartActions,
ScreenshotNotificationsController screenshotNotificationsController,
- UiEventLogger uiEventLogger) {
+ ScrollCaptureClient scrollCaptureClient,
+ UiEventLogger uiEventLogger,
+ DeviceConfigProxy configProxy) {
mScreenshotSmartActions = screenshotSmartActions;
mNotificationsController = screenshotNotificationsController;
+ mScrollCaptureClient = scrollCaptureClient;
mUiEventLogger = uiEventLogger;
final DisplayManager dm = requireNonNull(context.getSystemService(DisplayManager.class));
@@ -186,6 +193,7 @@ public class ScreenshotController {
mWindowManager = mContext.getSystemService(WindowManager.class);
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
+ mConfigProxy = configProxy;
reloadAssets();
Configuration config = mContext.getResources().getConfiguration();
@@ -193,6 +201,7 @@ public class ScreenshotController {
mDirectionLTR = config.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
mOrientationPortrait = config.orientation == ORIENTATION_PORTRAIT;
mWindowToken = new Binder("ScreenshotController");
+ mScrollCaptureClient.setHostWindowToken(mWindowToken);
// Setup the window that we are going to use
mWindowLayoutParams = new WindowManager.LayoutParams(
@@ -210,6 +219,8 @@ public class ScreenshotController {
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
mWindowLayoutParams.setFitInsetsTypes(0 /* types */);
mWindowLayoutParams.token = mWindowToken;
+ // This is needed to let touches pass through outside the touchable areas
+ mWindowLayoutParams.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
mDisplayMetrics = new DisplayMetrics();
mDisplay.getRealMetrics(mDisplayMetrics);
@@ -266,30 +277,22 @@ public class ScreenshotController {
rect -> takeScreenshotInternal(finisher, rect));
}
- boolean isDismissing() {
- return (mDismissAnimation != null && mDismissAnimation.isRunning());
- }
-
/**
* Clears current screenshot
*/
void dismissScreenshot(boolean immediate) {
- Log.v(TAG, "clearing screenshot");
+ // If we're already animating out, don't restart the animation
+ // (but do obey an immediate dismissal)
+ if (!immediate && mScreenshotView.isDismissing()) {
+ Log.v(TAG, "Already dismissing, ignoring duplicate command");
+ return;
+ }
+ Log.v(TAG, "Clearing screenshot");
mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
- mScreenshotView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
- mScreenshotView);
- if (!immediate) {
- mDismissAnimation = mScreenshotView.createScreenshotDismissAnimation();
- mDismissAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- clearScreenshot();
- }
- });
- mDismissAnimation.start();
+ if (immediate) {
+ resetScreenshotView();
} else {
- clearScreenshot();
+ mScreenshotView.animateDismissal();
}
}
@@ -360,6 +363,7 @@ public class ScreenshotController {
// Inflate the screenshot layout
mScreenshotView = (ScreenshotView)
LayoutInflater.from(mContext).inflate(R.layout.global_screenshot, null);
+ mScreenshotView.init(mUiEventLogger, this::resetScreenshotView);
// TODO(159460485): Remove this when focus is handled properly in the system
mScreenshotView.setOnTouchListener((v, event) -> {
@@ -425,10 +429,10 @@ public class ScreenshotController {
if (mScreenshotView.isAttachedToWindow()) {
// if we didn't already dismiss for another reason
- if (mDismissAnimation == null || !mDismissAnimation.isRunning()) {
+ if (!mScreenshotView.isDismissing()) {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_REENTERED);
}
- dismissScreenshot(true);
+ mScreenshotView.reset();
}
mScreenBitmap = screenshot;
@@ -446,15 +450,25 @@ public class ScreenshotController {
onConfigChanged(mContext.getResources().getConfiguration());
- if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
- mDismissAnimation.cancel();
- }
-
// The window is focusable by default
setWindowFocusable(true);
// Start the post-screenshot animation
startAnimation(finisher, screenRect, screenInsets, showFlash);
+
+ if (mConfigProxy.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.SCREENSHOT_SCROLLING_ENABLED, false)) {
+ mScrollCaptureClient.request(DEFAULT_DISPLAY, (connection) ->
+ mScreenshotView.showScrollChip(() ->
+ runScrollCapture(connection,
+ () -> mScreenshotHandler.post(
+ () -> dismissScreenshot(false)))));
+ }
+ }
+
+ private void runScrollCapture(ScrollCaptureClient.Connection connection,
+ Runnable after) {
+ new ScrollCaptureController(mContext, connection).run(after);
}
/**
@@ -493,6 +507,7 @@ public class ScreenshotController {
*/
private void startAnimation(final Consumer<Uri> finisher, Rect screenRect, Insets screenInsets,
boolean showFlash) {
+ mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
mScreenshotHandler.post(() -> {
if (!mScreenshotView.isAttachedToWindow()) {
mWindowManager.addView(mScreenshotView, mWindowLayoutParams);
@@ -505,8 +520,7 @@ public class ScreenshotController {
mScreenshotView);
mScreenshotAnimation =
- mScreenshotView.createScreenshotDropInAnimation(screenRect, showFlash,
- this::onElementTapped);
+ mScreenshotView.createScreenshotDropInAnimation(screenRect, showFlash);
saveScreenshotInWorkerThread(finisher,
new ScreenshotController.ActionsReadyListener() {
@@ -525,6 +539,14 @@ public class ScreenshotController {
});
}
+ private void resetScreenshotView() {
+ if (mScreenshotView.isAttachedToWindow()) {
+ mWindowManager.removeView(mScreenshotView);
+ }
+ mScreenshotView.reset();
+ mOnCompleteRunnable.run();
+ }
+
/**
* Creates a new worker thread and saves the screenshot to the media store.
*/
@@ -564,7 +586,6 @@ public class ScreenshotController {
SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS,
AccessibilityManager.FLAG_CONTENT_CONTROLS);
- mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
mScreenshotHandler.sendMessageDelayed(
mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
timeoutMs);
@@ -576,24 +597,16 @@ public class ScreenshotController {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
- mScreenshotView.setChipIntents(
- imageData, event -> onElementTapped(event));
+ mScreenshotView.setChipIntents(imageData);
}
});
} else {
- mScreenshotView.setChipIntents(
- imageData, this::onElementTapped);
+ mScreenshotView.setChipIntents(imageData);
}
});
}
}
- private void onElementTapped(ScreenshotEvent event) {
- mUiEventLogger.log(event);
- dismissScreenshot(false);
- mOnCompleteRunnable.run();
- }
-
/**
* Logs success/failure of the screenshot saving task, and shows an error if it failed.
*/
@@ -607,20 +620,11 @@ public class ScreenshotController {
}
}
- private void clearScreenshot() {
- if (mScreenshotView.isAttachedToWindow()) {
- mWindowManager.removeView(mScreenshotView);
- }
-
- mScreenshotView.reset();
- }
-
private boolean isUserSetupComplete() {
return Settings.Secure.getInt(mContext.getContentResolver(),
SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
}
-
/**
* Updates the window focusability. If the window is already showing, then it updates the
* window immediately, otherwise the layout params will be applied when the window is next
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 29f6e8b0db00..2b4eacbe616b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -60,6 +60,7 @@ import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.shared.system.QuickStepContract;
@@ -113,6 +114,11 @@ public class ScreenshotView extends FrameLayout implements
private FrameLayout mDismissButton;
private ScreenshotActionChip mShareChip;
private ScreenshotActionChip mEditChip;
+ private ScreenshotActionChip mScrollChip;
+
+ private UiEventLogger mUiEventLogger;
+ private Runnable mOnDismissRunnable;
+ private Animator mDismissAnimation;
private final ArrayList<ScreenshotActionChip> mSmartChips = new ArrayList<>();
private PendingInteraction mPendingInteraction;
@@ -152,6 +158,20 @@ public class ScreenshotView extends FrameLayout implements
mContext.getDisplay().getRealMetrics(mDisplayMetrics);
}
+ /**
+ * Called to display the scroll action chip when support is detected.
+ *
+ * @param onClick the action to take when the chip is clicked.
+ */
+ public void showScrollChip(Runnable onClick) {
+ mScrollChip.setVisibility(VISIBLE);
+ mScrollChip.setOnClickListener((v) ->
+ onClick.run()
+ // TODO Logging, store event consumer to a field
+ //onElementTapped.accept(ScreenshotEvent.SCREENSHOT_SCROLL_TAPPED);
+ );
+ }
+
@Override // ViewTreeObserver.OnComputeInternalInsetsListener
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
@@ -193,6 +213,7 @@ public class ScreenshotView extends FrameLayout implements
mScreenshotSelectorView = requireNonNull(findViewById(R.id.global_screenshot_selector));
mShareChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_share_chip));
mEditChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_edit_chip));
+ mScrollChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_scroll_chip));
mScreenshotPreview.setClipToOutline(true);
mScreenshotPreview.setOutlineProvider(new ViewOutlineProvider() {
@@ -232,6 +253,17 @@ public class ScreenshotView extends FrameLayout implements
requestFocus();
}
+ /**
+ * Set up the logger and callback on dismissal.
+ *
+ * Note: must be called before any other (non-constructor) method or null pointer exceptions
+ * may occur.
+ */
+ void init(UiEventLogger uiEventLogger, Runnable onDismissRunnable) {
+ mUiEventLogger = uiEventLogger;
+ mOnDismissRunnable = onDismissRunnable;
+ }
+
void takePartialScreenshot(Consumer<Rect> onPartialScreenshotSelected) {
mScreenshotSelectorView.setOnScreenshotSelected(onPartialScreenshotSelected);
mScreenshotSelectorView.setVisibility(View.VISIBLE);
@@ -244,8 +276,7 @@ public class ScreenshotView extends FrameLayout implements
mScreenshotPreview.setVisibility(View.INVISIBLE);
}
- AnimatorSet createScreenshotDropInAnimation(Rect bounds, boolean showFlash,
- Consumer<ScreenshotEvent> onElementTapped) {
+ AnimatorSet createScreenshotDropInAnimation(Rect bounds, boolean showFlash) {
mScreenshotPreview.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mScreenshotPreview.buildLayer();
@@ -346,8 +377,10 @@ public class ScreenshotView extends FrameLayout implements
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
- mDismissButton.setOnClickListener(view ->
- onElementTapped.accept(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL));
+ mDismissButton.setOnClickListener(view -> {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL);
+ animateDismissal();
+ });
mDismissButton.setAlpha(1);
float dismissOffset = mDismissButton.getWidth() / 2f;
float finalDismissX = mDirectionLTR
@@ -387,7 +420,7 @@ public class ScreenshotView extends FrameLayout implements
});
chips.add(mShareChip);
- mEditChip.setText(mContext.getString(com.android.internal.R.string.screenshot_edit));
+ mEditChip.setText(mContext.getString(R.string.screenshot_edit_label));
mEditChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_edit), true);
mEditChip.setOnClickListener(v -> {
mEditChip.setIsPending(true);
@@ -402,6 +435,11 @@ public class ScreenshotView extends FrameLayout implements
mPendingInteraction = PendingInteraction.PREVIEW;
});
+ mScrollChip.setText(mContext.getString(R.string.screenshot_scroll_label));
+ mScrollChip.setIcon(Icon.createWithResource(mContext,
+ R.drawable.ic_screenshot_scroll), true);
+ chips.add(mScrollChip);
+
// remove the margin from the last chip so that it's correctly aligned with the end
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)
mActionsView.getChildAt(0).getLayoutParams();
@@ -439,19 +477,25 @@ public class ScreenshotView extends FrameLayout implements
return animator;
}
- void setChipIntents(ScreenshotController.SavedImageData imageData,
- Consumer<ScreenshotEvent> onElementTapped) {
+ void setChipIntents(ScreenshotController.SavedImageData imageData) {
mShareChip.setPendingIntent(imageData.shareAction.actionIntent,
- () -> onElementTapped.accept(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED));
+ () -> {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED);
+ animateDismissal();
+ });
mEditChip.setPendingIntent(imageData.editAction.actionIntent,
- () -> onElementTapped.accept(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED));
+ () -> {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED);
+ animateDismissal();
+ });
mScreenshotPreview.setOnClickListener(v -> {
try {
imageData.editAction.actionIntent.send();
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Intent cancelled", e);
}
- onElementTapped.accept(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED);
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED);
+ animateDismissal();
});
if (mPendingInteraction != null) {
@@ -475,43 +519,49 @@ public class ScreenshotView extends FrameLayout implements
actionChip.setText(smartAction.title);
actionChip.setIcon(smartAction.getIcon(), false);
actionChip.setPendingIntent(smartAction.actionIntent,
- () -> onElementTapped.accept(
- ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED));
+ () -> {
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED);
+ animateDismissal();
+ });
mActionsView.addView(actionChip);
mSmartChips.add(actionChip);
}
}
}
+ boolean isDismissing() {
+ return (mDismissAnimation != null && mDismissAnimation.isRunning());
+ }
- AnimatorSet createScreenshotDismissAnimation() {
- ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
- alphaAnim.setStartDelay(SCREENSHOT_DISMISS_ALPHA_OFFSET_MS);
- alphaAnim.setDuration(SCREENSHOT_DISMISS_ALPHA_DURATION_MS);
- alphaAnim.addUpdateListener(animation -> {
- setAlpha(1 - animation.getAnimatedFraction());
- });
-
- ValueAnimator yAnim = ValueAnimator.ofFloat(0, 1);
- yAnim.setInterpolator(mAccelerateInterpolator);
- yAnim.setDuration(SCREENSHOT_DISMISS_Y_DURATION_MS);
- float screenshotStartY = mScreenshotPreview.getTranslationY();
- float dismissStartY = mDismissButton.getTranslationY();
- yAnim.addUpdateListener(animation -> {
- float yDelta = MathUtils.lerp(0, mDismissDeltaY, animation.getAnimatedFraction());
- mScreenshotPreview.setTranslationY(screenshotStartY + yDelta);
- mDismissButton.setTranslationY(dismissStartY + yDelta);
- mActionsContainer.setTranslationY(yDelta);
- mActionsContainerBackground.setTranslationY(yDelta);
- });
+ void animateDismissal() {
+ getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+ mDismissAnimation = createScreenshotDismissAnimation();
+ mDismissAnimation.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled = false;
- AnimatorSet animSet = new AnimatorSet();
- animSet.play(yAnim).with(alphaAnim);
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ mCancelled = true;
+ }
- return animSet;
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (!mCancelled) {
+ mOnDismissRunnable.run();
+ }
+ }
+ });
+ mDismissAnimation.start();
}
void reset() {
+ if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
+ mDismissAnimation.cancel();
+ }
+ // Make sure we clean up the view tree observer
+ getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
// Clear any references to the bitmap
mScreenshotPreview.setImageDrawable(null);
mActionsContainerBackground.setVisibility(View.GONE);
@@ -540,6 +590,33 @@ public class ScreenshotView extends FrameLayout implements
mScreenshotSelectorView.stop();
}
+ private AnimatorSet createScreenshotDismissAnimation() {
+ ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
+ alphaAnim.setStartDelay(SCREENSHOT_DISMISS_ALPHA_OFFSET_MS);
+ alphaAnim.setDuration(SCREENSHOT_DISMISS_ALPHA_DURATION_MS);
+ alphaAnim.addUpdateListener(animation -> {
+ setAlpha(1 - animation.getAnimatedFraction());
+ });
+
+ ValueAnimator yAnim = ValueAnimator.ofFloat(0, 1);
+ yAnim.setInterpolator(mAccelerateInterpolator);
+ yAnim.setDuration(SCREENSHOT_DISMISS_Y_DURATION_MS);
+ float screenshotStartY = mScreenshotPreview.getTranslationY();
+ float dismissStartY = mDismissButton.getTranslationY();
+ yAnim.addUpdateListener(animation -> {
+ float yDelta = MathUtils.lerp(0, mDismissDeltaY, animation.getAnimatedFraction());
+ mScreenshotPreview.setTranslationY(screenshotStartY + yDelta);
+ mDismissButton.setTranslationY(dismissStartY + yDelta);
+ mActionsContainer.setTranslationY(yDelta);
+ mActionsContainerBackground.setTranslationY(yDelta);
+ });
+
+ AnimatorSet animSet = new AnimatorSet();
+ animSet.play(yAnim).with(alphaAnim);
+
+ return animSet;
+ }
+
/**
* Create a drawable using the size of the bitmap and insets as the fractional inset parameters.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
new file mode 100644
index 000000000000..ea835fa94fe8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -0,0 +1,346 @@
+/*
+ * 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.screenshot;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.UiContext;
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.media.Image;
+import android.media.ImageReader;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IScrollCaptureCallbacks;
+import android.view.IScrollCaptureConnection;
+import android.view.IWindowManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.view.ScrollCaptureViewSupport;
+
+import java.util.function.Consumer;
+
+import javax.inject.Inject;
+
+/**
+ * High level interface to scroll capture API.
+ */
+public class ScrollCaptureClient {
+
+ @VisibleForTesting
+ static final int MATCH_ANY_TASK = ActivityTaskManager.INVALID_TASK_ID;
+
+ private static final String TAG = "ScrollCaptureClient";
+
+ /** Whether to log method names and arguments for most calls */
+ private static final boolean DEBUG_TRACE = false;
+
+ /**
+ * A connection to a remote window. Starts a capture session.
+ */
+ public interface Connection {
+ /**
+ * Session start should be deferred until UI is active because of resource allocation and
+ * potential visible side effects in the target window.
+ *
+ * @param maxBuffers the maximum number of buffers (tiles) that may be in use at one
+ * time, tiles are not cached anywhere so set this to a large enough
+ * number to retain offscreen content until it is no longer needed
+ * @param sessionConsumer listener to receive the session once active
+ */
+ void start(int maxBuffers, Consumer<Session> sessionConsumer);
+
+ /**
+ * Close the connection.
+ */
+ void close();
+ }
+
+ static class CaptureResult {
+ public final Image image;
+ /**
+ * The area requested, in content rect space, relative to scroll-bounds.
+ */
+ public final Rect requested;
+ /**
+ * The actual area captured, in content rect space, relative to scroll-bounds. This may be
+ * cropped or empty depending on available content.
+ */
+ public final Rect captured;
+
+ // Error?
+
+ private CaptureResult(Image image, Rect request, Rect captured) {
+ this.image = image;
+ this.requested = request;
+ this.captured = captured;
+ }
+ }
+
+ /**
+ * Represents the connection to a target window and provides a mechanism for requesting tiles.
+ */
+ interface Session {
+ /**
+ * Request the given horizontal strip. Values are y-coordinates in captured space, relative
+ * to start position.
+ *
+ * @param contentRect the area to capture, in content rect space, relative to scroll-bounds
+ * @param consumer listener to be informed of the result
+ */
+ void requestTile(Rect contentRect, Consumer<CaptureResult> consumer);
+
+ /**
+ * End the capture session, return the target app to original state. The returned
+ * stage must be waited for to complete to allow the target app a chance to restore to
+ * original state before becoming visible.
+ *
+ * @return a stage presenting the session shutdown
+ */
+ void end(Runnable listener);
+
+ int getMaxTileHeight();
+
+ int getMaxTileWidth();
+ }
+
+ private final IWindowManager mWindowManagerService;
+ private IBinder mHostWindowToken;
+
+ @Inject
+ public ScrollCaptureClient(@UiContext Context context, IWindowManager windowManagerService) {
+ requireNonNull(context.getDisplay(), "context must be associated with a Display!");
+ mWindowManagerService = windowManagerService;
+ }
+
+ public void setHostWindowToken(IBinder token) {
+ mHostWindowToken = token;
+ }
+
+ /**
+ * Check for scroll capture support.
+ *
+ * @param displayId id for the display containing the target window
+ * @param consumer receives a connection when available
+ */
+ public void request(int displayId, Consumer<Connection> consumer) {
+ request(displayId, MATCH_ANY_TASK, consumer);
+ }
+
+ /**
+ * Check for scroll capture support.
+ *
+ * @param displayId id for the display containing the target window
+ * @param taskId id for the task containing the target window or {@link #MATCH_ANY_TASK}.
+ * @param consumer receives a connection when available
+ */
+ public void request(int displayId, int taskId, Consumer<Connection> consumer) {
+ try {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "requestScrollCapture(displayId=" + displayId + ", " + mHostWindowToken
+ + ", taskId=" + taskId + ", consumer=" + consumer + ")");
+ }
+ mWindowManagerService.requestScrollCapture(displayId, mHostWindowToken, taskId,
+ new ControllerCallbacks(consumer));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Ignored remote exception", e);
+ }
+ }
+
+ private static class ControllerCallbacks extends IScrollCaptureCallbacks.Stub implements
+ Connection, Session, IBinder.DeathRecipient {
+
+ private IScrollCaptureConnection mConnection;
+ private Consumer<Connection> mConnectionConsumer;
+ private Consumer<Session> mSessionConsumer;
+ private Consumer<CaptureResult> mResultConsumer;
+ private Runnable mShutdownListener;
+
+ private ImageReader mReader;
+ private Rect mScrollBounds;
+ private Rect mRequestRect;
+ private boolean mStarted;
+
+ private ControllerCallbacks(Consumer<Connection> connectionConsumer) {
+ mConnectionConsumer = connectionConsumer;
+ }
+
+ // IScrollCaptureCallbacks
+
+ @Override
+ public void onConnected(IScrollCaptureConnection connection, Rect scrollBounds,
+ Point positionInWindow) throws RemoteException {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "onConnected(connection=" + connection + ", scrollBounds=" + scrollBounds
+ + ", positionInWindow=" + positionInWindow + ")");
+ }
+ mConnection = connection;
+ mConnection.asBinder().linkToDeath(this, 0);
+ mScrollBounds = scrollBounds;
+ mConnectionConsumer.accept(this);
+ mConnectionConsumer = null;
+ }
+
+ @Override
+ public void onUnavailable() throws RemoteException {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "onUnavailable");
+ }
+ // The targeted app does not support scroll capture
+ // or the window could not be found... etc etc.
+ }
+
+ @Override
+ public void onCaptureStarted() {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "onCaptureStarted()");
+ }
+ mSessionConsumer.accept(this);
+ mSessionConsumer = null;
+ }
+
+ @Override
+ public void onCaptureBufferSent(long frameNumber, Rect contentArea) {
+ Image image = null;
+ if (frameNumber != ScrollCaptureViewSupport.NO_FRAME_PRODUCED) {
+ image = mReader.acquireNextImage();
+ }
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "onCaptureBufferSent(frameNumber=" + frameNumber
+ + ", contentArea=" + contentArea + ") image=" + image);
+ }
+ // Save and clear first, since the consumer will likely request the next
+ // tile, otherwise the new consumer will be wiped out.
+ Consumer<CaptureResult> consumer = mResultConsumer;
+ mResultConsumer = null;
+ consumer.accept(new CaptureResult(image, mRequestRect, contentArea));
+ }
+
+ @Override
+ public void onConnectionClosed() {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "onConnectionClosed()");
+ }
+ disconnect();
+ if (mShutdownListener != null) {
+ mShutdownListener.run();
+ mShutdownListener = null;
+ }
+ }
+
+ // Misc
+
+ private void disconnect() {
+ if (mConnection != null) {
+ mConnection.asBinder().unlinkToDeath(this, 0);
+ }
+ mConnection = null;
+ }
+
+ // ScrollCaptureController.Connection
+
+ // -> Error handling: BiConsumer<Session, Throwable> ?
+ @Override
+ public void start(int maxBufferCount, Consumer<Session> sessionConsumer) {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "start(maxBufferCount=" + maxBufferCount
+ + ", sessionConsumer=" + sessionConsumer + ")");
+ }
+ mReader = ImageReader.newInstance(mScrollBounds.width(), mScrollBounds.height(),
+ PixelFormat.RGBA_8888, maxBufferCount, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
+ mSessionConsumer = sessionConsumer;
+ try {
+ mConnection.startCapture(mReader.getSurface());
+ mStarted = true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "should not be happening :-(");
+ // ?
+ //mSessionListener.onError(e);
+ //mSessionListener = null;
+ }
+ }
+
+ @Override
+ public void close() {
+ end(null);
+ }
+
+ // ScrollCaptureController.Session
+
+ @Override
+ public void end(Runnable listener) {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "end(listener=" + listener + ")");
+ }
+ if (mStarted) {
+ mShutdownListener = listener;
+ try {
+ // listener called from onConnectionClosed callback
+ mConnection.endCapture();
+ } catch (RemoteException e) {
+ Log.d(TAG, "Ignored exception from endCapture()", e);
+ disconnect();
+ listener.run();
+ }
+ } else {
+ disconnect();
+ listener.run();
+ }
+ }
+
+ @Override
+ public int getMaxTileHeight() {
+ return mScrollBounds.height();
+ }
+
+ @Override
+ public int getMaxTileWidth() {
+ return mScrollBounds.width();
+ }
+
+ @Override
+ public void requestTile(Rect contentRect, Consumer<CaptureResult> consumer) {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "requestTile(contentRect=" + contentRect + "consumer=" + consumer + ")");
+ }
+ mRequestRect = new Rect(contentRect);
+ mResultConsumer = consumer;
+ try {
+ mConnection.requestImage(mRequestRect);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught remote exception from requestImage", e);
+ // ?
+ }
+ }
+
+ /**
+ * The process hosting the window went away abruptly!
+ */
+ @Override
+ public void binderDied() {
+ if (DEBUG_TRACE) {
+ Log.d(TAG, "binderDied()");
+ }
+ disconnect();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 5ced40cb1b3b..47b4a508f401 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -16,46 +16,231 @@
package com.android.systemui.screenshot;
-import android.os.IBinder;
-import android.view.IWindowManager;
+import static android.graphics.ColorSpace.Named.SRGB;
-import javax.inject.Inject;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorSpace;
+import android.graphics.Picture;
+import android.graphics.Rect;
+import android.media.ExifInterface;
+import android.media.Image;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.provider.MediaStore;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
+import com.android.systemui.screenshot.ScrollCaptureClient.Session;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.sql.Date;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.function.Consumer;
/**
- * Stub
+ * Interaction controller between the UI and ScrollCaptureClient.
*/
public class ScrollCaptureController {
+ private static final String TAG = "ScrollCaptureController";
- public static final int STATUS_A = 0;
- public static final int STATUS_B = 1;
+ public static final int MAX_PAGES = 5;
+ public static final int MAX_HEIGHT = 12000;
- private final IWindowManager mWindowManagerService;
- private StatusListener mListener;
+ private final Connection mConnection;
+ private final Context mContext;
+ private Picture mPicture;
+
+ public ScrollCaptureController(Context context, Connection connection) {
+ mContext = context;
+ mConnection = connection;
+ }
/**
+ * Run scroll capture!
*
- * @param windowManagerService
+ * @param after action to take after the flow is complete
*/
- @Inject
- public ScrollCaptureController(IWindowManager windowManagerService) {
- mWindowManagerService = windowManagerService;
+ public void run(final Runnable after) {
+ mConnection.start(MAX_PAGES, (session) -> startCapture(session, after));
}
- interface StatusListener {
- void onScrollCaptureStatus(boolean available);
- }
+ private void startCapture(Session session, final Runnable after) {
+ Rect requestRect = new Rect(0, 0,
+ session.getMaxTileWidth(), session.getMaxTileHeight());
+ Consumer<ScrollCaptureClient.CaptureResult> consumer =
+ new Consumer<ScrollCaptureClient.CaptureResult>() {
+
+ int mFrameCount = 0;
+
+ @Override
+ public void accept(ScrollCaptureClient.CaptureResult result) {
+ mFrameCount++;
+ boolean emptyFrame = result.captured.height() == 0;
+ if (!emptyFrame) {
+ mPicture = stackBelow(mPicture, result.image, result.captured.width(),
+ result.captured.height());
+ }
+ if (emptyFrame || mFrameCount >= MAX_PAGES
+ || requestRect.bottom > MAX_HEIGHT) {
+ Uri uri = null;
+ if (mPicture != null) {
+ // This is probably on a binder thread right now ¯\_(ツ)_/¯
+ uri = writeImage(Bitmap.createBitmap(mPicture));
+ // Release those buffers!
+ mPicture.close();
+ }
+ if (uri != null) {
+ launchViewer(uri);
+ } else {
+ Toast.makeText(mContext, "Failed to create tall screenshot",
+ Toast.LENGTH_SHORT).show();
+ }
+ session.end(after); // end session, close connection, after.run()
+ return;
+ }
+ requestRect.offset(0, session.getMaxTileHeight());
+ session.requestTile(requestRect, /* consumer */ this);
+ }
+ };
+
+ // fire it up!
+ session.requestTile(requestRect, consumer);
+ };
+
/**
+ * Combine the top {@link Picture} with an {@link Image} by appending the image directly
+ * below, creating a result that is the combined height of both.
+ * <p>
+ * Note: no pixel data is transferred here, only a record of drawing commands. Backing
+ * hardware buffers must not be modified/recycled until the picture is
+ * {@link Picture#close closed}.
+ *
+ * @param top the existing picture
+ * @param below the image to append below
+ * @param cropWidth the width of the pixel data to use from the image
+ * @param cropHeight the height of the pixel data to use from the image
*
- * @param window
- * @param listener
+ * @return a new Picture which draws the previous picture with the image below it
*/
- public void getStatus(IBinder window, StatusListener listener) {
- mListener = listener;
-// try {
-// mWindowManagerService.requestScrollCapture(window, new ClientCallbacks());
-// } catch (RemoteException e) {
-// }
+ private static Picture stackBelow(Picture top, Image below, int cropWidth, int cropHeight) {
+ int width = cropWidth;
+ int height = cropHeight;
+ if (top != null) {
+ height += top.getHeight();
+ width = Math.max(width, top.getWidth());
+ }
+ Picture combined = new Picture();
+ Canvas canvas = combined.beginRecording(width, height);
+ int y = 0;
+ if (top != null) {
+ canvas.drawPicture(top, new Rect(0, 0, top.getWidth(), top.getHeight()));
+ y += top.getHeight();
+ }
+ canvas.drawBitmap(Bitmap.wrapHardwareBuffer(
+ below.getHardwareBuffer(), ColorSpace.get(SRGB)), 0, y, null);
+ combined.endRecording();
+ return combined;
}
+ Uri writeImage(Bitmap image) {
+ ContentResolver resolver = mContext.getContentResolver();
+ long mImageTime = System.currentTimeMillis();
+ String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime));
+ String mImageFileName = String.format("tall_Screenshot_%s.png", imageDate);
+ String mScreenshotId = String.format("Screenshot_%s", UUID.randomUUID());
+ try {
+ // Save the screenshot to the MediaStore
+ final ContentValues values = new ContentValues();
+ values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES
+ + File.separator + Environment.DIRECTORY_SCREENSHOTS);
+ values.put(MediaStore.MediaColumns.DISPLAY_NAME, mImageFileName);
+ values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
+ values.put(MediaStore.MediaColumns.DATE_ADDED, mImageTime / 1000);
+ values.put(MediaStore.MediaColumns.DATE_MODIFIED, mImageTime / 1000);
+ values.put(
+ MediaStore.MediaColumns.DATE_EXPIRES,
+ (mImageTime + DateUtils.DAY_IN_MILLIS) / 1000);
+ values.put(MediaStore.MediaColumns.IS_PENDING, 1);
+
+ final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+ values);
+ try {
+ try (OutputStream out = resolver.openOutputStream(uri)) {
+ if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) {
+ throw new IOException("Failed to compress");
+ }
+ }
+
+ // Next, write metadata to help index the screenshot
+ try (ParcelFileDescriptor pfd = resolver.openFile(uri, "rw", null)) {
+ final ExifInterface exif = new ExifInterface(pfd.getFileDescriptor());
+
+ exif.setAttribute(ExifInterface.TAG_SOFTWARE,
+ "Android " + Build.DISPLAY);
+
+ exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH,
+ Integer.toString(image.getWidth()));
+ exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH,
+ Integer.toString(image.getHeight()));
+
+ final ZonedDateTime time = ZonedDateTime.ofInstant(
+ Instant.ofEpochMilli(mImageTime), ZoneId.systemDefault());
+ exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL,
+ DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss").format(time));
+ exif.setAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL,
+ DateTimeFormatter.ofPattern("SSS").format(time));
+
+ if (Objects.equals(time.getOffset(), ZoneOffset.UTC)) {
+ exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "+00:00");
+ } else {
+ exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL,
+ DateTimeFormatter.ofPattern("XXX").format(time));
+ }
+ exif.saveAttributes();
+ }
+
+ // Everything went well above, publish it!
+ values.clear();
+ values.put(MediaStore.MediaColumns.IS_PENDING, 0);
+ values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);
+ resolver.update(uri, values, null, null);
+ return uri;
+ } catch (Exception e) {
+ resolver.delete(uri, null);
+ throw e;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "unable to save screenshot", e);
+ }
+ return null;
+ }
+
+ void launchViewer(Uri uri) {
+ Intent editIntent = new Intent(Intent.ACTION_VIEW);
+ editIntent.setType("image/png");
+ editIntent.setData(uri);
+ editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivityAsUser(editIntent, UserHandle.CURRENT);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 4e2283396e25..5f35e60ad142 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -144,7 +144,7 @@ public class TakeScreenshotService extends Service {
@Override
public boolean onUnbind(Intent intent) {
- if (mScreenshot != null && !mScreenshot.isDismissing()) {
+ if (mScreenshot != null) {
mScreenshot.dismissScreenshot(true);
}
unregisterReceiver(mBroadcastReceiver);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java
deleted file mode 100644
index 90744a62677d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSliderView.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.settings;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.RelativeLayout;
-import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
-import android.widget.TextView;
-
-import com.android.settingslib.RestrictedLockUtils;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.BrightnessMirrorController;
-
-public class ToggleSliderView extends RelativeLayout implements ToggleSlider {
- private Listener mListener;
- private boolean mTracking;
-
- private CompoundButton mToggle;
- private ToggleSeekBar mSlider;
- private TextView mLabel;
-
- private ToggleSliderView mMirror;
- private BrightnessMirrorController mMirrorController;
-
- public ToggleSliderView(Context context) {
- this(context, null);
- }
-
- public ToggleSliderView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ToggleSliderView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- View.inflate(context, R.layout.status_bar_toggle_slider, this);
-
- final Resources res = context.getResources();
- final TypedArray a = context.obtainStyledAttributes(
- attrs, R.styleable.ToggleSliderView, defStyle, 0);
-
- mToggle = findViewById(R.id.toggle);
- mToggle.setOnCheckedChangeListener(mCheckListener);
-
- mSlider = findViewById(R.id.slider);
- mSlider.setOnSeekBarChangeListener(mSeekListener);
-
- mLabel = findViewById(R.id.label);
- mLabel.setText(a.getString(R.styleable.ToggleSliderView_text));
-
- mSlider.setAccessibilityLabel(getContentDescription().toString());
-
- a.recycle();
- }
-
- public void setMirror(ToggleSliderView toggleSlider) {
- mMirror = toggleSlider;
- if (mMirror != null) {
- mMirror.setChecked(mToggle.isChecked());
- mMirror.setMax(mSlider.getMax());
- mMirror.setValue(mSlider.getProgress());
- }
- }
-
- public void setMirrorController(BrightnessMirrorController c) {
- mMirrorController = c;
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (mListener != null) {
- mListener.onInit(this);
- }
- }
-
- public void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
- mToggle.setEnabled(admin == null);
- mSlider.setEnabled(admin == null);
- mSlider.setEnforcedAdmin(admin);
- }
-
- public void setOnChangedListener(Listener l) {
- mListener = l;
- }
-
- @Override
- public void setChecked(boolean checked) {
- mToggle.setChecked(checked);
- }
-
- @Override
- public boolean isChecked() {
- return mToggle.isChecked();
- }
-
- @Override
- public void setMax(int max) {
- mSlider.setMax(max);
- if (mMirror != null) {
- mMirror.setMax(max);
- }
- }
-
- @Override
- public void setValue(int value) {
- mSlider.setProgress(value);
- if (mMirror != null) {
- mMirror.setValue(value);
- }
- }
-
- @Override
- public int getValue() {
- return mSlider.getProgress();
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (mMirror != null) {
- MotionEvent copy = ev.copy();
- mMirror.dispatchTouchEvent(copy);
- copy.recycle();
- }
- return super.dispatchTouchEvent(ev);
- }
-
- private final OnCheckedChangeListener mCheckListener = new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton toggle, boolean checked) {
- mSlider.setEnabled(!checked);
-
- if (mListener != null) {
- mListener.onChanged(
- ToggleSliderView.this, mTracking, checked, mSlider.getProgress(), false);
- }
-
- if (mMirror != null) {
- mMirror.mToggle.setChecked(checked);
- }
- }
- };
-
- private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (mListener != null) {
- mListener.onChanged(
- ToggleSliderView.this, mTracking, mToggle.isChecked(), progress, false);
- }
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- mTracking = true;
-
- if (mListener != null) {
- mListener.onChanged(ToggleSliderView.this, mTracking, mToggle.isChecked(),
- mSlider.getProgress(), false);
- }
-
- mToggle.setChecked(false);
-
- if (mMirrorController != null) {
- mMirrorController.showMirror();
- mMirrorController.setLocation((View) getParent());
- }
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- mTracking = false;
-
- if (mListener != null) {
- mListener.onChanged(ToggleSliderView.this, mTracking, mToggle.isChecked(),
- mSlider.getProgress(), true);
- }
-
- if (mMirrorController != null) {
- mMirrorController.hideMirror();
- }
- }
- };
-}
-
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index 72034f84fd30..be10c26df5bf 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 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.settings;
+package com.android.systemui.settings.brightness;
import static com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX;
import static com.android.settingslib.display.BrightnessUtils.convertGammaToLinearFloat;
@@ -47,6 +47,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.systemui.Dependency;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.settings.CurrentUserTracker;
import java.util.ArrayList;
@@ -100,13 +101,14 @@ public class BrightnessController implements ToggleSlider.Listener {
private ValueAnimator mSliderAnimator;
public interface BrightnessStateChangeCallback {
- public void onBrightnessLevelChanged();
+ /** Indicates that some of the brightness settings have changed */
+ void onBrightnessLevelChanged();
}
/** ContentObserver to watch brightness */
private class BrightnessObserver extends ContentObserver {
- public BrightnessObserver(Handler handler) {
+ BrightnessObserver(Handler handler) {
super(handler);
}
@@ -339,11 +341,6 @@ public class BrightnessController implements ToggleSlider.Listener {
return mChangeCallbacks.remove(cb);
}
- @Override
- public void onInit(ToggleSlider control) {
- // Do nothing
- }
-
public void registerCallbacks() {
mBackgroundHandler.post(mStartListeningRunnable);
}
@@ -355,7 +352,7 @@ public class BrightnessController implements ToggleSlider.Listener {
}
@Override
- public void onChanged(ToggleSlider toggleSlider, boolean tracking, boolean automatic,
+ public void onChanged(boolean tracking, boolean automatic,
int value, boolean stopTracking) {
if (mExternalChange) return;
@@ -409,7 +406,7 @@ public class BrightnessController implements ToggleSlider.Listener {
mBackgroundHandler.post(new Runnable() {
@Override
public void run() {
- ((ToggleSliderView)mControl).setEnforcedAdmin(
+ mControl.setEnforcedAdmin(
RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext,
UserManager.DISALLOW_CONFIG_BRIGHTNESS,
mUserTracker.getCurrentUserId()));
@@ -493,4 +490,5 @@ public class BrightnessController implements ToggleSlider.Listener {
return new BrightnessController(mContext, toggleSlider, mBroadcastDispatcher);
}
}
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessControllerSettings.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessControllerSettings.java
new file mode 100644
index 000000000000..a151fd0b48ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessControllerSettings.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.settings.brightness;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.util.settings.SecureSettings;
+
+import javax.inject.Inject;
+
+/**
+ * Settings for prototyping thick brightness slider
+ */
+@SysUISingleton
+public class BrightnessControllerSettings {
+
+ private static final String THICK_BRIGHTNESS_SLIDER = "sysui_thick_brighthness";
+ private final boolean mUseThickSlider;
+ private final boolean mUseMirrorOnThickSlider;
+
+ @Inject
+ public BrightnessControllerSettings(SecureSettings settings) {
+ mUseThickSlider = settings.getInt(THICK_BRIGHTNESS_SLIDER, 0) != 0;
+ mUseMirrorOnThickSlider = settings.getInt(THICK_BRIGHTNESS_SLIDER, 0) != 2;
+ }
+
+ // Changing this setting between zero and non-zero may crash systemui down the line. Better to
+ // restart systemui after changing it.
+ /** */
+ boolean useThickSlider() {
+ return mUseThickSlider;
+ }
+
+ /** */
+ boolean useMirrorOnThickSlider() {
+ return mUseMirrorOnThickSlider;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
index 70c2531ca6d4..1961bfc9ee27 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 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,20 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.settings;
+package com.android.systemui.settings.brightness;
import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import javax.inject.Inject;
@@ -36,11 +33,15 @@ import javax.inject.Inject;
public class BrightnessDialog extends Activity {
private BrightnessController mBrightnessController;
+ private final BrightnessSlider.Factory mToggleSliderFactory;
private final BroadcastDispatcher mBroadcastDispatcher;
@Inject
- public BrightnessDialog(BroadcastDispatcher broadcastDispatcher) {
+ public BrightnessDialog(
+ BroadcastDispatcher broadcastDispatcher,
+ BrightnessSlider.Factory factory) {
mBroadcastDispatcher = broadcastDispatcher;
+ mToggleSliderFactory = factory;
}
@@ -50,16 +51,21 @@ public class BrightnessDialog extends Activity {
final Window window = getWindow();
- window.setGravity(Gravity.TOP);
+ window.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.requestFeature(Window.FEATURE_NO_TITLE);
- View v = LayoutInflater.from(this).inflate(
- R.layout.quick_settings_brightness_dialog, null);
- setContentView(v);
+ // Calling this creates the decor View, so setLayout takes proper effect
+ // (see Dialog#onWindowAttributesChanged)
+ window.getDecorView();
+ window.setLayout(
+ WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
- final ToggleSliderView slider = findViewById(R.id.brightness_slider);
- mBrightnessController = new BrightnessController(this, slider, mBroadcastDispatcher);
+
+ BrightnessSlider controller = mToggleSliderFactory.create(this, null);
+ controller.init();
+ setContentView(controller.getRootView());
+ mBrightnessController = new BrightnessController(this, controller, mBroadcastDispatcher);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
new file mode 100644
index 000000000000..6c4f8083788a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSlider.java
@@ -0,0 +1,282 @@
+/*
+ * 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.settings.brightness;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.SeekBar;
+
+import androidx.annotation.Nullable;
+
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.BrightnessMirrorController;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+
+/**
+ * {@code ViewController} for a {@code BrightnessSliderView}
+ *
+ * This class allows to control the views of a {@code BrightnessSliderViewView} and get callbacks
+ * when the views change value. It also propagates and manipulates another {@link ToggleSlider} as a
+ * mirror.
+ *
+ * @see BrightnessMirrorController
+ */
+public class BrightnessSlider
+ extends ViewController<View>
+ implements ToggleSlider {
+
+ private Listener mListener;
+ private ToggleSlider mMirror;
+ private final BrightnessSliderView mBrightnessSliderView;
+ private BrightnessMirrorController mMirrorController;
+ private boolean mTracking;
+ private final boolean mUseMirror;
+
+ BrightnessSlider(
+ View rootView,
+ BrightnessSliderView brightnessSliderView,
+ boolean useMirror
+ ) {
+ super(rootView);
+ mBrightnessSliderView = brightnessSliderView;
+ mUseMirror = useMirror;
+ }
+
+ /**
+ * Returns a top level view in the hierarchy that can be attached where necessary
+ */
+ public View getRootView() {
+ return mView;
+ }
+
+ private void enableSlider(boolean enable) {
+ mBrightnessSliderView.enableSlider(enable);
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mBrightnessSliderView.setOnSeekBarChangeListener(mSeekListener);
+ mBrightnessSliderView.setOnCheckedChangeListener(mCheckListener);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mBrightnessSliderView.setOnSeekBarChangeListener(null);
+ mBrightnessSliderView.setOnCheckedChangeListener(null);
+ mBrightnessSliderView.setOnDispatchTouchEventListener(null);
+ }
+
+ @Override
+ public boolean mirrorTouchEvent(MotionEvent ev) {
+ if (mMirror != null) {
+ return copyEventToMirror(ev);
+ } else {
+ // We are the mirror, so we have to dispatch the event
+ return mBrightnessSliderView.dispatchTouchEvent(ev);
+ }
+ }
+
+ private boolean copyEventToMirror(MotionEvent ev) {
+ MotionEvent copy = ev.copy();
+ boolean out = mMirror.mirrorTouchEvent(copy);
+ copy.recycle();
+ return out;
+ }
+
+ @Override
+ public void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
+ mBrightnessSliderView.setEnforcedAdmin(admin);
+ }
+
+ private void setMirror(ToggleSlider toggleSlider) {
+ mMirror = toggleSlider;
+ if (mMirror != null) {
+ mMirror.setChecked(mBrightnessSliderView.isChecked());
+ mMirror.setMax(mBrightnessSliderView.getMax());
+ mMirror.setValue(mBrightnessSliderView.getValue());
+ mBrightnessSliderView.setOnDispatchTouchEventListener(this::mirrorTouchEvent);
+ } else {
+ // If there's no mirror, we may be the ones dispatching, events but we should not mirror
+ // them
+ mBrightnessSliderView.setOnDispatchTouchEventListener(null);
+ }
+ }
+
+ /**
+ * This will set the mirror from the controller using
+ * {@link BrightnessMirrorController#getToggleSlider} as a side-effect.
+ * @param c
+ */
+ @Override
+ public void setMirrorControllerAndMirror(BrightnessMirrorController c) {
+ if (!mUseMirror) return;
+ mMirrorController = c;
+ if (c != null) {
+ setMirror(c.getToggleSlider());
+ } else {
+ // If there's no mirror, we may be the ones dispatching, events but we should not mirror
+ // them
+ mBrightnessSliderView.setOnDispatchTouchEventListener(null);
+ }
+ }
+
+ @Override
+ public void setOnChangedListener(Listener l) {
+ mListener = l;
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ mBrightnessSliderView.setChecked(checked);
+ }
+
+ @Override
+ public boolean isChecked() {
+ return mBrightnessSliderView.isChecked();
+ }
+
+ @Override
+ public void setMax(int max) {
+ mBrightnessSliderView.setMax(max);
+ if (mMirror != null) {
+ mMirror.setMax(max);
+ }
+ }
+
+ @Override
+ public int getMax() {
+ return mBrightnessSliderView.getMax();
+ }
+
+ @Override
+ public void setValue(int value) {
+ mBrightnessSliderView.setValue(value);
+ if (mMirror != null) {
+ mMirror.setValue(value);
+ }
+ }
+
+ @Override
+ public int getValue() {
+ return mBrightnessSliderView.getValue();
+ }
+
+ private final SeekBar.OnSeekBarChangeListener mSeekListener =
+ new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (mListener != null) {
+ mListener.onChanged(mTracking, isChecked(), progress, false);
+ }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ mTracking = true;
+
+ if (mListener != null) {
+ mListener.onChanged(mTracking, isChecked(),
+ getValue(), false);
+ }
+
+ setChecked(false);
+
+ if (mMirrorController != null) {
+ mMirrorController.showMirror();
+ mMirrorController.setLocation((View) mBrightnessSliderView.getParent());
+ }
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ mTracking = false;
+
+ if (mListener != null) {
+ mListener.onChanged(mTracking, isChecked(),
+ getValue(), true);
+ }
+
+ if (mMirrorController != null) {
+ mMirrorController.hideMirror();
+ }
+ }
+ };
+
+ private final CompoundButton.OnCheckedChangeListener mCheckListener =
+ new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton toggle, boolean checked) {
+ enableSlider(!checked);
+
+ if (mListener != null) {
+ mListener.onChanged(mTracking, checked, getValue(), false);
+ }
+
+ if (mMirror != null) {
+ mMirror.setChecked(checked);
+ }
+ }
+ };
+
+ /**
+ * Creates a {@link BrightnessSlider} with its associated view.
+ *
+ * The views inflated are determined by {@link BrightnessControllerSettings#useThickSlider()}.
+ */
+ public static class Factory {
+
+ BrightnessControllerSettings mSettings;
+
+ @Inject
+ public Factory(BrightnessControllerSettings settings) {
+ mSettings = settings;
+ }
+
+ /**
+ * Creates the view hierarchy and controller
+ *
+ * @param context a {@link Context} to inflate the hierarchy
+ * @param viewRoot the {@link ViewGroup} that will contain the hierarchy. The inflated
+ * hierarchy will not be attached
+ */
+ public BrightnessSlider create(Context context, @Nullable ViewGroup viewRoot) {
+ int layout = getLayout();
+ ViewGroup root = (ViewGroup) LayoutInflater.from(context)
+ .inflate(layout, viewRoot, false);
+ return fromTree(root, mSettings.useMirrorOnThickSlider());
+ }
+
+ private BrightnessSlider fromTree(ViewGroup root, boolean useMirror) {
+ BrightnessSliderView v = root.requireViewById(R.id.brightness_slider);
+ return new BrightnessSlider(root, v, useMirror);
+ }
+
+ /** Get the layout to inflate based on what slider to use */
+ public int getLayout() {
+ return mSettings.useThickSlider()
+ ? R.layout.quick_settings_brightness_dialog_thick
+ : R.layout.quick_settings_brightness_dialog;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
new file mode 100644
index 000000000000..cbf4e88b3241
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
@@ -0,0 +1,206 @@
+/*
+ * 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.settings.brightness;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.FrameLayout;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.systemui.R;
+
+/**
+ * {@code FrameLayout} used to show and manipulate a {@link ToggleSeekBar}.
+ *
+ * It can additionally control a {@link CompoundButton} and display a label. For the class to work,
+ * add children before inflation with the following ids:
+ * <ul>
+ * <li>{@code @id/slider} of type {@link ToggleSeekBar}</li>
+ * <li>{@code @id/toggle} of type {@link CompoundButton} (optional)</li>
+ * <li>{@code @id/label} of type {@link TextView} (optional)</li>
+ * </ul>
+ */
+public class BrightnessSliderView extends FrameLayout {
+
+ @Nullable
+ private CompoundButton mToggle;
+ @NonNull
+ private ToggleSeekBar mSlider;
+ @Nullable
+ private TextView mLabel;
+ private final CharSequence mText;
+ private DispatchTouchEventListener mListener;
+
+ public BrightnessSliderView(Context context) {
+ this(context, null);
+ }
+
+ public BrightnessSliderView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public BrightnessSliderView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.ToggleSliderView, defStyle, 0);
+ mText = a.getString(R.styleable.ToggleSliderView_text);
+
+ a.recycle();
+ }
+
+ // Inflated from quick_settings_brightness_dialog or quick_settings_brightness_dialog_thick
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mToggle = findViewById(R.id.toggle);
+
+ mSlider = requireViewById(R.id.slider);
+
+ mLabel = findViewById(R.id.label);
+ if (mLabel != null) {
+ mLabel.setText(mText);
+ }
+ mSlider.setAccessibilityLabel(getContentDescription().toString());
+ }
+
+ /**
+ * Attaches a listener to relay touch events.
+ * @param listener use {@code null} to remove listener
+ */
+ public void setOnDispatchTouchEventListener(
+ DispatchTouchEventListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (mListener != null) {
+ mListener.onDispatchTouchEvent(ev);
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+
+ /**
+ * Attaches a listener to the {@link ToggleSeekBar} in the view so changes can be observed
+ * @param seekListener use {@code null} to remove listener
+ */
+ public void setOnSeekBarChangeListener(OnSeekBarChangeListener seekListener) {
+ mSlider.setOnSeekBarChangeListener(seekListener);
+ }
+
+ /**
+ * Attaches a listener to the {@link CompoundButton} in the view (if present) so changes to its
+ * state can be observed
+ * @param checkListener use {@code null} to remove listener
+ */
+ public void setOnCheckedChangeListener(OnCheckedChangeListener checkListener) {
+ if (mToggle != null) {
+ mToggle.setOnCheckedChangeListener(checkListener);
+ }
+ }
+
+ /**
+ * Enforces admin rules for toggling auto-brightness and changing value of brightness
+ * @param admin
+ * @see ToggleSeekBar#setEnforcedAdmin
+ */
+ public void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
+ if (mToggle != null) {
+ mToggle.setEnabled(admin == null);
+ }
+ mSlider.setEnabled(admin == null);
+ mSlider.setEnforcedAdmin(admin);
+ }
+
+ /**
+ * Enables or disables the slider
+ * @param enable
+ */
+ public void enableSlider(boolean enable) {
+ mSlider.setEnabled(enable);
+ }
+
+ /**
+ * Sets the state of the {@link CompoundButton} if present
+ * @param checked
+ */
+ public void setChecked(boolean checked) {
+ if (mToggle != null) {
+ mToggle.setChecked(checked);
+ }
+ }
+
+ /**
+ * @return the state of the {@link CompoundButton} if present, or {@code true} if not.
+ */
+ public boolean isChecked() {
+ if (mToggle != null) {
+ return mToggle.isChecked();
+ }
+ return true;
+ }
+
+ /**
+ * @return the maximum value of the {@link ToggleSeekBar}.
+ */
+ public int getMax() {
+ return mSlider.getMax();
+ }
+
+ /**
+ * Sets the maximum value of the {@link ToggleSeekBar}.
+ * @param max
+ */
+ public void setMax(int max) {
+ mSlider.setMax(max);
+ }
+
+ /**
+ * Sets the current value of the {@link ToggleSeekBar}.
+ * @param value
+ */
+ public void setValue(int value) {
+ mSlider.setProgress(value);
+ }
+
+ /**
+ * @return the current value of the {@link ToggleSeekBar}
+ */
+ public int getValue() {
+ return mSlider.getProgress();
+ }
+
+ /**
+ * Interface to attach a listener for {@link View#dispatchTouchEvent}.
+ */
+ @FunctionalInterface
+ interface DispatchTouchEventListener {
+ boolean onDispatchTouchEvent(MotionEvent ev);
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java
index 8ed4c75e8673..a5a0ae70045e 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSeekBar.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSeekBar.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 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.settings;
+package com.android.systemui.settings.brightness;
import android.content.Context;
import android.content.Intent;
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
index 135f89d3f343..71e4818c605a 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 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.
@@ -11,22 +11,31 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
-package com.android.systemui.settings;
+package com.android.systemui.settings.brightness;
+
+import android.view.MotionEvent;
+
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.systemui.statusbar.policy.BrightnessMirrorController;
public interface ToggleSlider {
interface Listener {
- void onInit(ToggleSlider control);
- void onChanged(ToggleSlider slider, boolean tracking, boolean automatic, int value,
+ void onChanged(boolean tracking, boolean automatic, int value,
boolean stopTracking);
}
+ void setEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin);
+ void setMirrorControllerAndMirror(BrightnessMirrorController c);
+ boolean mirrorTouchEvent(MotionEvent ev);
+
void setOnChangedListener(Listener l);
default void setChecked(boolean checked) {}
default boolean isChecked() { return false; }
void setMax(int max);
+ int getMax();
void setValue(int value);
int getValue();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
new file mode 100644
index 000000000000..86377fb014ae
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -0,0 +1,207 @@
+package com.android.systemui.statusbar
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.graphics.PointF
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
+import android.graphics.PorterDuffXfermode
+import android.graphics.RadialGradient
+import android.graphics.Shader
+import android.os.SystemProperties
+import android.util.AttributeSet
+import android.view.View
+import com.android.systemui.Interpolators
+
+val enableLightReveal =
+ SystemProperties.getBoolean("persist.sysui.show_new_screen_on_transitions", false)
+
+/**
+ * Provides methods to modify the various properties of a [LightRevealScrim] to reveal between 0% to
+ * 100% of the view(s) underneath the scrim.
+ */
+interface LightRevealEffect {
+ fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim)
+
+ companion object {
+
+ /**
+ * Returns the percent that the given value is past the threshold value. For example, 0.9 is
+ * 50% of the way past 0.8.
+ */
+ fun getPercentPastThreshold(value: Float, threshold: Float): Float {
+ return (value - threshold).coerceAtLeast(0f) * (1f / (1f - threshold))
+ }
+ }
+}
+
+/**
+ * Light reveal effect that shows light entering the phone from the bottom of the screen. The light
+ * enters from the bottom-middle as a narrow oval, and moves upward, eventually widening to fill the
+ * screen.
+ */
+object LiftReveal : LightRevealEffect {
+
+ /** Widen the oval of light after 35%, so it will eventually fill the screen. */
+ private const val WIDEN_OVAL_THRESHOLD = 0.35f
+
+ /** After 85%, fade out the black color at the end of the gradient. */
+ private const val FADE_END_COLOR_OUT_THRESHOLD = 0.85f
+
+ /** The initial width of the light oval, in percent of scrim width. */
+ private const val OVAL_INITIAL_WIDTH_PERCENT = 0.5f
+
+ /** The initial top value of the light oval, in percent of scrim height. */
+ private const val OVAL_INITIAL_TOP_PERCENT = 1.05f
+
+ /** The initial bottom value of the light oval, in percent of scrim height. */
+ private const val OVAL_INITIAL_BOTTOM_PERCENT = 1.2f
+
+ /** Interpolator to use for the reveal amount. */
+ private val INTERPOLATOR = Interpolators.FAST_OUT_SLOW_IN_REVERSE
+
+ override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
+ val interpolatedAmount = INTERPOLATOR.getInterpolation(amount)
+ val ovalWidthIncreaseAmount =
+ LightRevealEffect.getPercentPastThreshold(interpolatedAmount, WIDEN_OVAL_THRESHOLD)
+
+ val initialWidthMultiplier = (1f - OVAL_INITIAL_WIDTH_PERCENT) / 2f
+
+ with(scrim) {
+ revealGradientEndColorAlpha = 1f - LightRevealEffect.getPercentPastThreshold(
+ amount, FADE_END_COLOR_OUT_THRESHOLD)
+ setRevealGradientBounds(
+ scrim.width * initialWidthMultiplier +
+ -scrim.width * ovalWidthIncreaseAmount,
+ scrim.height * OVAL_INITIAL_TOP_PERCENT -
+ scrim.height * interpolatedAmount,
+ scrim.width * (1f - initialWidthMultiplier) +
+ scrim.width * ovalWidthIncreaseAmount,
+ scrim.height * OVAL_INITIAL_BOTTOM_PERCENT +
+ scrim.height * interpolatedAmount)
+ }
+ }
+}
+
+/**
+ * Scrim view that partially reveals the content underneath it using a [RadialGradient] with a
+ * transparent center. The center position, size, and stops of the gradient can be manipulated to
+ * reveal views below the scrim as if they are being 'lit up'.
+ */
+class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
+
+ /**
+ * How much of the underlying views are revealed, in percent. 0 means they will be completely
+ * obscured and 1 means they'll be fully visible.
+ */
+ var revealAmount: Float = 0f
+ set(value) {
+ if (field != value) {
+ field = value
+
+ revealEffect.setRevealAmountOnScrim(value, this)
+ invalidate()
+ }
+ }
+
+ /**
+ * The [LightRevealEffect] used to manipulate the radial gradient whenever [revealAmount]
+ * changes.
+ */
+ var revealEffect: LightRevealEffect = LiftReveal
+ set(value) {
+ if (field != value) {
+ field = value
+
+ revealEffect.setRevealAmountOnScrim(revealAmount, this)
+ invalidate()
+ }
+ }
+
+ var revealGradientCenter = PointF()
+ var revealGradientWidth: Float = 0f
+ var revealGradientHeight: Float = 0f
+
+ var revealGradientEndColor: Int = Color.BLACK
+ set(value) {
+ if (field != value) {
+ field = value
+ setPaintColorFilter()
+ }
+ }
+
+ var revealGradientEndColorAlpha = 0f
+ set(value) {
+ if (field != value) {
+ field = value
+ setPaintColorFilter()
+ }
+ }
+
+ /**
+ * Paint used to draw a transparent-to-white radial gradient. This will be scaled and translated
+ * via local matrix in [onDraw] so we never need to construct a new shader.
+ */
+ private val gradientPaint = Paint().apply {
+ shader = RadialGradient(
+ 0f, 0f, 1f,
+ intArrayOf(Color.TRANSPARENT, Color.WHITE), floatArrayOf(0f, 1f),
+ Shader.TileMode.CLAMP)
+
+ // SRC_OVER ensures that we draw the semitransparent pixels over other views in the same
+ // window, rather than outright replacing them.
+ xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)
+ }
+
+ /**
+ * Matrix applied to [gradientPaint]'s RadialGradient shader to move the gradient to
+ * [revealGradientCenter] and set its size to [revealGradientWidth]/[revealGradientHeight],
+ * without needing to construct a new shader each time those properties change.
+ */
+ private val shaderGradientMatrix = Matrix()
+
+ /**
+ * Sets bounds for the transparent oval gradient that reveals the views below the scrim. This is
+ * simply a helper method that sets [revealGradientCenter], [revealGradientWidth], and
+ * [revealGradientHeight] for you.
+ *
+ * This method does not call [invalidate] - you should do so once you're done changing
+ * properties.
+ */
+ public fun setRevealGradientBounds(left: Float, top: Float, right: Float, bottom: Float) {
+ revealGradientWidth = right - left
+ revealGradientHeight = bottom - top
+
+ revealGradientCenter.x = left + (revealGradientWidth / 2f)
+ revealGradientCenter.y = top + (revealGradientHeight / 2f)
+ }
+
+ override fun onDraw(canvas: Canvas?) {
+ if (canvas == null || revealGradientWidth <= 0 || revealGradientHeight <= 0) {
+ return
+ }
+
+ with(shaderGradientMatrix) {
+ setScale(revealGradientWidth, revealGradientHeight, 0f, 0f)
+ postTranslate(revealGradientCenter.x, revealGradientCenter.y)
+
+ gradientPaint.shader.setLocalMatrix(this)
+ }
+
+ // Draw the gradient over the screen, then multiply the end color by it.
+ canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), gradientPaint)
+ }
+
+ private fun setPaintColorFilter() {
+ gradientPaint.colorFilter = PorterDuffColorFilter(
+ Color.argb(
+ (revealGradientEndColorAlpha * 255).toInt(),
+ Color.red(revealGradientEndColor),
+ Color.green(revealGradientEndColor),
+ Color.blue(revealGradientEndColor)),
+ PorterDuff.Mode.MULTIPLY)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index f9d2d31dbfd4..7f31fddbfb6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -22,6 +22,7 @@ import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
+import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
@@ -159,6 +160,19 @@ public class NotificationListener extends NotificationListenerWithPlugins {
}
@Override
+ public void onNotificationChannelModified(
+ String pkgName, UserHandle user, NotificationChannel channel, int modificationType) {
+ if (DEBUG) Log.d(TAG, "onNotificationChannelModified");
+ if (!onPluginNotificationChannelModified(pkgName, user, channel, modificationType)) {
+ mMainHandler.post(() -> {
+ for (NotificationHandler handler : mNotificationHandlers) {
+ handler.onNotificationChannelModified(pkgName, user, channel, modificationType);
+ }
+ });
+ }
+ }
+
+ @Override
public void onSilentStatusBarIconsVisibilityChanged(boolean hideSilentStatusIcons) {
for (NotificationSettingsListener listener : mSettingsListeners) {
listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
@@ -229,6 +243,14 @@ public class NotificationListener extends NotificationListenerWithPlugins {
void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap, int reason);
void onNotificationRankingUpdate(RankingMap rankingMap);
+ /** Called after a notification channel is modified. */
+ default void onNotificationChannelModified(
+ String pkgName,
+ UserHandle user,
+ NotificationChannel channel,
+ int modificationType) {
+ }
+
/**
* Called after the listener has connected to NoMan and posted any current notifications.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index a92b9e4818b4..9bd34ad1937f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -26,7 +26,6 @@ import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.R;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.dagger.StatusBarModule;
@@ -43,6 +42,7 @@ import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectio
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.util.Assert;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index cee9c70f53eb..efd0519d6608 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -21,7 +21,6 @@ import android.content.Context;
import android.os.Handler;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.MediaDataManager;
@@ -62,6 +61,7 @@ import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
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 382715a3fb77..45e8098e71d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_APP_START;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -32,6 +34,7 @@ import android.view.SyncRtSurfaceTransactionApplier;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.View;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -226,10 +229,27 @@ public class ActivityLaunchAnimator {
}
});
anim.addListener(new AnimatorListenerAdapter() {
+ private boolean mWasCancelled;
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ InteractionJankMonitor.getInstance().begin(CUJ_NOTIFICATION_APP_START);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
setExpandAnimationRunning(false);
invokeCallback(iRemoteAnimationFinishedCallback);
+ if (!mWasCancelled) {
+ InteractionJankMonitor.getInstance().end(CUJ_NOTIFICATION_APP_START);
+ } else {
+ InteractionJankMonitor.getInstance().cancel(CUJ_NOTIFICATION_APP_START);
+ }
}
});
anim.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
index eee9cc683e2b..967524ce308d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/AnimatableProperty.java
@@ -16,9 +16,7 @@
package com.android.systemui.statusbar.notification;
-import android.graphics.drawable.Drawable;
import android.util.FloatProperty;
-import android.util.Log;
import android.util.Property;
import android.view.View;
@@ -34,9 +32,14 @@ public abstract class AnimatableProperty {
public static final AnimatableProperty X = AnimatableProperty.from(View.X,
R.id.x_animator_tag, R.id.x_animator_tag_start_value, R.id.x_animator_tag_end_value);
+
public static final AnimatableProperty Y = AnimatableProperty.from(View.Y,
R.id.y_animator_tag, R.id.y_animator_tag_start_value, R.id.y_animator_tag_end_value);
+ public static final AnimatableProperty TRANSLATION_X = AnimatableProperty.from(
+ View.TRANSLATION_X, R.id.x_animator_tag, R.id.x_animator_tag_start_value,
+ R.id.x_animator_tag_end_value);
+
/**
* Similar to X, however this doesn't allow for any other modifications other than from this
* property. When using X, it's possible that the view is laid out during the animation,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index 7d8979ca1129..aef01e9bd811 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -22,10 +22,10 @@ import android.util.Log;
import android.view.View;
import com.android.systemui.DejankUtils;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.Optional;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
index 1710daa16735..09ae7eb38a06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
@@ -19,6 +19,8 @@ package com.android.systemui.statusbar.notification.collection.coalescer;
import static java.util.Objects.requireNonNull;
import android.annotation.MainThread;
+import android.app.NotificationChannel;
+import android.os.UserHandle;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
@@ -158,6 +160,15 @@ public class GroupCoalescer implements Dumpable {
public void onNotificationsInitialized() {
mHandler.onNotificationsInitialized();
}
+
+ @Override
+ public void onNotificationChannelModified(
+ String pkgName,
+ UserHandle user,
+ NotificationChannel channel,
+ int modificationType) {
+ mHandler.onNotificationChannelModified(pkgName, user, channel, modificationType);
+ }
};
private void maybeEmitBatch(StatusBarNotification sbn) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index 83a569bd6573..29a030f910a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -26,6 +24,8 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.HashSet;
import java.util.Optional;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
index db49e4476a99..4fde1187477c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
@@ -21,6 +21,7 @@ import android.util.Log;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
@@ -49,6 +50,7 @@ public class NotifPipelineInitializer implements Dumpable {
private final ShadeListBuilder mListBuilder;
private final NotifCoordinators mNotifPluggableCoordinators;
private final NotifInflaterImpl mNotifInflater;
+ private final PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
private final DumpManager mDumpManager;
private final ShadeViewManagerFactory mShadeViewManagerFactory;
private final FeatureFlags mFeatureFlags;
@@ -62,6 +64,7 @@ public class NotifPipelineInitializer implements Dumpable {
ShadeListBuilder listBuilder,
NotifCoordinators notifCoordinators,
NotifInflaterImpl notifInflater,
+ PeopleSpaceWidgetManager peopleSpaceWidgetManager,
DumpManager dumpManager,
ShadeViewManagerFactory shadeViewManagerFactory,
FeatureFlags featureFlags) {
@@ -72,6 +75,7 @@ public class NotifPipelineInitializer implements Dumpable {
mNotifPluggableCoordinators = notifCoordinators;
mDumpManager = dumpManager;
mNotifInflater = notifInflater;
+ mPeopleSpaceWidgetManager = peopleSpaceWidgetManager;
mShadeViewManagerFactory = shadeViewManagerFactory;
mFeatureFlags = featureFlags;
}
@@ -99,6 +103,7 @@ public class NotifPipelineInitializer implements Dumpable {
mListBuilder.attach(mNotifCollection);
mNotifCollection.attach(mGroupCoalescer);
mGroupCoalescer.attach(notificationService);
+ mPeopleSpaceWidgetManager.attach(notificationService);
Log.d(TAG, "Notif pipeline initialized");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
index 36adfac21bc3..3db544011700 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
@@ -22,7 +22,6 @@ import android.util.ArraySet;
import android.util.Log;
import com.android.systemui.Dumpable;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
@@ -34,6 +33,7 @@ import com.android.systemui.statusbar.notification.collection.render.GroupMember
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.wm.shell.bubbles.Bubbles;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
index 049b471aa7cb..52b9b0606e81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
@@ -17,13 +17,13 @@
package com.android.systemui.statusbar.notification.init
import android.service.notification.StatusBarNotification
-import com.android.systemui.bubbles.Bubbles
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.StatusBar
+import com.android.wm.shell.bubbles.Bubbles
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.Optional
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 45a5d1044b9a..8f352ad55041 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.init
import android.service.notification.StatusBarNotification
-import com.android.systemui.bubbles.Bubbles
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
import com.android.systemui.statusbar.FeatureFlags
@@ -41,6 +40,7 @@ import com.android.systemui.statusbar.phone.StatusBar
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.RemoteInputUriController
+import com.android.wm.shell.bubbles.Bubbles
import dagger.Lazy
import java.io.FileDescriptor
import java.io.PrintWriter
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
index 7569c1bdbb73..d0e68bf75373 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.init
import android.service.notification.StatusBarNotification
-import com.android.systemui.bubbles.Bubbles
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
import com.android.systemui.statusbar.NotificationListener
import com.android.systemui.statusbar.NotificationPresenter
@@ -25,6 +24,7 @@ import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.StatusBar
+import com.android.wm.shell.bubbles.Bubbles
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.Optional
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 094e8661d262..10273cbbebad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -33,6 +33,7 @@ import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -750,12 +751,16 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
if (!mWasCancelled) {
enableAppearDrawing(false);
onAppearAnimationFinished(isAppearing);
+ InteractionJankMonitor.getInstance().end(getCujType(isAppearing));
+ } else {
+ InteractionJankMonitor.getInstance().cancel(getCujType(isAppearing));
}
}
@Override
public void onAnimationStart(Animator animation) {
mWasCancelled = false;
+ InteractionJankMonitor.getInstance().begin(getCujType(isAppearing));
}
@Override
@@ -766,6 +771,18 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mAppearAnimator.start();
}
+ private int getCujType(boolean isAppearing) {
+ if (mIsHeadsUpAnimation) {
+ return isAppearing
+ ? InteractionJankMonitor.CUJ_NOTIFICATION_HEADS_UP_APPEAR
+ : InteractionJankMonitor.CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR;
+ } else {
+ return isAppearing
+ ? InteractionJankMonitor.CUJ_NOTIFICATION_ADD
+ : InteractionJankMonitor.CUJ_NOTIFICATION_REMOVE;
+ }
+ }
+
protected void onAppearAnimationFinished(boolean wasAppearing) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 280c525f41cf..2253b2ba26f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -35,6 +35,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Color;
import android.graphics.Path;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
@@ -43,6 +44,7 @@ import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
+import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -327,8 +329,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private boolean mShelfIconVisible;
private boolean mAboveShelf;
private OnUserInteractionCallback mOnUserInteractionCallback;
+ private NotificationGutsManager mNotificationGutsManager;
private boolean mIsLowPriority;
- private boolean mIsColorized;
private boolean mUseIncreasedCollapsedHeight;
private boolean mUseIncreasedHeadsUpHeight;
private float mTranslationWhenRemoved;
@@ -538,7 +540,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
for (NotificationContentView l : mLayouts) {
l.onNotificationUpdated(mEntry);
}
- mIsColorized = mEntry.getSbn().getNotification().isColorized();
mShowingPublicInitialized = false;
updateNotificationColor();
if (mMenuRow != null) {
@@ -1089,6 +1090,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
};
}
+ /** The click listener for the snooze button. */
+ public View.OnClickListener getSnoozeClickListener(MenuItem item) {
+ return v -> {
+ mNotificationGutsManager.openGuts(this, 0, 0, item);
+ };
+ }
+
private void updateClickAndFocus() {
boolean normalChild = !isChildInGroup() || isGroupExpanded();
boolean clickable = mOnClickListener != null && normalChild;
@@ -1155,10 +1163,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
*/
@Nullable
public NotificationMenuRowPlugin createMenu() {
- if (mMenuRow == null) {
+ final boolean removeShelf = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.SHOW_NEW_NOTIF_DISMISS, 0 /* show shelf by default */) == 1;
+ if (mMenuRow == null || removeShelf) {
return null;
}
-
if (mMenuRow.getMenuView() == null) {
mMenuRow.createMenu(this, mEntry.getSbn());
mMenuRow.setAppName(mAppName);
@@ -1555,7 +1564,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
StatusBarStateController statusBarStateController,
PeopleNotificationIdentifier peopleNotificationIdentifier,
OnUserInteractionCallback onUserInteractionCallback,
- Optional<BubblesManager> bubblesManagerOptional) {
+ Optional<BubblesManager> bubblesManagerOptional,
+ NotificationGutsManager gutsManager) {
mEntry = entry;
mAppName = appName;
if (mMenuRow == null) {
@@ -1584,6 +1594,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
mOnUserInteractionCallback = onUserInteractionCallback;
mBubblesManagerOptional = bubblesManagerOptional;
+ mNotificationGutsManager = gutsManager;
cacheIsSystemNotification();
}
@@ -1611,8 +1622,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
R.dimen.notification_max_heads_up_height_increased);
Resources res = getResources();
- mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
- R.dimen.notification_divider_height_increased);
mEnableNonGroupedNotificationExpand =
res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
mShowGroupBackgroundWhenExpanded =
@@ -2831,24 +2840,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
@Override
- public float getIncreasedPaddingAmount() {
- if (mIsSummaryWithChildren) {
- if (isGroupExpanded()) {
- return 1.0f;
- } else if (isUserLocked()) {
- return mChildrenContainer.getIncreasedPaddingAmount();
- }
- } else if (isColorized() && (!mIsLowPriority || isExpanded())) {
- return -1.0f;
- }
- return 0.0f;
- }
-
- private boolean isColorized() {
- return mIsColorized && mBgTint != NO_COLOR;
- }
-
- @Override
protected boolean disallowSingleClick(MotionEvent event) {
if (areGutsExposed()) {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 05b1dba36a7b..cb2af54a25cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -154,7 +154,8 @@ public class ExpandableNotificationRowController implements NodeController {
mStatusBarStateController,
mPeopleNotificationIdentifier,
mOnUserInteractionCallback,
- mBubblesManagerOptional
+ mBubblesManagerOptional,
+ mNotificationGutsManager
);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
index bb78f6168d28..2ff43d002f3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
@@ -239,8 +239,7 @@ public abstract class ExpandableOutlineView extends ExpandableView {
mOutlineRadius = res.getDimension(R.dimen.notification_shadow_radius);
mAlwaysRoundBothCorners = res.getBoolean(R.bool.config_clipNotificationsToOutline);
if (!mAlwaysRoundBothCorners) {
- mOutlineRadius = res.getDimensionPixelSize(
- Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
+ mOutlineRadius = res.getDimensionPixelSize(R.dimen.notification_corner_radius);
}
setClipToOutline(mAlwaysRoundBothCorners);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index ccfd8a329ffd..73e080423d40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -499,15 +499,6 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable {
return super.hasOverlappingRendering() && getActualHeight() <= getHeight();
}
- /**
- * @return an amount between -1 and 1 of increased padding that this child needs. 1 means it
- * needs a full increased padding while -1 means it needs no padding at all. For 0.0f the normal
- * padding is applied.
- */
- public float getIncreasedPaddingAmount() {
- return 0.0f;
- }
-
public boolean mustStayOnScreen() {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 71e1d12b610e..79c300782ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -18,12 +18,14 @@ package com.android.systemui.statusbar.notification.row;
import static android.provider.Settings.Global.NOTIFICATION_BUBBLES;
+import static android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -31,6 +33,7 @@ import android.provider.Settings;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.NotificationHeaderView;
import android.view.View;
@@ -44,6 +47,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.TransformableView;
@@ -458,7 +462,7 @@ public class NotificationContentView extends FrameLayout {
mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child,
mContainingNotification);
if (mContainingNotification != null) {
- applyBubbleAction(mExpandedChild, mContainingNotification.getEntry());
+ applySystemActions(mExpandedChild, mContainingNotification.getEntry());
}
}
@@ -500,7 +504,7 @@ public class NotificationContentView extends FrameLayout {
mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child,
mContainingNotification);
if (mContainingNotification != null) {
- applyBubbleAction(mHeadsUpChild, mContainingNotification.getEntry());
+ applySystemActions(mHeadsUpChild, mContainingNotification.getEntry());
}
}
@@ -1161,8 +1165,8 @@ public class NotificationContentView extends FrameLayout {
mForceSelectNextLayout = true;
mPreviousExpandedRemoteInputIntent = null;
mPreviousHeadsUpRemoteInputIntent = null;
- applyBubbleAction(mExpandedChild, entry);
- applyBubbleAction(mHeadsUpChild, entry);
+ applySystemActions(mExpandedChild, entry);
+ applySystemActions(mHeadsUpChild, entry);
}
private void updateAllSingleLineViews() {
@@ -1340,6 +1344,14 @@ public class NotificationContentView extends FrameLayout {
NOTIFICATION_BUBBLES, 0) == 1;
}
+ /**
+ * Setup icon buttons provided by System UI.
+ */
+ private void applySystemActions(View layout, NotificationEntry entry) {
+ applySnoozeAction(layout);
+ applyBubbleAction(layout, entry);
+ }
+
private void applyBubbleAction(View layout, NotificationEntry entry) {
if (layout == null || mContainingNotification == null || mPeopleIdentifier == null) {
return;
@@ -1359,8 +1371,8 @@ public class NotificationContentView extends FrameLayout {
&& entry.getBubbleMetadata() != null;
if (showButton) {
Drawable d = mContext.getResources().getDrawable(entry.isBubble()
- ? R.drawable.ic_stop_bubble
- : R.drawable.ic_create_bubble);
+ ? R.drawable.bubble_ic_stop_bubble
+ : R.drawable.bubble_ic_create_bubble);
mContainingNotification.updateNotificationColor();
final int tint = mContainingNotification.getNotificationColor();
d.setTint(tint);
@@ -1387,6 +1399,45 @@ public class NotificationContentView extends FrameLayout {
}
}
+ private void applySnoozeAction(View layout) {
+ if (layout == null || mContainingNotification == null) {
+ return;
+ }
+ ImageView snoozeButton = layout.findViewById(com.android.internal.R.id.snooze_button);
+ View actionContainer = layout.findViewById(com.android.internal.R.id.actions_container);
+ LinearLayout actionContainerLayout =
+ layout.findViewById(com.android.internal.R.id.actions_container_layout);
+ if (snoozeButton == null || actionContainer == null || actionContainerLayout == null) {
+ return;
+ }
+ final boolean showSnooze = Settings.Secure.getInt(mContext.getContentResolver(),
+ SHOW_NOTIFICATION_SNOOZE, 0) == 1;
+ if (!showSnooze) {
+ snoozeButton.setVisibility(GONE);
+ return;
+ }
+
+ Resources res = mContext.getResources();
+ Drawable snoozeDrawable = res.getDrawable(R.drawable.ic_snooze);
+ mContainingNotification.updateNotificationColor();
+ snoozeDrawable.setTint(mContainingNotification.getNotificationColor());
+ snoozeButton.setImageDrawable(snoozeDrawable);
+
+ final NotificationSnooze snoozeGuts = (NotificationSnooze) LayoutInflater.from(mContext)
+ .inflate(R.layout.notification_snooze, null, false);
+ final String snoozeDescription = res.getString(
+ R.string.notification_menu_snooze_description);
+ final NotificationMenuRowPlugin.MenuItem snoozeMenuItem =
+ new NotificationMenuRow.NotificationMenuItem(
+ mContext, snoozeDescription, snoozeGuts, R.drawable.ic_snooze);
+ snoozeButton.setContentDescription(
+ mContext.getResources().getString(R.string.notification_menu_snooze_description));
+ snoozeButton.setOnClickListener(
+ mContainingNotification.getSnoozeClickListener(snoozeMenuItem));
+ snoozeButton.setVisibility(VISIBLE);
+ actionContainer.setVisibility(VISIBLE);
+ }
+
private void applySmartReplyView(
SmartRepliesAndActions smartRepliesAndActions,
NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 00bccfc1a323..b04f94ce9c1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1271,13 +1271,6 @@ public class NotificationChildrenContainer extends ViewGroup {
}
}
- public float getIncreasedPaddingAmount() {
- if (showingAsLowPriority()) {
- return 0.0f;
- }
- return getGroupExpandFraction();
- }
-
@VisibleForTesting
public boolean isUserLocked() {
return mUserLocked;
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 2a2a0b14a2d2..fbcfef3964af 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
@@ -198,7 +198,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private int mIntrinsicContentHeight;
private int mCollapsedSize;
private int mPaddingBetweenElements;
- private int mIncreasedPaddingBetweenElements;
private int mMaxTopPadding;
private int mTopPadding;
private int mBottomMargin;
@@ -883,8 +882,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mAmbientState.reload(context);
mPaddingBetweenElements = Math.max(1,
res.getDimensionPixelSize(R.dimen.notification_divider_height));
- mIncreasedPaddingBetweenElements =
- res.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
mMinTopOverScrollToEscape = res.getDimensionPixelSize(
R.dimen.min_top_overscroll_to_qs);
mStatusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height);
@@ -892,15 +889,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mSidePaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
mMinInteractionHeight = res.getDimensionPixelSize(
R.dimen.notification_min_interaction_height);
- mCornerRadius = res.getDimensionPixelSize(
- Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
+ mCornerRadius = res.getDimensionPixelSize(R.dimen.notification_corner_radius);
mHeadsUpInset = mStatusBarHeight + res.getDimensionPixelSize(
R.dimen.heads_up_status_bar_padding);
}
void updateCornerRadius() {
- int newRadius = getResources().getDimensionPixelSize(
- Utils.getThemeAttr(getContext(), android.R.attr.dialogCornerRadius));
+ int newRadius = getResources().getDimensionPixelSize(R.dimen.notification_corner_radius);
if (mCornerRadius != newRadius) {
mCornerRadius = newRadius;
invalidate();
@@ -1101,11 +1096,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
if (mChildrenToAddAnimated.contains(child)) {
- int startingPosition = getPositionInLinearLayout(child);
- float increasedPaddingAmount = child.getIncreasedPaddingAmount();
- int padding = increasedPaddingAmount == 1.0f ? mIncreasedPaddingBetweenElements
- : increasedPaddingAmount == -1.0f ? 0 : mPaddingBetweenElements;
- int childHeight = getIntrinsicHeight(child) + padding;
+ final int startingPosition = getPositionInLinearLayout(child);
+ final int childHeight = getIntrinsicHeight(child) + mPaddingBetweenElements;
if (startingPosition < mOwnScrollY) {
// This child starts off screen, so let's keep it offscreen to keep the
// others visible
@@ -2299,7 +2291,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private void updateContentHeight() {
int height = 0;
float previousPaddingRequest = mPaddingBetweenElements;
- float previousPaddingAmount = 0.0f;
int numShownItems = 0;
boolean finish = false;
int maxDisplayedNotifications = mMaxDisplayedNotifications;
@@ -2318,37 +2309,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
} else {
viewHeight = expandableView.getIntrinsicHeight();
}
- float increasedPaddingAmount = expandableView.getIncreasedPaddingAmount();
- float padding;
- if (increasedPaddingAmount >= 0.0f) {
- padding = (int) NotificationUtils.interpolate(
- previousPaddingRequest,
- mIncreasedPaddingBetweenElements,
- increasedPaddingAmount);
- previousPaddingRequest = (int) NotificationUtils.interpolate(
- mPaddingBetweenElements,
- mIncreasedPaddingBetweenElements,
- increasedPaddingAmount);
- } else {
- int ownPadding = (int) NotificationUtils.interpolate(
- 0,
- mPaddingBetweenElements,
- 1.0f + increasedPaddingAmount);
- if (previousPaddingAmount > 0.0f) {
- padding = (int) NotificationUtils.interpolate(
- ownPadding,
- mIncreasedPaddingBetweenElements,
- previousPaddingAmount);
- } else {
- padding = ownPadding;
- }
- previousPaddingRequest = ownPadding;
- }
if (height != 0) {
- height += padding;
+ height += mPaddingBetweenElements;
}
height += calculateGapHeight(previousView, expandableView, numShownItems);
- previousPaddingAmount = increasedPaddingAmount;
height += viewHeight;
numShownItems++;
previousView = expandableView;
@@ -3056,22 +3020,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
updateOnScrollChange();
} else {
- int startingPosition = getPositionInLinearLayout(removedChild);
- float increasedPaddingAmount = removedChild.getIncreasedPaddingAmount();
- int padding;
- if (increasedPaddingAmount >= 0) {
- padding = (int) NotificationUtils.interpolate(
- mPaddingBetweenElements,
- mIncreasedPaddingBetweenElements,
- increasedPaddingAmount);
- } else {
- padding = (int) NotificationUtils.interpolate(
- 0,
- mPaddingBetweenElements,
- 1.0f + increasedPaddingAmount);
- }
- int childHeight = getIntrinsicHeight(removedChild) + padding;
- int endPosition = startingPosition + childHeight;
+ final int startingPosition = getPositionInLinearLayout(removedChild);
+ final int childHeight = getIntrinsicHeight(removedChild) + mPaddingBetweenElements;
+ final int endPosition = startingPosition + childHeight;
if (endPosition <= mOwnScrollY) {
// This child is fully scrolled of the top, so we have to deduct its height from the
// scrollPosition
@@ -3104,42 +3055,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
requestedView = requestedRow = childInGroup.getNotificationParent();
}
int position = 0;
- float previousPaddingRequest = mPaddingBetweenElements;
- float previousPaddingAmount = 0.0f;
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
boolean notGone = child.getVisibility() != View.GONE;
if (notGone && !child.hasNoContentHeight()) {
- float increasedPaddingAmount = child.getIncreasedPaddingAmount();
- float padding;
- if (increasedPaddingAmount >= 0.0f) {
- padding = (int) NotificationUtils.interpolate(
- previousPaddingRequest,
- mIncreasedPaddingBetweenElements,
- increasedPaddingAmount);
- previousPaddingRequest = (int) NotificationUtils.interpolate(
- mPaddingBetweenElements,
- mIncreasedPaddingBetweenElements,
- increasedPaddingAmount);
- } else {
- int ownPadding = (int) NotificationUtils.interpolate(
- 0,
- mPaddingBetweenElements,
- 1.0f + increasedPaddingAmount);
- if (previousPaddingAmount > 0.0f) {
- padding = (int) NotificationUtils.interpolate(
- ownPadding,
- mIncreasedPaddingBetweenElements,
- previousPaddingAmount);
- } else {
- padding = ownPadding;
- }
- previousPaddingRequest = ownPadding;
- }
if (position != 0) {
- position += padding;
+ position += mPaddingBetweenElements;
}
- previousPaddingAmount = increasedPaddingAmount;
}
if (child == requestedView) {
if (requestedRow != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 7698133e1521..7cee365bc7d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -48,6 +48,7 @@ import android.view.WindowInsets;
import android.widget.FrameLayout;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
@@ -177,6 +178,8 @@ public class NotificationStackScrollLayoutController {
private final NotificationListContainerImpl mNotificationListContainer =
new NotificationListContainerImpl();
+ private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener;
+
@VisibleForTesting
final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
new View.OnAttachStateChangeListener() {
@@ -703,10 +706,11 @@ public class NotificationStackScrollLayoutController {
Settings.Secure.NOTIFICATION_DISMISS_RTL,
Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
- mColorExtractor.addOnColorsChangedListener((colorExtractor, which) -> {
+ mOnColorsChangedListener = (colorExtractor, which) -> {
final boolean useDarkText = mColorExtractor.getNeutralColors().supportsDarkText();
mView.updateDecorViews(useDarkText);
- });
+ };
+ mColorExtractor.addOnColorsChangedListener(mOnColorsChangedListener);
mKeyguardMediaController.setVisibilityChangedListener(visible -> {
mView.setKeyguardMediaControllorVisible(visible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index d7a8202d7a4c..d85baa9f1b93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -51,7 +51,6 @@ public class StackScrollAlgorithm {
private final ViewGroup mHostView;
private int mPaddingBetweenElements;
- private int mIncreasedPaddingBetweenElements;
private int mGapHeight;
private int mCollapsedSize;
@@ -77,8 +76,6 @@ public class StackScrollAlgorithm {
Resources res = context.getResources();
mPaddingBetweenElements = res.getDimensionPixelSize(
R.dimen.notification_divider_height);
- mIncreasedPaddingBetweenElements =
- res.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
mCollapsedSize = res.getDimensionPixelSize(R.dimen.notification_min_height);
mStatusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height);
mClipNotificationScrollToTop = res.getBoolean(R.bool.config_clipNotificationScrollToTop);
@@ -240,17 +237,8 @@ public class StackScrollAlgorithm {
int childCount = hostView.getChildCount();
state.visibleChildren.clear();
state.visibleChildren.ensureCapacity(childCount);
- state.paddingMap.clear();
int notGoneIndex = 0;
ExpandableView lastView = null;
- int firstHiddenIndex = ambientState.isDozing()
- ? (ambientState.hasPulsingNotifications() ? 1 : 0)
- : childCount;
-
- // The goal here is to fill the padding map, by iterating over how much padding each child
- // needs. The map is thereby reused, by first filling it with the padding amount and when
- // iterating over it again, it's filled with the actual resolved value.
-
for (int i = 0; i < childCount; i++) {
if (ANCHOR_SCROLLING) {
if (i == ambientState.getAnchorViewIndex()) {
@@ -262,39 +250,7 @@ public class StackScrollAlgorithm {
if (v == ambientState.getShelf()) {
continue;
}
- if (i >= firstHiddenIndex) {
- // we need normal padding now, to be in sync with what the stack calculates
- lastView = null;
- }
notGoneIndex = updateNotGoneIndex(state, notGoneIndex, v);
- float increasedPadding = v.getIncreasedPaddingAmount();
- if (increasedPadding != 0.0f) {
- state.paddingMap.put(v, increasedPadding);
- if (lastView != null) {
- Float prevValue = state.paddingMap.get(lastView);
- float newValue = getPaddingForValue(increasedPadding);
- if (prevValue != null) {
- float prevPadding = getPaddingForValue(prevValue);
- if (increasedPadding > 0) {
- newValue = NotificationUtils.interpolate(
- prevPadding,
- newValue,
- increasedPadding);
- } else if (prevValue > 0) {
- newValue = NotificationUtils.interpolate(
- newValue,
- prevPadding,
- prevValue);
- }
- }
- state.paddingMap.put(lastView, newValue);
- }
- } else if (lastView != null) {
-
- // Let's now resolve the value to an actual padding
- float newValue = getPaddingForValue(state.paddingMap.get(lastView));
- state.paddingMap.put(lastView, newValue);
- }
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
@@ -310,7 +266,6 @@ public class StackScrollAlgorithm {
}
}
}
- lastView = v;
}
}
ExpandableNotificationRow expandingNotification = ambientState.getExpandingNotification();
@@ -321,22 +276,6 @@ public class StackScrollAlgorithm {
: -1;
}
- private float getPaddingForValue(Float increasedPadding) {
- if (increasedPadding == null) {
- return mPaddingBetweenElements;
- } else if (increasedPadding >= 0.0f) {
- return NotificationUtils.interpolate(
- mPaddingBetweenElements,
- mIncreasedPaddingBetweenElements,
- increasedPadding);
- } else {
- return NotificationUtils.interpolate(
- 0,
- mPaddingBetweenElements,
- 1.0f + increasedPadding);
- }
- }
-
private int updateNotGoneIndex(StackScrollAlgorithmState state, int notGoneIndex,
ExpandableView v) {
ExpandableViewState viewState = v.getViewState();
@@ -413,10 +352,10 @@ public class StackScrollAlgorithm {
currentYPosition += mGapHeight;
}
- int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
int childHeight = getMaxAllowedChildHeight(child);
if (reverse) {
- childViewState.yTranslation = currentYPosition - (childHeight + paddingAfterChild);
+ childViewState.yTranslation = currentYPosition
+ - (childHeight + mPaddingBetweenElements);
if (currentYPosition <= 0) {
childViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
}
@@ -453,7 +392,7 @@ public class StackScrollAlgorithm {
currentYPosition -= mGapHeight;
}
} else {
- currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
+ currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements;
if (currentYPosition <= 0) {
childViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
}
@@ -516,11 +455,6 @@ public class StackScrollAlgorithm {
return needsGapHeight;
}
- protected int getPaddingAfterChild(StackScrollAlgorithmState algorithmState,
- ExpandableView child) {
- return algorithmState.getPaddingAfterChild(child);
- }
-
private void updatePulsingStates(StackScrollAlgorithmState algorithmState,
AmbientState ambientState) {
int childCount = algorithmState.visibleChildren.size();
@@ -780,21 +714,8 @@ public class StackScrollAlgorithm {
*/
public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();
- /**
- * The padding after each child measured in pixels.
- */
- public final HashMap<ExpandableView, Float> paddingMap = new HashMap<>();
private int indexOfExpandingNotification;
- public int getPaddingAfterChild(ExpandableView child) {
- Float padding = paddingMap.get(child);
- if (padding == null) {
- // Should only happen for the last view
- return mPaddingBetweenElements;
- }
- return (int) padding.floatValue();
- }
-
public int getIndexOfExpandingNotification() {
return indexOfExpandingNotification;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 3622f1cd3952..e40c262765ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -53,6 +53,7 @@ public class AutoTileManager implements UserAwareController {
public static final String WORK = "work";
public static final String NIGHT = "night";
public static final String CAST = "cast";
+ public static final String BRIGHTNESS = "reduce_brightness";
static final String SETTING_SEPARATOR = ":";
private UserHandle mCurrentUser;
@@ -124,6 +125,9 @@ public class AutoTileManager implements UserAwareController {
mCastController.addCallback(mCastCallback);
}
+ // TODO(b/170970675): Set a listener/controller and callback for Reduce Bright Colors
+ // state changes. Call into ColorDisplayService to get availability/config status
+
int settingsN = mAutoAddSettingList.size();
for (int i = 0; i < settingsN; i++) {
if (!mAutoTracker.isAdded(mAutoAddSettingList.get(i).mSpec)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 2767b7e1627d..80cb289a3c0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -39,7 +39,6 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.DejankUtils;
-import com.android.systemui.biometrics.AuthController;
import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.FalsingManager;
@@ -70,7 +69,6 @@ public class KeyguardBouncer {
private final DismissCallbackRegistry mDismissCallbackRegistry;
private final Handler mHandler;
private final List<BouncerExpansionCallback> mExpansionCallbacks = new ArrayList<>();
- private final AuthController mAuthController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardSecurityModel mKeyguardSecurityModel;
@@ -104,7 +102,6 @@ public class KeyguardBouncer {
ViewGroup container,
DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
BouncerExpansionCallback expansionCallback,
- AuthController authController,
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardBypassController keyguardBypassController, Handler handler,
@@ -123,8 +120,6 @@ public class KeyguardBouncer {
mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
mKeyguardBypassController = keyguardBypassController;
mExpansionCallbacks.add(expansionCallback);
- mExpansionCallbacks.add(authController);
- mAuthController = authController;
}
public void show(boolean resetSecuritySelection) {
@@ -297,11 +292,6 @@ public class KeyguardBouncer {
mIsScrimmed = false;
mFalsingManager.onBouncerHidden();
mCallback.onBouncerVisiblityChanged(false /* shown */);
- // TODO(b/165257355): `mAuthController.onFullyHidden` should be `dispatchFullyHidden()`
- // But, it is causing the UDFPS icon to disappear after SystemUI restarts. I guess the
- // ExpansionCallback from StatusBarKeyguardViewManager can't handle the call to
- // onFullyHidden after a restart.
- mAuthController.onFullyHidden();
cancelShowRunnable();
if (mKeyguardViewController != null) {
mKeyguardViewController.cancelDismissAction();
@@ -552,7 +542,6 @@ public class KeyguardBouncer {
private final ViewMediatorCallback mCallback;
private final DismissCallbackRegistry mDismissCallbackRegistry;
private final FalsingManager mFalsingManager;
- private final AuthController mAuthController;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardBypassController mKeyguardBypassController;
@@ -563,7 +552,6 @@ public class KeyguardBouncer {
@Inject
public Factory(Context context, ViewMediatorCallback callback,
DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
- AuthController authController,
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardBypassController keyguardBypassController, Handler handler,
@@ -573,7 +561,6 @@ public class KeyguardBouncer {
mCallback = callback;
mDismissCallbackRegistry = dismissCallbackRegistry;
mFalsingManager = falsingManager;
- mAuthController = authController;
mKeyguardStateController = keyguardStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardBypassController = keyguardBypassController;
@@ -586,7 +573,7 @@ public class KeyguardBouncer {
BouncerExpansionCallback expansionCallback) {
return new KeyguardBouncer(mContext, mCallback, container,
mDismissCallbackRegistry, mFalsingManager, expansionCallback,
- mAuthController, mKeyguardStateController, mKeyguardUpdateMonitor,
+ mKeyguardStateController, mKeyguardUpdateMonitor,
mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
mKeyguardBouncerComponentFactory);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index bd228933c8a5..5c225e5a3529 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -257,7 +257,7 @@ public class KeyguardClockPositionAlgorithm {
// TODO(b/12836565) - prototyping only adjustment
if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
// This will keep the clock at the top for AOD
- darkAmount = 0f;
+ return (int) (clockY + burnInPreventionOffsetY() + mEmptyDragAmount);
}
return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mEmptyDragAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 8636cb29811c..5f547b5df671 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -45,7 +45,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -369,8 +369,9 @@ public class KeyguardStatusBarView extends RelativeLayout
mMultiUserAvatar.setImageDrawable(picture);
}
- public void setQSPanel(QSPanel qsp) {
- mMultiUserSwitch.setQsPanel(qsp);
+ /** */
+ public void setQSDetailDisplayer(QSDetailDisplayer detailDisplayer) {
+ mMultiUserSwitch.setQSDetailDisplayer(detailDisplayer);
}
@Override
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 5e883bee13a8..289ff71dcb46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -39,7 +39,6 @@ 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.biometrics.AuthController;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
@@ -77,7 +76,6 @@ public class LockscreenLockIconController {
private final KeyguardStateController mKeyguardStateController;
private final Resources mResources;
private final HeadsUpManagerPhone mHeadsUpManagerPhone;
- private final AuthController mAuthController;
private boolean mKeyguardShowing;
private boolean mKeyguardJustShown;
private boolean mBlockUpdates;
@@ -326,8 +324,7 @@ public class LockscreenLockIconController {
@Nullable DockManager dockManager,
KeyguardStateController keyguardStateController,
@Main Resources resources,
- HeadsUpManagerPhone headsUpManagerPhone,
- AuthController authController) {
+ HeadsUpManagerPhone headsUpManagerPhone) {
mLockscreenGestureLogger = lockscreenGestureLogger;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
@@ -342,7 +339,6 @@ public class LockscreenLockIconController {
mKeyguardStateController = keyguardStateController;
mResources = resources;
mHeadsUpManagerPhone = headsUpManagerPhone;
- mAuthController = authController;
mKeyguardIndicationController.setLockIconController(this);
}
@@ -508,7 +504,7 @@ public class LockscreenLockIconController {
* @return true if the visibility changed
*/
private boolean updateIconVisibility() {
- if (mAuthController.isUdfpsEnrolled()) {
+ if (mKeyguardUpdateMonitor.isUdfpsEnrolled()) {
boolean changed = mLockIcon.getVisibility() == GONE;
mLockIcon.setVisibility(GONE);
return changed;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 67b7e979f62d..480d3f42ae77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -34,7 +34,7 @@ import com.android.systemui.Prefs;
import com.android.systemui.Prefs.Key;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.DetailAdapter;
-import com.android.systemui.qs.QSPanel;
+import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -43,14 +43,13 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
*/
public class MultiUserSwitch extends FrameLayout implements View.OnClickListener {
- protected QSPanel mQsPanel;
+ protected QSDetailDisplayer mQSDetailDisplayer;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private boolean mKeyguardMode;
private UserSwitcherController.BaseUserAdapter mUserListener;
final UserManager mUserManager;
- private final int[] mTmpInt2 = new int[2];
protected UserSwitcherController mUserSwitcherController;
@@ -66,8 +65,9 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
refreshContentDescription();
}
- public void setQsPanel(QSPanel qsPanel) {
- mQsPanel = qsPanel;
+ /** */
+ public void setQSDetailDisplayer(QSDetailDisplayer detailDisplayer) {
+ mQSDetailDisplayer = detailDisplayer;
setUserSwitcherController(Dependency.get(UserSwitcherController.class));
}
@@ -127,16 +127,15 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener
if (mKeyguardUserSwitcher != null) {
mKeyguardUserSwitcher.show(true /* animate */);
}
- } else if (mQsPanel != null && mUserSwitcherController != null) {
+ } else if (mQSDetailDisplayer != null && mUserSwitcherController != null) {
View center = getChildCount() > 0 ? getChildAt(0) : this;
- center.getLocationInWindow(mTmpInt2);
- mTmpInt2[0] += center.getWidth() / 2;
- mTmpInt2[1] += center.getHeight() / 2;
+ int[] tmpInt = new int[2];
+ center.getLocationInWindow(tmpInt);
+ tmpInt[0] += center.getWidth() / 2;
+ tmpInt[1] += center.getHeight() / 2;
- mQsPanel.showDetailAdapter(true,
- getUserDetailAdapter(),
- mTmpInt2);
+ mQSDetailDisplayer.showDetailAdapter(getUserDetailAdapter(), tmpInt[0], tmpInt[1]);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index f2ae3da73f5e..ac91b7050ae9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -19,7 +19,6 @@ import com.android.internal.util.ContrastColorUtil;
import com.android.settingslib.Utils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
@@ -32,10 +31,14 @@ import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList;
import java.util.List;
@@ -175,6 +178,16 @@ public class NotificationIconAreaController implements
updateIconLayoutParams(mContext);
}
+ /**
+ * Update position of the view, with optional animation
+ */
+ public void updatePosition(int x, AnimationProperties props, boolean animate) {
+ if (mAodIcons != null) {
+ PropertyAnimator.setProperty(mAodIcons, AnimatableProperty.TRANSLATION_X, x, props,
+ animate);
+ }
+ }
+
public void setupShelf(NotificationShelfController notificationShelfController) {
mShelfIcons = notificationShelfController.getShelfIcons();
notificationShelfController.setCollapsedIcons(mNotificationIcons);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java
index 9e561d13f347..4651e8446059 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationListenerWithPlugins.java
@@ -14,9 +14,11 @@
package com.android.systemui.statusbar.phone;
+import android.app.NotificationChannel;
import android.content.ComponentName;
import android.content.Context;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
@@ -78,7 +80,7 @@ public class NotificationListenerWithPlugins extends NotificationListenerService
/**
* Called when listener receives a onNotificationPosted.
- * Returns true to indicate this callback should be skipped.
+ * Returns true if there's a plugin determining to skip the default callbacks.
*/
public boolean onPluginNotificationPosted(StatusBarNotification sbn,
final RankingMap rankingMap) {
@@ -92,7 +94,7 @@ public class NotificationListenerWithPlugins extends NotificationListenerService
/**
* Called when listener receives a onNotificationRemoved.
- * Returns true to indicate this callback should be skipped.
+ * Returns true if there's a plugin determining to skip the default callbacks.
*/
public boolean onPluginNotificationRemoved(StatusBarNotification sbn,
final RankingMap rankingMap) {
@@ -104,6 +106,20 @@ public class NotificationListenerWithPlugins extends NotificationListenerService
return false;
}
+ /**
+ * Called when listener receives a onNotificationChannelModified.
+ * Returns true if there's a plugin determining to skip the default callbacks.
+ */
+ public boolean onPluginNotificationChannelModified(
+ String pkgName, UserHandle user, NotificationChannel channel, int modificationType) {
+ for (NotificationListenerController plugin : mPlugins) {
+ if (plugin.onNotificationChannelModified(pkgName, user, channel, modificationType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public RankingMap onPluginRankingUpdate(RankingMap rankingMap) {
return getCurrentRanking();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index e9a7132f4a5c..193c96373f68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -89,7 +89,7 @@ import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.qs.QSFragment;
+import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
@@ -268,6 +268,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final MediaHierarchyManager mMediaHierarchyManager;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
+ private final QSDetailDisplayer mQSDetailDisplayer;
// Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
// If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
private final int mMaxKeyguardNotifications;
@@ -519,7 +520,8 @@ public class NotificationPanelViewController extends PanelViewController {
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
NotificationGroupManagerLegacy groupManager,
NotificationIconAreaController notificationIconAreaController,
- AuthController authController) {
+ AuthController authController,
+ QSDetailDisplayer qsDetailDisplayer) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
@@ -534,6 +536,7 @@ public class NotificationPanelViewController extends PanelViewController {
mGroupManager = groupManager;
mNotificationIconAreaController = notificationIconAreaController;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
+ mQSDetailDisplayer = qsDetailDisplayer;
mView.setWillNotDraw(!DEBUG);
mInjectionInflationController = injectionInflationController;
mFalsingManager = falsingManager;
@@ -606,6 +609,7 @@ public class NotificationPanelViewController extends PanelViewController {
private void onFinishInflate() {
loadDimens();
mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header);
+ mKeyguardStatusBar.setQSDetailDisplayer(mQSDetailDisplayer);
mBigClockContainer = mView.findViewById(R.id.big_clock_container);
updateViewControllers(mView.findViewById(R.id.keyguard_status_view));
mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
@@ -873,7 +877,7 @@ public class NotificationPanelViewController extends PanelViewController {
clockPreferredY, hasCustomClock(),
hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount,
bypassEnabled, getUnlockedStackScrollerPadding(),
- mAuthController.isUdfpsEnrolled());
+ mUpdateMonitor.isUdfpsEnrolled());
mClockPositionAlgorithm.run(mClockPositionResult);
mKeyguardStatusViewController.updatePosition(
mClockPositionResult.clockX, mClockPositionResult.clockY, animateClock);
@@ -914,7 +918,7 @@ public class NotificationPanelViewController extends PanelViewController {
- Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding)
- mKeyguardStatusViewController.getLogoutButtonHeight();
- if (mAuthController.isUdfpsEnrolled()) {
+ if (mUpdateMonitor.isUdfpsEnrolled()) {
availableSpace = mNotificationStackScrollLayoutController.getHeight()
- minPadding - shelfSize
- (mStatusBar.getDisplayHeight() - mAuthController.getUdfpsRegion().top);
@@ -2867,9 +2871,6 @@ public class NotificationPanelViewController extends PanelViewController {
}
});
mNotificationStackScrollLayoutController.setQsContainer((ViewGroup) mQs.getView());
- if (mQs instanceof QSFragment) {
- mKeyguardStatusBar.setQSPanel(((QSFragment) mQs).getQsPanel());
- }
updateQsExpansion();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index a3d3c2bb0af5..3db3ab5a56c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -224,9 +224,6 @@ public class NotificationShadeWindowViewController {
if (!isCancel && mService.shouldIgnoreTouch()) {
return false;
}
- if (isDown && mNotificationPanelViewController.isFullyCollapsed()) {
- mNotificationPanelViewController.startExpandLatencyTracking();
- }
if (isDown) {
setTouchActive(true);
mTouchCancelled = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 7c41bcd09b57..c0a5ffa1474e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -66,6 +66,7 @@ public class PhoneStatusBarView extends PanelBar {
}
};
private DarkReceiver mBattery;
+ private DarkReceiver mClock;
private int mRotationOrientation = -1;
@Nullable
private View mCenterIconSpace;
@@ -99,6 +100,7 @@ public class PhoneStatusBarView extends PanelBar {
@Override
public void onFinishInflate() {
mBattery = findViewById(R.id.battery);
+ mClock = findViewById(R.id.clock);
mCutoutSpace = findViewById(R.id.cutout_space_view);
mCenterIconSpace = findViewById(R.id.centered_icon_area);
@@ -110,6 +112,7 @@ public class PhoneStatusBarView extends PanelBar {
super.onAttachedToWindow();
// Always have Battery meters in the status bar observe the dark/light modes.
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
+ Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mClock);
if (updateOrientationAndCutout()) {
updateLayoutForCutout();
}
@@ -119,6 +122,7 @@ public class PhoneStatusBarView extends PanelBar {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mBattery);
+ Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mClock);
mDisplayCutout = null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
index af2f3e55c9ce..a930a897c2dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
@@ -22,13 +22,13 @@ import android.view.ViewTreeObserver;
import android.view.WindowManager;
import com.android.systemui.assist.AssistManager;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.wm.shell.bubbles.Bubbles;
import java.util.ArrayList;
import java.util.Optional;
@@ -51,7 +51,7 @@ public class ShadeControllerImpl implements ShadeController {
private final int mDisplayId;
protected final Lazy<StatusBar> mStatusBarLazy;
private final Lazy<AssistManager> mAssistManagerLazy;
- private final Optional<Lazy<Bubbles>> mBubblesOptional;
+ private final Optional<Bubbles> mBubblesOptional;
private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
@@ -64,7 +64,7 @@ public class ShadeControllerImpl implements ShadeController {
WindowManager windowManager,
Lazy<StatusBar> statusBarLazy,
Lazy<AssistManager> assistManagerLazy,
- Optional<Lazy<Bubbles>> bubblesOptional
+ Optional<Bubbles> bubblesOptional
) {
mCommandQueue = commandQueue;
mStatusBarStateController = statusBarStateController;
@@ -135,7 +135,7 @@ public class ShadeControllerImpl implements ShadeController {
getStatusBar().getNotificationShadeWindowViewController().cancelExpandHelper();
getStatusBarView().collapsePanel(true /* animate */, delayed, speedUpFactor);
} else if (mBubblesOptional.isPresent()) {
- mBubblesOptional.get().get().collapseStack();
+ mBubblesOptional.get().collapseStack();
}
}
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 a8d41046a1eb..09de57509c2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -35,6 +35,7 @@ import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASL
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
+import static com.android.systemui.statusbar.LightRevealScrimKt.getEnableLightReveal;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
@@ -144,7 +145,6 @@ import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.charging.WirelessChargingAnimation;
import com.android.systemui.classifier.FalsingLog;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -173,6 +173,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.statusbar.AutoHideUiElement;
@@ -182,6 +183,8 @@ import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.LiftReveal;
+import com.android.systemui.statusbar.LightRevealScrim;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -229,6 +232,7 @@ import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.io.FileDescriptor;
@@ -367,6 +371,7 @@ public class StatusBar extends SystemUI implements DemoMode,
DozeServiceHost mDozeServiceHost;
private boolean mWakeUpComingFromTouch;
private PointF mWakeUpTouchLocation;
+ private LightRevealScrim mLightRevealScrim;
private final Object mQueueLock = new Object();
@@ -428,6 +433,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private final NotificationViewHierarchyManager mViewHierarchyManager;
private final KeyguardViewMediator mKeyguardViewMediator;
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+ private final BrightnessSlider.Factory mBrightnessSliderFactory;
// for disabling the status bar
private int mDisabled1 = 0;
@@ -740,7 +746,8 @@ public class StatusBar extends SystemUI implements DemoMode,
DemoModeController demoModeController,
Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
- NotificationIconAreaController notificationIconAreaController) {
+ NotificationIconAreaController notificationIconAreaController,
+ BrightnessSlider.Factory brightnessSliderFactory) {
super(context);
mNotificationsController = notificationsController;
mLightBarController = lightBarController;
@@ -817,6 +824,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mDismissCallbackRegistry = dismissCallbackRegistry;
mDemoModeController = demoModeController;
mNotificationIconAreaController = notificationIconAreaController;
+ mBrightnessSliderFactory = brightnessSliderFactory;
mBubbleExpandListener =
(isExpanding, key) -> {
@@ -1155,6 +1163,13 @@ public class StatusBar extends SystemUI implements DemoMode,
});
mScrimController.attachViews(scrimBehind, scrimInFront, scrimForBubble);
+ mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
+
+ if (getEnableLightReveal()) {
+ mLightRevealScrim.setVisibility(View.VISIBLE);
+ mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
+ }
+
mNotificationPanelViewController.initDependencies(
this,
mNotificationShelfController);
@@ -1194,6 +1209,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationShadeWindowView,
mNotificationPanelViewController,
mNotificationShadeDepthControllerLazy.get(),
+ mBrightnessSliderFactory,
(visible) -> {
mBrightnessMirrorVisible = visible;
updateScrimController();
@@ -3619,6 +3635,13 @@ public class StatusBar extends SystemUI implements DemoMode,
}
@Override
+ public void onDozeAmountChanged(float linear, float eased) {
+ if (getEnableLightReveal()) {
+ mLightRevealScrim.setRevealAmount(1f - linear);
+ }
+ }
+
+ @Override
public void onDozingChanged(boolean isDozing) {
Trace.beginSection("StatusBar#updateDozing");
mDozing = isDozing;
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 9e2e57e7047e..f9dfd7a769a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -117,6 +117,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
@Override
public void onStartingToShow() {
+ updateStates();
updateLockIcon();
}
@@ -164,6 +165,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
protected boolean mLastShowing;
protected boolean mLastOccluded;
private boolean mLastBouncerShowing;
+ private boolean mLastBouncerIsOrWillBeShowing;
private boolean mLastBouncerDismissible;
protected boolean mLastRemoteInputActive;
private boolean mLastDozing;
@@ -811,6 +813,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
boolean showing = mShowing;
boolean occluded = mOccluded;
boolean bouncerShowing = mBouncer.isShowing();
+ boolean bouncerIsOrWillBeShowing = bouncerIsOrWillBeShowing();
boolean bouncerDismissible = !mBouncer.isFullscreenBouncer();
boolean remoteInputActive = mRemoteInputActive;
@@ -839,8 +842,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) {
mKeyguardUpdateManager.onKeyguardVisibilityChanged(showing && !occluded);
}
- if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
- mKeyguardUpdateManager.sendKeyguardBouncerChanged(bouncerShowing);
+ if (bouncerIsOrWillBeShowing != mLastBouncerIsOrWillBeShowing || mFirstUpdate) {
+ mKeyguardUpdateManager.sendKeyguardBouncerChanged(bouncerIsOrWillBeShowing);
}
mFirstUpdate = false;
@@ -848,6 +851,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mLastGlobalActionsVisible = mGlobalActionsVisible;
mLastOccluded = occluded;
mLastBouncerShowing = bouncerShowing;
+ mLastBouncerIsOrWillBeShowing = bouncerIsOrWillBeShowing;
mLastBouncerDismissible = bouncerDismissible;
mLastRemoteInputActive = remoteInputActive;
mLastDozing = mDozing;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index b69da859b3c8..f6631ce1414c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -31,7 +31,6 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.InitController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -44,6 +43,7 @@ import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -98,6 +98,7 @@ import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
@@ -198,7 +199,8 @@ public interface StatusBarPhoneModule {
Lazy<NotificationShadeDepthController> notificationShadeDepthController,
DismissCallbackRegistry dismissCallbackRegistry,
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
- NotificationIconAreaController notificationIconAreaController) {
+ NotificationIconAreaController notificationIconAreaController,
+ BrightnessSlider.Factory brightnessSliderFactory) {
return new StatusBar(
context,
notificationsController,
@@ -276,6 +278,7 @@ public interface StatusBarPhoneModule {
demoModeController,
notificationShadeDepthController,
statusBarTouchableRegionManager,
- notificationIconAreaController);
+ notificationIconAreaController,
+ brightnessSliderFactory);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index a0b03e1c54c2..07d3f0122aa0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -17,13 +17,18 @@
package com.android.systemui.statusbar.policy;
import android.annotation.NonNull;
+import android.content.Context;
import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
import android.util.ArraySet;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.systemui.R;
+import com.android.systemui.settings.brightness.BrightnessSlider;
+import com.android.systemui.settings.brightness.ToggleSlider;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
@@ -42,15 +47,20 @@ public class BrightnessMirrorController
private final NotificationPanelViewController mNotificationPanel;
private final NotificationShadeDepthController mDepthController;
private final ArraySet<BrightnessMirrorListener> mBrightnessMirrorListeners = new ArraySet<>();
+ private final BrightnessSlider.Factory mToggleSliderFactory;
+ private BrightnessSlider mToggleSliderController;
private final int[] mInt2Cache = new int[2];
- private View mBrightnessMirror;
+ private FrameLayout mBrightnessMirror;
public BrightnessMirrorController(NotificationShadeWindowView statusBarWindow,
NotificationPanelViewController notificationPanelViewController,
NotificationShadeDepthController notificationShadeDepthController,
+ BrightnessSlider.Factory factory,
@NonNull Consumer<Boolean> visibilityCallback) {
mStatusBarWindow = statusBarWindow;
+ mToggleSliderFactory = factory;
mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror);
+ mToggleSliderController = setMirrorLayout();
mNotificationPanel = notificationPanelViewController;
mDepthController = notificationShadeDepthController;
mNotificationPanel.setPanelAlphaEndAction(() -> {
@@ -88,8 +98,8 @@ public class BrightnessMirrorController
mBrightnessMirror.setTranslationY(originalY - mirrorY);
}
- public View getMirror() {
- return mBrightnessMirror;
+ public ToggleSlider getToggleSlider() {
+ return mToggleSliderController;
}
public void updateResources() {
@@ -110,11 +120,33 @@ public class BrightnessMirrorController
reinflate();
}
+ private BrightnessSlider setMirrorLayout() {
+ Context context = mBrightnessMirror.getContext();
+ BrightnessSlider controller = mToggleSliderFactory.create(context, mBrightnessMirror);
+ controller.init();
+ Drawable mirrorBackground = context.getDrawable(R.drawable.brightness_mirror_background);
+
+ View rootView = controller.getRootView();
+ rootView.setBackground(mirrorBackground);
+
+ ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) rootView.getLayoutParams();
+ lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ int margin = context.getResources()
+ .getDimensionPixelSize(R.dimen.notification_side_paddings);
+ lp.leftMargin = margin;
+ lp.rightMargin = margin;
+ mBrightnessMirror.addView(rootView, lp);
+
+ return controller;
+ }
+
private void reinflate() {
int index = mStatusBarWindow.indexOfChild(mBrightnessMirror);
mStatusBarWindow.removeView(mBrightnessMirror);
- mBrightnessMirror = LayoutInflater.from(mBrightnessMirror.getContext()).inflate(
- R.layout.brightness_mirror, mStatusBarWindow, false);
+ mBrightnessMirror = (FrameLayout) LayoutInflater.from(mBrightnessMirror.getContext())
+ .inflate(R.layout.brightness_mirror, mStatusBarWindow, false);
+ mToggleSliderController = setMirrorLayout();
mStatusBarWindow.addView(mBrightnessMirror, index);
for (int i = 0; i < mBrightnessMirrorListeners.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index ef35a3c55ab8..fbbf362f19d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import android.annotation.ColorInt;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -35,6 +36,7 @@ import android.text.format.DateFormat;
import android.text.style.CharacterStyle;
import android.text.style.RelativeSizeSpan;
import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.View;
import android.widget.TextView;
@@ -96,7 +98,6 @@ public class Clock extends TextView implements
private static final int AM_PM_STYLE_GONE = 2;
private final int mAmPmStyle;
- private final boolean mShowDark;
private boolean mShowSeconds;
private Handler mSecondsHandler;
@@ -126,7 +127,6 @@ public class Clock extends TextView implements
0, 0);
try {
mAmPmStyle = a.getInt(R.styleable.Clock_amPmStyle, AM_PM_STYLE_GONE);
- mShowDark = a.getBoolean(R.styleable.Clock_showDark, true);
mNonAdaptedColor = getCurrentTextColor();
} finally {
a.recycle();
@@ -196,9 +196,6 @@ public class Clock extends TextView implements
Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
StatusBarIconController.ICON_HIDE_LIST);
mCommandQueue.addCallback(this);
- if (mShowDark) {
- Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this);
- }
mCurrentUserTracker.startTracking();
mCurrentUserId = mCurrentUserTracker.getCurrentUserId();
}
@@ -229,9 +226,6 @@ public class Clock extends TextView implements
mAttached = false;
Dependency.get(TunerService.class).removeTunable(this);
mCommandQueue.removeCallback(this);
- if (mShowDark) {
- Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(this);
- }
mCurrentUserTracker.stopTracking();
}
}
@@ -334,6 +328,13 @@ public class Clock extends TextView implements
}
}
+ // Update text color based when shade scrim changes color.
+ public void onColorsChanged(boolean lightTheme) {
+ final Context context = new ContextThemeWrapper(mContext,
+ lightTheme ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI);
+ setTextColor(Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColor));
+ }
+
@Override
public void onDensityOrFontScaleChanged() {
FontSizeUtils.updateFontSize(this, R.dimen.status_bar_clock_size);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 4552026ced4b..79f09158fc67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -45,7 +45,7 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
-import android.view.OnReceiveContentCallback;
+import android.view.OnReceiveContentListener;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
@@ -74,6 +74,7 @@ import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LightBarController;
import java.util.HashMap;
+import java.util.Map;
import java.util.function.Consumer;
/**
@@ -585,27 +586,32 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
protected void onFinishInflate() {
super.onFinishInflate();
if (mSupportedMimeTypes != null && mSupportedMimeTypes.length > 0) {
- setOnReceiveContentCallback(mSupportedMimeTypes,
- new OnReceiveContentCallback<View>() {
+ setOnReceiveContentListener(mSupportedMimeTypes,
+ new OnReceiveContentListener() {
@Override
- public boolean onReceiveContent(@NonNull View view,
+ @Nullable
+ public Payload onReceiveContent(@NonNull View view,
@NonNull Payload payload) {
- ClipData clip = payload.getClip();
- if (clip.getItemCount() == 0) {
- return false;
- }
- Uri contentUri = clip.getItemAt(0).getUri();
- ClipDescription description = clip.getDescription();
- String mimeType = null;
- if (description.getMimeTypeCount() > 0) {
- mimeType = description.getMimeType(0);
- }
- if (mimeType != null) {
+ Map<Boolean, Payload> split = payload.partition(
+ item -> item.getUri() != null);
+ Payload uriItems = split.get(true);
+ Payload remainingItems = split.get(false);
+ if (uriItems != null) {
+ ClipData clip = uriItems.getClip();
+ ClipDescription description = clip.getDescription();
+ if (clip.getItemCount() > 1
+ || description.getMimeTypeCount() < 1
+ || remainingItems != null) {
+ // TODO(b/172363500): Update to loop over all the items
+ return payload;
+ }
+ Uri contentUri = clip.getItemAt(0).getUri();
+ String mimeType = description.getMimeType(0);
Intent dataIntent = mRemoteInputView
.prepareRemoteInputFromData(mimeType, contentUri);
mRemoteInputView.sendRemoteInput(dataIntent);
}
- return true;
+ return remainingItems;
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt b/packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt
new file mode 100644
index 000000000000..7c6f86aceeb0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+@file:JvmName("VpnStatusObserver")
+
+package com.android.systemui.statusbar.tv
+
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.content.Context
+import com.android.internal.messages.nano.SystemMessageProto
+import com.android.internal.net.VpnConfig
+import com.android.systemui.Dependency
+import com.android.systemui.R
+import com.android.systemui.SystemUI
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.policy.SecurityController
+import javax.inject.Inject
+
+/**
+ * Observes if a vpn connection is active and displays a notification to the user
+ */
+@SysUISingleton
+class VpnStatusObserver @Inject constructor(context: Context) : SystemUI(context),
+ SecurityController.SecurityControllerCallback {
+
+ private var vpnConnected = false
+ private val securityController: SecurityController =
+ Dependency.get(SecurityController::class.java)
+ private val notificationManager = NotificationManager.from(context)
+ private val notificationChannel = createNotificationChannel()
+ private val vpnConnectedNotificationBuilder = createVpnConnectedNotificationBuilder()
+ private val vpnDisconnectedNotification = createVpnDisconnectedNotification()
+
+ private val vpnIconId: Int
+ get() = if (securityController.isVpnBranded) {
+ R.drawable.stat_sys_branded_vpn
+ } else {
+ R.drawable.stat_sys_vpn_ic
+ }
+
+ private val vpnName: String?
+ get() = securityController.primaryVpnName ?: securityController.workProfileVpnName
+
+ override fun start() {
+ // register callback to vpn state changes
+ securityController.addCallback(this)
+ }
+
+ override fun onStateChanged() {
+ securityController.isVpnEnabled.let { newVpnConnected ->
+ if (vpnConnected != newVpnConnected) {
+ if (newVpnConnected) {
+ notifyVpnConnected()
+ } else {
+ notifyVpnDisconnected()
+ }
+ vpnConnected = newVpnConnected
+ }
+ }
+ }
+
+ private fun notifyVpnConnected() = notificationManager.notify(
+ NOTIFICATION_TAG,
+ SystemMessageProto.SystemMessage.NOTE_VPN_STATUS,
+ createVpnConnectedNotification()
+ )
+
+ private fun notifyVpnDisconnected() = notificationManager.run {
+ // remove existing connected notification
+ cancel(NOTIFICATION_TAG, SystemMessageProto.SystemMessage.NOTE_VPN_STATUS)
+ // show the disconnected notification only for a short while
+ notify(NOTIFICATION_TAG, SystemMessageProto.SystemMessage.NOTE_VPN_DISCONNECTED,
+ vpnDisconnectedNotification)
+ }
+
+ private fun createNotificationChannel() =
+ NotificationChannel(
+ NOTIFICATION_CHANNEL_TV_VPN,
+ NOTIFICATION_CHANNEL_TV_VPN,
+ NotificationManager.IMPORTANCE_HIGH
+ ).also {
+ notificationManager.createNotificationChannel(it)
+ }
+
+ private fun createVpnConnectedNotification() =
+ vpnConnectedNotificationBuilder
+ .apply {
+ vpnName?.let {
+ setContentText(
+ mContext.getString(
+ R.string.notification_disclosure_vpn_text, it
+ )
+ )
+ }
+ }
+ .build()
+
+ private fun createVpnConnectedNotificationBuilder() =
+ Notification.Builder(mContext, NOTIFICATION_CHANNEL_TV_VPN)
+ .setSmallIcon(vpnIconId)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .extend(Notification.TvExtender())
+ .setOngoing(true)
+ .setContentTitle(mContext.getString(R.string.notification_vpn_connected))
+ .setContentIntent(VpnConfig.getIntentForStatusPanel(mContext))
+
+ private fun createVpnDisconnectedNotification() =
+ Notification.Builder(mContext, NOTIFICATION_CHANNEL_TV_VPN)
+ .setSmallIcon(vpnIconId)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .extend(Notification.TvExtender())
+ .setTimeoutAfter(VPN_DISCONNECTED_NOTIFICATION_TIMEOUT_MS)
+ .setContentTitle(mContext.getString(R.string.notification_vpn_disconnected))
+ .build()
+
+ companion object {
+ const val NOTIFICATION_CHANNEL_TV_VPN = "VPN Status"
+ val NOTIFICATION_TAG: String = VpnStatusObserver::class.java.simpleName
+
+ private const val TAG = "TvVpnNotification"
+ private const val VPN_DISCONNECTED_NOTIFICATION_TIMEOUT_MS = 5_000L
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index 665cb6307b6a..0aa2a739eb82 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -21,11 +21,18 @@ import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dump.DumpManager;
+
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -34,9 +41,19 @@ import java.util.Set;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
-class ThemeOverlayManager {
+/**
+ * Responsible for orchestrating overlays, based on user preferences and other inputs from
+ * {@link ThemeOverlayController}.
+ */
+@SysUISingleton
+public class ThemeOverlayApplier implements Dumpable {
private static final String TAG = "ThemeOverlayManager";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ @VisibleForTesting
+ static final String MONET_ACCENT_COLOR_PACKAGE = "com.android.theme.accentcolor.color";
+ @VisibleForTesting
+ static final String MONET_SYSTEM_PALETTE_PACKAGE = "com.android.theme.systemcolors.color";
@VisibleForTesting
static final String ANDROID_PACKAGE = "android";
@@ -46,7 +63,11 @@ class ThemeOverlayManager {
static final String SYSUI_PACKAGE = "com.android.systemui";
@VisibleForTesting
- static final String OVERLAY_CATEGORY_COLOR = "android.theme.customization.accent_color";
+ static final String OVERLAY_CATEGORY_ACCENT_COLOR =
+ "android.theme.customization.accent_color";
+ @VisibleForTesting
+ static final String OVERLAY_CATEGORY_SYSTEM_PALETTE =
+ "android.theme.customization.system_palette";
@VisibleForTesting
static final String OVERLAY_CATEGORY_FONT = "android.theme.customization.font";
@VisibleForTesting
@@ -73,24 +94,36 @@ class ThemeOverlayManager {
* starts with launcher and grouped by target package.
*/
static final List<String> THEME_CATEGORIES = Lists.newArrayList(
+ OVERLAY_CATEGORY_SYSTEM_PALETTE,
OVERLAY_CATEGORY_ICON_LAUNCHER,
OVERLAY_CATEGORY_SHAPE,
OVERLAY_CATEGORY_FONT,
- OVERLAY_CATEGORY_COLOR,
+ OVERLAY_CATEGORY_ACCENT_COLOR,
OVERLAY_CATEGORY_ICON_ANDROID,
OVERLAY_CATEGORY_ICON_SYSUI,
OVERLAY_CATEGORY_ICON_SETTINGS,
OVERLAY_CATEGORY_ICON_THEME_PICKER);
- /* Categories that need to applied to the current user as well as the system user. */
+ /* Categories that need to be applied to the current user as well as the system user. */
@VisibleForTesting
static final Set<String> SYSTEM_USER_CATEGORIES = Sets.newHashSet(
- OVERLAY_CATEGORY_COLOR,
+ OVERLAY_CATEGORY_SYSTEM_PALETTE,
+ OVERLAY_CATEGORY_ACCENT_COLOR,
OVERLAY_CATEGORY_FONT,
OVERLAY_CATEGORY_SHAPE,
OVERLAY_CATEGORY_ICON_ANDROID,
OVERLAY_CATEGORY_ICON_SYSUI);
+ /**
+ * List of main colors of Monet themes. These are extracted from overlays installed
+ * on the system.
+ */
+ private final ArrayList<Integer> mMainSystemColors = new ArrayList<>();
+ /**
+ * Same as above, but providing accent colors instead of a system palette.
+ */
+ private final ArrayList<Integer> mAccentColors = new ArrayList<>();
+
/* Allowed overlay categories for each target package. */
private final Map<String, Set<String>> mTargetPackageToCategories = new ArrayMap<>();
/* Target package for each overlay category. */
@@ -100,15 +133,15 @@ class ThemeOverlayManager {
private final String mLauncherPackage;
private final String mThemePickerPackage;
- ThemeOverlayManager(OverlayManager overlayManager, Executor executor,
- String launcherPackage, String themePickerPackage) {
+ public ThemeOverlayApplier(OverlayManager overlayManager, Executor executor,
+ String launcherPackage, String themePickerPackage, DumpManager dumpManager) {
mOverlayManager = overlayManager;
mExecutor = executor;
mLauncherPackage = launcherPackage;
mThemePickerPackage = themePickerPackage;
mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
- OVERLAY_CATEGORY_COLOR, OVERLAY_CATEGORY_FONT,
- OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_ICON_ANDROID));
+ OVERLAY_CATEGORY_SYSTEM_PALETTE, OVERLAY_CATEGORY_ACCENT_COLOR,
+ OVERLAY_CATEGORY_FONT, OVERLAY_CATEGORY_SHAPE, OVERLAY_CATEGORY_ICON_ANDROID));
mTargetPackageToCategories.put(SYSUI_PACKAGE,
Sets.newHashSet(OVERLAY_CATEGORY_ICON_SYSUI));
mTargetPackageToCategories.put(SETTINGS_PACKAGE,
@@ -117,7 +150,7 @@ class ThemeOverlayManager {
Sets.newHashSet(OVERLAY_CATEGORY_ICON_LAUNCHER));
mTargetPackageToCategories.put(mThemePickerPackage,
Sets.newHashSet(OVERLAY_CATEGORY_ICON_THEME_PICKER));
- mCategoryToTargetPackage.put(OVERLAY_CATEGORY_COLOR, ANDROID_PACKAGE);
+ mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR, ANDROID_PACKAGE);
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_FONT, ANDROID_PACKAGE);
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_SHAPE, ANDROID_PACKAGE);
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_ANDROID, ANDROID_PACKAGE);
@@ -125,6 +158,54 @@ class ThemeOverlayManager {
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_SETTINGS, SETTINGS_PACKAGE);
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_LAUNCHER, mLauncherPackage);
mCategoryToTargetPackage.put(OVERLAY_CATEGORY_ICON_THEME_PICKER, mThemePickerPackage);
+
+ collectMonetSystemOverlays();
+ dumpManager.registerDumpable(TAG, this);
+ }
+
+ /**
+ * List of accent colors available as Monet overlays.
+ */
+ List<Integer> getAvailableAccentColors() {
+ return mAccentColors;
+ }
+
+ /**
+ * List of main system colors available as Monet overlays.
+ */
+ List<Integer> getAvailableSystemColors() {
+ return mMainSystemColors;
+ }
+
+ private void collectMonetSystemOverlays() {
+ List<OverlayInfo> androidOverlays = mOverlayManager
+ .getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM);
+ for (OverlayInfo overlayInfo : androidOverlays) {
+ String packageName = overlayInfo.packageName;
+ if (DEBUG) {
+ Log.d(TAG, "Processing overlay " + packageName);
+ }
+ if (OVERLAY_CATEGORY_SYSTEM_PALETTE.equals(overlayInfo.category)
+ && packageName.startsWith(MONET_SYSTEM_PALETTE_PACKAGE)) {
+ try {
+ String color = packageName.replace(MONET_SYSTEM_PALETTE_PACKAGE, "");
+ mMainSystemColors.add(Integer.parseInt(color, 16));
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Invalid package name for overlay " + packageName, e);
+ }
+ } else if (OVERLAY_CATEGORY_ACCENT_COLOR.equals(overlayInfo.category)
+ && packageName.startsWith(MONET_ACCENT_COLOR_PACKAGE)) {
+ try {
+ String color = packageName.replace(MONET_ACCENT_COLOR_PACKAGE, "");
+ mAccentColors.add(Integer.parseInt(color, 16));
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Invalid package name for overlay " + packageName, e);
+ }
+ } else if (DEBUG) {
+ Log.d(TAG, "Unknown overlay: " + packageName + " category: "
+ + overlayInfo.category);
+ }
+ }
}
/**
@@ -184,4 +265,13 @@ class ThemeOverlayManager {
}
});
}
+
+ /**
+ * @inherit
+ */
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("mMainSystemColors=" + mMainSystemColors.size());
+ pw.println("mAccentColors=" + mAccentColors.size());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 132e092b8ada..c4e2b5d47ba8 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -15,16 +15,20 @@
*/
package com.android.systemui.theme;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
+
import android.app.ActivityManager;
+import android.app.WallpaperColors;
+import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.om.OverlayManager;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
+import android.graphics.Color;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
@@ -33,20 +37,32 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
-import com.android.systemui.R;
+import androidx.annotation.NonNull;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
+import com.android.systemui.Dumpable;
import com.android.systemui.SystemUI;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.settings.SecureSettings;
import com.google.android.collect.Sets;
import org.json.JSONException;
import org.json.JSONObject;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -60,49 +76,76 @@ import javax.inject.Inject;
* associated work profiles
*/
@SysUISingleton
-public class ThemeOverlayController extends SystemUI {
+public class ThemeOverlayController extends SystemUI implements Dumpable {
private static final String TAG = "ThemeOverlayController";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ // If lock screen wallpaper colors should also be considered when selecting the theme.
+ // Doing this has performance impact, given that overlays would need to be swapped when
+ // the device unlocks.
+ @VisibleForTesting
+ static final boolean USE_LOCK_SCREEN_WALLPAPER = false;
- private ThemeOverlayManager mThemeManager;
- private UserManager mUserManager;
- private BroadcastDispatcher mBroadcastDispatcher;
+ private final ThemeOverlayApplier mThemeManager;
+ private final UserManager mUserManager;
+ private final BroadcastDispatcher mBroadcastDispatcher;
+ private final Executor mBgExecutor;
+ private final SecureSettings mSecureSettings;
+ private final Executor mMainExecutor;
private final Handler mBgHandler;
+ private final WallpaperManager mWallpaperManager;
+ private final KeyguardStateController mKeyguardStateController;
+ private WallpaperColors mLockColors;
+ private WallpaperColors mSystemColors;
+ // Color extracted from wallpaper, NOT the color used on the overlay
+ private int mMainWallpaperColor = Color.TRANSPARENT;
+ // Color extracted from wallpaper, NOT the color used on the overlay
+ private int mWallpaperAccentColor = Color.TRANSPARENT;
+ // Main system color that maps to an overlay color
+ private int mSystemOverlayColor = Color.TRANSPARENT;
+ // Accent color that maps to an overlay color
+ private int mAccentOverlayColor = Color.TRANSPARENT;
@Inject
public ThemeOverlayController(Context context, BroadcastDispatcher broadcastDispatcher,
- @Background Handler bgHandler) {
+ @Background Handler bgHandler, @Main Executor mainExecutor,
+ @Background Executor bgExecutor, ThemeOverlayApplier themeOverlayApplier,
+ SecureSettings secureSettings, WallpaperManager wallpaperManager,
+ UserManager userManager, KeyguardStateController keyguardStateController,
+ DumpManager dumpManager) {
super(context);
+
mBroadcastDispatcher = broadcastDispatcher;
+ mUserManager = userManager;
+ mBgExecutor = bgExecutor;
+ mMainExecutor = mainExecutor;
mBgHandler = bgHandler;
+ mThemeManager = themeOverlayApplier;
+ mSecureSettings = secureSettings;
+ mWallpaperManager = wallpaperManager;
+ mKeyguardStateController = keyguardStateController;
+ dumpManager.registerDumpable(TAG, this);
}
@Override
public void start() {
if (DEBUG) Log.d(TAG, "Start");
- mUserManager = mContext.getSystemService(UserManager.class);
- mThemeManager = new ThemeOverlayManager(
- mContext.getSystemService(OverlayManager.class),
- AsyncTask.THREAD_POOL_EXECUTOR,
- mContext.getString(R.string.launcher_overlayable_package),
- mContext.getString(R.string.themepicker_overlayable_package));
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
- mBroadcastDispatcher.registerReceiverWithHandler(new BroadcastReceiver() {
+ mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
updateThemeOverlays();
}
- }, filter, mBgHandler, UserHandle.ALL);
- mContext.getContentResolver().registerContentObserver(
+ }, filter, mBgExecutor, UserHandle.ALL);
+ mSecureSettings.registerContentObserverForUser(
Settings.Secure.getUriFor(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES),
false,
new ContentObserver(mBgHandler) {
-
@Override
- public void onChange(boolean selfChange, Collection<Uri> uris, int flags,
+ public void onChange(boolean selfChange, Collection<Uri> collection, int flags,
int userId) {
if (DEBUG) Log.d(TAG, "Overlay changed for user: " + userId);
if (ActivityManager.getCurrentUser() == userId) {
@@ -111,20 +154,147 @@ public class ThemeOverlayController extends SystemUI {
}
},
UserHandle.USER_ALL);
+
+ // Upon boot, make sure we have the most up to date colors
+ mBgExecutor.execute(() -> {
+ WallpaperColors lockColors = mWallpaperManager.getWallpaperColors(
+ WallpaperManager.FLAG_LOCK);
+ WallpaperColors systemColor = mWallpaperManager.getWallpaperColors(
+ WallpaperManager.FLAG_SYSTEM);
+ mMainExecutor.execute(() -> {
+ if (USE_LOCK_SCREEN_WALLPAPER) {
+ mLockColors = lockColors;
+ }
+ mSystemColors = systemColor;
+ reevaluateSystemTheme();
+ });
+ });
+ if (USE_LOCK_SCREEN_WALLPAPER) {
+ mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ if (mLockColors == null) {
+ return;
+ }
+ // It's possible that the user has a lock screen wallpaper. On this case we'll
+ // end up with different colors after unlocking.
+ reevaluateSystemTheme();
+ }
+ });
+ }
+ mWallpaperManager.addOnColorsChangedListener((wallpaperColors, which) -> {
+ if (USE_LOCK_SCREEN_WALLPAPER && (which & WallpaperManager.FLAG_LOCK) != 0) {
+ mLockColors = wallpaperColors;
+ if (DEBUG) {
+ Log.d(TAG, "got new lock colors: " + wallpaperColors + " where: " + which);
+ }
+ }
+ if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
+ mSystemColors = wallpaperColors;
+ if (DEBUG) {
+ Log.d(TAG, "got new lock colors: " + wallpaperColors + " where: " + which);
+ }
+ }
+ reevaluateSystemTheme();
+ }, null, UserHandle.USER_ALL);
+ }
+
+ private void reevaluateSystemTheme() {
+ if (mLockColors == null && mSystemColors == null) {
+ Log.w(TAG, "Cannot update theme, colors are null");
+ return;
+ }
+ WallpaperColors currentColor =
+ mKeyguardStateController.isShowing() && mLockColors != null
+ ? mLockColors : mSystemColors;
+ int mainColor = currentColor.getPrimaryColor().toArgb();
+
+ //TODO(b/172860591) implement more complex logic for picking accent color.
+ //For now, picking the secondary should be enough.
+ Color accentCandidate = currentColor.getSecondaryColor();
+ if (accentCandidate == null) {
+ accentCandidate = currentColor.getTertiaryColor();
+ }
+ if (accentCandidate == null) {
+ accentCandidate = currentColor.getPrimaryColor();
+ }
+
+ if (mMainWallpaperColor == mainColor && mWallpaperAccentColor == accentCandidate.toArgb()) {
+ return;
+ }
+
+ mMainWallpaperColor = mainColor;
+ mWallpaperAccentColor = accentCandidate.toArgb();
+
+ // Let's compare these colors to our finite set of overlays, and then pick an overlay.
+ List<Integer> systemColors = mThemeManager.getAvailableSystemColors();
+ List<Integer> accentColors = mThemeManager.getAvailableAccentColors();
+
+ if (systemColors.size() == 0 || accentColors.size() == 0) {
+ if (DEBUG) {
+ Log.d(TAG, "Cannot apply system theme, palettes are unavailable");
+ }
+ return;
+ }
+
+ mSystemOverlayColor = getClosest(systemColors, mMainWallpaperColor);
+ mAccentOverlayColor = getClosest(accentColors, mWallpaperAccentColor);
+
+ updateThemeOverlays();
+ }
+
+ /**
+ * Given a color and a list of candidates, return the candidate that's the most similar to the
+ * given color.
+ */
+ private static int getClosest(List<Integer> candidates, int color) {
+ float[] hslMain = new float[3];
+ float[] hslCandidate = new float[3];
+
+ ColorUtils.RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), hslMain);
+ hslMain[0] /= 360f;
+
+ float minDistance = Float.MAX_VALUE;
+ int closestColor = Color.TRANSPARENT;
+ for (int candidate: candidates) {
+ ColorUtils.RGBToHSL(Color.red(candidate), Color.green(candidate), Color.blue(candidate),
+ hslCandidate);
+ hslCandidate[0] /= 360f;
+
+ float sqDistance = squared(hslCandidate[0] - hslMain[0])
+ + squared(hslCandidate[1] - hslMain[1])
+ + squared(hslCandidate[2] - hslMain[2]);
+ if (sqDistance < minDistance) {
+ minDistance = sqDistance;
+ closestColor = candidate;
+ }
+ }
+ return closestColor;
+ }
+
+ private static float squared(float f) {
+ return f * f;
}
private void updateThemeOverlays() {
final int currentUser = ActivityManager.getCurrentUser();
- final String overlayPackageJson = Settings.Secure.getStringForUser(
- mContext.getContentResolver(), Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
+ final String overlayPackageJson = mSecureSettings.getStringForUser(
+ Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
currentUser);
if (DEBUG) Log.d(TAG, "updateThemeOverlays: " + overlayPackageJson);
+ boolean hasSystemPalette = false;
+ boolean hasAccentColor = false;
final Map<String, String> categoryToPackage = new ArrayMap<>();
if (!TextUtils.isEmpty(overlayPackageJson)) {
try {
JSONObject object = new JSONObject(overlayPackageJson);
- for (String category : ThemeOverlayManager.THEME_CATEGORIES) {
+ for (String category : ThemeOverlayApplier.THEME_CATEGORIES) {
if (object.has(category)) {
+ if (category.equals(OVERLAY_CATEGORY_ACCENT_COLOR)) {
+ hasAccentColor = true;
+ } else if (category.equals(OVERLAY_CATEGORY_SYSTEM_PALETTE)) {
+ hasSystemPalette = true;
+ }
categoryToPackage.put(category, object.getString(category));
}
}
@@ -132,6 +302,20 @@ public class ThemeOverlayController extends SystemUI {
Log.i(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e);
}
}
+
+ // Let's apply the system palette, but only if it was not overridden by the style picker.
+ if (!hasSystemPalette && mSystemOverlayColor != Color.TRANSPARENT) {
+ categoryToPackage.put(OVERLAY_CATEGORY_SYSTEM_PALETTE,
+ ThemeOverlayApplier.MONET_SYSTEM_PALETTE_PACKAGE
+ + Integer.toHexString(mSystemOverlayColor).toUpperCase());
+ }
+ // Same for the accent color
+ if (!hasAccentColor && mAccentOverlayColor != Color.TRANSPARENT) {
+ categoryToPackage.put(OVERLAY_CATEGORY_ACCENT_COLOR,
+ ThemeOverlayApplier.MONET_ACCENT_COLOR_PACKAGE
+ + Integer.toHexString(mAccentOverlayColor).toUpperCase());
+ }
+
Set<UserHandle> userHandles = Sets.newHashSet(UserHandle.of(currentUser));
for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) {
if (userInfo.isManagedProfile()) {
@@ -140,4 +324,14 @@ public class ThemeOverlayController extends SystemUI {
}
mThemeManager.applyCurrentUserOverlays(categoryToPackage, userHandles);
}
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("mLockColors=" + mLockColors);
+ pw.println("mSystemColors=" + mSystemColors);
+ pw.println("mMainWallpaperColor=" + Integer.toHexString(mMainWallpaperColor));
+ pw.println("mWallpaperAccentColor=" + Integer.toHexString(mWallpaperAccentColor));
+ pw.println("mSystemOverlayColor=" + Integer.toHexString(mSystemOverlayColor));
+ pw.println("mAccentOverlayColor=" + Integer.toHexString(mAccentOverlayColor));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index e79d432b3b15..4b4e1df21bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -26,7 +26,6 @@ import android.view.View;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QuickQSPanel;
-import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import java.lang.reflect.InvocationTargetException;
@@ -104,11 +103,6 @@ public class InjectionInflationController {
* Creates the QuickQSPanel.
*/
QuickQSPanel createQuickQSPanel();
-
- /**
- * Creates the QSCustomizer.
- */
- QSCustomizer createQSCustomizer();
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
index 880d09abeb60..0dd5788105b7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
@@ -76,12 +76,10 @@ public abstract class ViewController<T extends View> {
onInit();
mInited = true;
- if (mView != null) {
- if (mView.isAttachedToWindow()) {
- mOnAttachStateListener.onViewAttachedToWindow(mView);
- }
- mView.addOnAttachStateChangeListener(mOnAttachStateListener);
+ if (isAttachedToWindow()) {
+ mOnAttachStateListener.onViewAttachedToWindow(mView);
}
+ addOnAttachStateChangeListener(mOnAttachStateListener);
}
/**
@@ -100,6 +98,17 @@ public abstract class ViewController<T extends View> {
return mView.getResources();
}
+ public boolean isAttachedToWindow() {
+ return mView != null && mView.isAttachedToWindow();
+ }
+
+ /** Add an OnAttachStateListener to the view. Does nothing if the view is null. */
+ public void addOnAttachStateChangeListener(View.OnAttachStateChangeListener listener) {
+ if (mView != null) {
+ mView.addOnAttachStateChangeListener(listener);
+ }
+ }
+
/**
* Called when the view is attached and a call to {@link #init()} has been made in either order.
*/
@@ -109,4 +118,5 @@ public abstract class ViewController<T extends View> {
* Called when the view is detached.
*/
protected abstract void onViewDetached();
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index ad596c27ba97..844f12e0c43e 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -27,10 +27,10 @@ import static android.service.notification.NotificationListenerService.REASON_GR
import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
-import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
+import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.app.INotificationManager;
import android.app.Notification;
@@ -53,8 +53,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
-import com.android.systemui.bubbles.BubbleEntry;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
@@ -80,6 +78,8 @@ import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.wm.shell.bubbles.BubbleEntry;
+import com.android.wm.shell.bubbles.Bubbles;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
index a59c87652632..86ba5f1f74a9 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
@@ -22,8 +22,9 @@ import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
@@ -50,19 +51,21 @@ public abstract class TvPipModule {
static Optional<Pip> providePip(
Context context,
PipBoundsState pipBoundsState,
- PipBoundsHandler pipBoundsHandler,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
PipTaskOrganizer pipTaskOrganizer,
PipMediaController pipMediaController,
PipNotification pipNotification,
+ TaskStackListenerImpl taskStackListener,
WindowManagerShellWrapper windowManagerShellWrapper) {
return Optional.of(
new PipController(
context,
pipBoundsState,
- pipBoundsHandler,
+ pipBoundsAlgorithm,
pipTaskOrganizer,
pipMediaController,
pipNotification,
+ taskStackListener,
windowManagerShellWrapper));
}
@@ -88,26 +91,26 @@ public abstract class TvPipModule {
@WMSingleton
@Provides
- static PipBoundsHandler providePipBoundsHandler(Context context,
+ static PipBoundsAlgorithm providePipBoundsHandler(Context context,
PipBoundsState pipBoundsState) {
- return new PipBoundsHandler(context, pipBoundsState);
+ return new PipBoundsAlgorithm(context, pipBoundsState);
}
@WMSingleton
@Provides
- static PipBoundsState providePipBoundsState() {
- return new PipBoundsState();
+ static PipBoundsState providePipBoundsState(Context context) {
+ return new PipBoundsState(context);
}
@WMSingleton
@Provides
static PipTaskOrganizer providePipTaskOrganizer(Context context,
PipBoundsState pipBoundsState,
- PipBoundsHandler pipBoundsHandler,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
- return new PipTaskOrganizer(context, pipBoundsState, pipBoundsHandler,
+ return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
null /* menuActivityController */, pipSurfaceTransactionHelper, splitScreenOptional,
displayController, pipUiEventLogger, shellTaskOrganizer);
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index 294c749a2abe..f88bedd88d9f 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -27,6 +27,7 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -57,8 +58,9 @@ public class TvWMShellModule {
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer,
- SyncTransactionQueue syncQueue) {
+ SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener) {
return new SplitScreenController(context, displayController, systemWindows,
- displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue);
+ displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue,
+ taskStackListener);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index f896891c5039..c36acf5b6def 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -16,8 +16,6 @@
package com.android.systemui.wmshell;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
@@ -29,21 +27,14 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_O
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
-import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.ActivityTaskManager.RootTaskInfo;
-import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.util.Log;
-import android.util.Pair;
import android.view.KeyEvent;
import com.android.internal.annotations.VisibleForTesting;
@@ -55,9 +46,6 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.shared.system.InputConsumerController;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -65,13 +53,14 @@ import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.wm.shell.ShellDump;
+import com.android.wm.shell.apppairs.AppPairs;
+import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.nano.WmShellTraceProto;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedEvents;
import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEventCallback;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogImpl;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -100,17 +89,17 @@ public final class WMShell extends SystemUI
private final CommandQueue mCommandQueue;
private final ConfigurationController mConfigurationController;
- private final InputConsumerController mInputConsumerController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final TaskStackChangeListeners mTaskStackChangeListeners;
private final NavigationModeController mNavigationModeController;
private final ScreenLifecycle mScreenLifecycle;
private final SysUiState mSysUiState;
private final Optional<Pip> mPipOptional;
private final Optional<SplitScreen> mSplitScreenOptional;
private final Optional<OneHanded> mOneHandedOptional;
+ private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional;
private final ProtoTracer mProtoTracer;
private final Optional<ShellDump> mShellDump;
+ private final Optional<AppPairs> mAppPairsOptional;
private boolean mIsSysUiStateValid;
private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
@@ -120,32 +109,32 @@ public final class WMShell extends SystemUI
@Inject
public WMShell(Context context, CommandQueue commandQueue,
ConfigurationController configurationController,
- InputConsumerController inputConsumerController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- TaskStackChangeListeners taskStackChangeListeners,
NavigationModeController navigationModeController,
ScreenLifecycle screenLifecycle,
SysUiState sysUiState,
Optional<Pip> pipOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<OneHanded> oneHandedOptional,
+ Optional<HideDisplayCutout> hideDisplayCutoutOptional,
ProtoTracer protoTracer,
- Optional<ShellDump> shellDump) {
+ Optional<ShellDump> shellDump,
+ Optional<AppPairs> appPairsOptional) {
super(context);
mCommandQueue = commandQueue;
mConfigurationController = configurationController;
- mInputConsumerController = inputConsumerController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mTaskStackChangeListeners = taskStackChangeListeners;
mNavigationModeController = navigationModeController;
mScreenLifecycle = screenLifecycle;
mSysUiState = sysUiState;
mPipOptional = pipOptional;
mSplitScreenOptional = splitScreenOptional;
mOneHandedOptional = oneHandedOptional;
+ mHideDisplayCutoutOptional = hideDisplayCutoutOptional;
mProtoTracer = protoTracer;
mProtoTracer.add(this);
mShellDump = shellDump;
+ mAppPairsOptional = appPairsOptional;
}
@Override
@@ -154,6 +143,7 @@ public final class WMShell extends SystemUI
mPipOptional.ifPresent(this::initPip);
mSplitScreenOptional.ifPresent(this::initSplitScreen);
mOneHandedOptional.ifPresent(this::initOneHanded);
+ mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
}
@VisibleForTesting
@@ -192,58 +182,6 @@ public final class WMShell extends SystemUI
}
});
- // TODO: Move this into the shell
- // Handle for system task stack changes.
- mTaskStackChangeListeners.registerTaskStackListener(
- new TaskStackChangeListener() {
- @Override
- public void onTaskStackChanged() {
- pip.onTaskStackChanged();
- }
-
- @Override
- public void onActivityPinned(String packageName, int userId, int taskId,
- int stackId) {
- pip.onActivityPinned(packageName);
- mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
- }
-
- @Override
- public void onActivityUnpinned() {
- final Pair<ComponentName, Integer> topPipActivityInfo =
- PipUtils.getTopPipActivity(mContext);
- final ComponentName topActivity = topPipActivityInfo.first;
- pip.onActivityUnpinned(topActivity);
- mInputConsumerController.unregisterInputConsumer();
- }
-
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- pip.onActivityRestartAttempt(task, clearedTask);
- }
- });
-
- try {
- RootTaskInfo taskInfo = ActivityTaskManager.getService().getRootTaskInfo(
- WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
- if (taskInfo != null) {
- // If SystemUI restart, and it already existed a pinned stack,
- // register the pip input consumer to ensure touch can send to it.
- mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
- }
- } catch (RemoteException | UnsupportedOperationException e) {
- Log.e(TAG, "Failed to register pinned stack listener", e);
- e.printStackTrace();
- }
-
- // Register the listener for input consumer touch events. Only for Phone
- if (pip.getPipTouchHandler() != null) {
- mInputConsumerController.setInputListener(pip.getPipTouchHandler()::handleTouchEvent);
- mInputConsumerController.setRegistrationListener(
- pip.getPipTouchHandler()::onRegistrationChanged);
- }
-
// The media session listener needs to be re-registered when switching users
UserInfoController userInfoController = Dependency.get(UserInfoController.class);
userInfoController.addCallback((String name, Drawable picture, String userAccount) ->
@@ -263,39 +201,6 @@ public final class WMShell extends SystemUI
}
};
mKeyguardUpdateMonitor.registerCallback(mSplitScreenKeyguardCallback);
-
- mTaskStackChangeListeners.registerTaskStackListener(
- new TaskStackChangeListener() {
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || !splitScreen.isSplitScreenSupported()) {
- return;
- }
-
- if (splitScreen.isMinimized()) {
- splitScreen.onUndockingTask();
- }
- }
-
- @Override
- public void onActivityForcedResizable(String packageName, int taskId,
- int reason) {
- splitScreen.onActivityForcedResizable(packageName, taskId, reason);
- }
-
- @Override
- public void onActivityDismissingDockedStack() {
- splitScreen.onActivityDismissingSplitScreen();
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayFailed() {
- splitScreen.onActivityLaunchOnSecondaryDisplayFailed();
- }
- });
}
@VisibleForTesting
@@ -375,21 +280,16 @@ public final class WMShell extends SystemUI
}
}
});
+ }
- mTaskStackChangeListeners.registerTaskStackListener(
- new TaskStackChangeListener() {
- @Override
- public void onTaskCreated(int taskId, ComponentName componentName) {
- oneHanded.stopOneHanded(
- OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
- }
-
- @Override
- public void onTaskMovedToFront(int taskId) {
- oneHanded.stopOneHanded(
- OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
- }
- });
+ @VisibleForTesting
+ void initHideDisplayCutout(HideDisplayCutout hideDisplayCutout) {
+ mConfigurationController.addCallback(new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ hideDisplayCutout.onConfigurationChanged(newConfig);
+ }
+ });
}
@Override
@@ -439,6 +339,21 @@ public final class WMShell extends SystemUI
}
return true;
}
+
+ case "pair": {
+ String[] groups = Arrays.copyOfRange(args, i + 1, args.length);
+ final int taskId1 = new Integer(groups[0]);
+ final int taskId2 = new Integer(groups[1]);
+ mAppPairsOptional.ifPresent(appPairs -> appPairs.pair(taskId1, taskId2));
+ return true;
+ }
+
+ case "unpair": {
+ String[] groups = Arrays.copyOfRange(args, i + 1, args.length);
+ final int taskId = new Integer(groups[0]);
+ mAppPairsOptional.ifPresent(appPairs -> appPairs.unpair(taskId));
+ return true;
+ }
}
}
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 91ae08e07677..74aa1a7d0749 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -18,27 +18,36 @@ package com.android.systemui.wmshell;
import android.app.IActivityManager;
import android.content.Context;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.view.IWindowManager;
+import android.view.WindowManager;
import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.bubbles.Bubbles;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.dagger.WMSingleton;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.shared.system.InputConsumerController;
import com.android.wm.shell.ShellDump;
import com.android.wm.shell.ShellInit;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.apppairs.AppPairs;
+import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.AnimationThread;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.HandlerExecutor;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.draganddrop.DragAndDropController;
+import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
+import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
@@ -67,11 +76,13 @@ public abstract class WMShellBaseModule {
static ShellInit provideShellInit(DisplayImeController displayImeController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
- Optional<SplitScreen> splitScreenOptional) {
+ Optional<SplitScreen> splitScreenOptional,
+ Optional<AppPairs> appPairsOptional) {
return new ShellInit(displayImeController,
dragAndDropController,
shellTaskOrganizer,
- splitScreenOptional);
+ splitScreenOptional,
+ appPairsOptional);
}
/**
@@ -83,9 +94,11 @@ public abstract class WMShellBaseModule {
static Optional<ShellDump> provideShellDump(ShellTaskOrganizer shellTaskOrganizer,
Optional<SplitScreen> splitScreenOptional,
Optional<Pip> pipOptional,
- Optional<OneHanded> oneHandedOptional) {
+ Optional<OneHanded> oneHandedOptional,
+ Optional<HideDisplayCutout> hideDisplayCutout,
+ Optional<AppPairs> appPairsOptional) {
return Optional.of(new ShellDump(shellTaskOrganizer, splitScreenOptional, pipOptional,
- oneHandedOptional));
+ oneHandedOptional, hideDisplayCutout, appPairsOptional));
}
@WMSingleton
@@ -110,8 +123,14 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
- static InputConsumerController provideInputConsumerController() {
- return InputConsumerController.getPipInputConsumer();
+ static FloatingContentCoordinator provideFloatingContentCoordinator() {
+ return new FloatingContentCoordinator();
+ }
+
+ @WMSingleton
+ @Provides
+ static WindowManagerShellWrapper provideWindowManagerShellWrapper() {
+ return new WindowManagerShellWrapper();
}
@WMSingleton
@@ -158,22 +177,45 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static ShellTaskOrganizer provideShellTaskOrganizer(SyncTransactionQueue syncQueue,
- ShellExecutor mainExecutor, TransactionPool transactionPool) {
+ ShellExecutor mainExecutor, TransactionPool transactionPool, Context context) {
return new ShellTaskOrganizer(syncQueue, transactionPool,
- mainExecutor, AnimationThread.instance().getExecutor());
+ mainExecutor, AnimationThread.instance().getExecutor(), context);
+ }
+
+ @WMSingleton
+ @Provides
+ static TaskStackListenerImpl providerTaskStackListenerImpl(@Main Handler handler) {
+ return new TaskStackListenerImpl(handler);
}
@BindsOptionalOf
abstract SplitScreen optionalSplitScreen();
@BindsOptionalOf
- abstract Bubbles optionalBubbles();
+ abstract AppPairs optionalAppPairs();
+
+ @WMSingleton
+ @Provides
+ static Optional<Bubbles> provideBubbles(Context context,
+ FloatingContentCoordinator floatingContentCoordinator,
+ IStatusBarService statusBarService,
+ WindowManager windowManager,
+ WindowManagerShellWrapper windowManagerShellWrapper,
+ LauncherApps launcherApps,
+ UiEventLogger uiEventLogger,
+ @Main Handler mainHandler,
+ ShellTaskOrganizer organizer) {
+ return Optional.of(BubbleController.create(context, null /* synchronizer */,
+ floatingContentCoordinator, statusBarService, windowManager,
+ windowManagerShellWrapper, launcherApps, uiEventLogger, mainHandler, organizer));
+ }
@WMSingleton
@Provides
static Optional<OneHanded> provideOneHandedController(Context context,
- DisplayController displayController) {
- return Optional.ofNullable(OneHandedController.create(context, displayController));
+ DisplayController displayController, TaskStackListenerImpl taskStackListener) {
+ return Optional.ofNullable(OneHandedController.create(context, displayController,
+ taskStackListener));
}
@WMSingleton
@@ -182,4 +224,10 @@ public abstract class WMShellBaseModule {
return new HandlerExecutor(handler);
}
+ @WMSingleton
+ @Provides
+ static Optional<HideDisplayCutout> provideHideDisplayCutoutController(Context context,
+ DisplayController displayController) {
+ return Optional.ofNullable(HideDisplayCutoutController.create(context, displayController));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 0f8fb7bbd0ec..ef8a08c565a0 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -24,15 +24,18 @@ import com.android.systemui.dagger.WMSingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.apppairs.AppPairs;
+import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.pip.PipBoundsHandler;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
@@ -72,36 +75,44 @@ public class WMShellModule {
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer,
- SyncTransactionQueue syncQueue) {
+ SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener) {
return new SplitScreenController(context, displayController, systemWindows,
- displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue);
+ displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue,
+ taskStackListener);
+ }
+
+ @WMSingleton
+ @Provides
+ static AppPairs provideAppPairs(ShellTaskOrganizer shellTaskOrganizer,
+ SyncTransactionQueue syncQueue) {
+ return new AppPairsController(shellTaskOrganizer, syncQueue);
}
@WMSingleton
@Provides
static Optional<Pip> providePip(Context context, DisplayController displayController,
- PipAppOpsListener pipAppOpsListener, PipBoundsHandler pipBoundsHandler,
+ PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
- ShellExecutor mainExecutor) {
+ TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
return Optional.ofNullable(PipController.create(context, displayController,
- pipAppOpsListener, pipBoundsHandler, pipBoundsState, pipMediaController,
+ pipAppOpsListener, pipBoundsAlgorithm, pipBoundsState, pipMediaController,
pipMenuActivityController, pipTaskOrganizer, pipTouchHandler,
- windowManagerShellWrapper, mainExecutor));
+ windowManagerShellWrapper, taskStackListener, mainExecutor));
}
@WMSingleton
@Provides
- static PipBoundsState providePipBoundsState() {
- return new PipBoundsState();
+ static PipBoundsState providePipBoundsState(Context context) {
+ return new PipBoundsState(context);
}
@WMSingleton
@Provides
- static PipBoundsHandler providesPipBoundsHandler(Context context,
+ static PipBoundsAlgorithm providesPipBoundsHandler(Context context,
PipBoundsState pipBoundsState) {
- return new PipBoundsHandler(context, pipBoundsState);
+ return new PipBoundsAlgorithm(context, pipBoundsState);
}
@WMSingleton
@@ -114,12 +125,12 @@ public class WMShellModule {
@WMSingleton
@Provides
static PipTouchHandler providePipTouchHandler(Context context,
- PipMenuActivityController menuActivityController, PipBoundsHandler pipBoundsHandler,
+ PipMenuActivityController menuActivityController, PipBoundsAlgorithm pipBoundsAlgorithm,
PipBoundsState pipBoundsState,
PipTaskOrganizer pipTaskOrganizer,
FloatingContentCoordinator floatingContentCoordinator,
PipUiEventLogger pipUiEventLogger) {
- return new PipTouchHandler(context, menuActivityController, pipBoundsHandler,
+ return new PipTouchHandler(context, menuActivityController, pipBoundsAlgorithm,
pipBoundsState, pipTaskOrganizer, floatingContentCoordinator, pipUiEventLogger);
}
@@ -127,12 +138,12 @@ public class WMShellModule {
@Provides
static PipTaskOrganizer providePipTaskOrganizer(Context context,
PipBoundsState pipBoundsState,
- PipBoundsHandler pipBoundsHandler,
+ PipBoundsAlgorithm pipBoundsAlgorithm,
PipMenuActivityController menuActivityController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
- return new PipTaskOrganizer(context, pipBoundsState, pipBoundsHandler,
+ return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
menuActivityController, pipSurfaceTransactionHelper, splitScreenOptional,
displayController, pipUiEventLogger, shellTaskOrganizer);
}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index e5847b08a4c5..f1c687ff3224 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -63,7 +63,7 @@
</intent-filter>
</receiver>
- <activity android:name="com.android.systemui.bubbles.BubblesTestActivity"
+ <activity android:name=".wmshell.BubblesTestActivity"
android:allowEmbedded="true"
android:documentLaunchMode="always"
android:excludeFromRecents="true"
diff --git a/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
index 594f0b1a8deb..cbd6e8659e69 100644
--- a/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
+++ b/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
@@ -116,6 +116,13 @@ public class AAAPlusPlusVerifySysuiRequiredTestPropertiesTest extends SysuiTestC
filter.add(s -> s.startsWith("com.android.systemui")
|| s.startsWith("com.android.keyguard"));
+ // Screenshots run in an isolated process and should not be run
+ // with the main process dependency graph because it will not exist
+ // at runtime and could lead to incorrect tests which assume
+ // the main SystemUI process. Therefore, exclude this package
+ // from the base class whitelist.
+ filter.add(s -> !s.startsWith("com.android.systemui.screenshot"));
+
try {
return scanner.getClassPathEntries(filter);
} catch (IOException e) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/FontInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/FontInterpolatorTest.kt
new file mode 100644
index 000000000000..95fa3b9c594b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/FontInterpolatorTest.kt
@@ -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 com.android.keyguard
+
+import android.graphics.Paint
+import android.graphics.fonts.Font
+import android.graphics.fonts.FontVariationAxis
+import android.graphics.text.TextRunShaper
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class FontInterpolatorTest : SysuiTestCase() {
+
+ private val sFont = TextRunShaper.shapeTextRun("A", 0, 1, 0, 1, 0f, 0f, false, Paint())
+ .getFont(0)
+
+ private fun assertSameAxes(expect: Font, actual: Font) {
+ val expectAxes = expect.axes?.also { it.sortBy { axis -> axis.tag } }
+ val actualAxes = actual.axes?.also { it.sortBy { axis -> axis.tag } }
+ assertThat(expectAxes).isEqualTo(actualAxes)
+ }
+
+ private fun assertSameAxes(expectVarSettings: String, actual: Font) {
+
+ val expectAxes = FontVariationAxis.fromFontVariationSettings(expectVarSettings)?.also {
+ it.sortBy { axis -> axis.tag }
+ }
+ val actualAxes = actual.axes?.also { it.sortBy { axis -> axis.tag } }
+ assertThat(expectAxes).isEqualTo(actualAxes)
+ }
+
+ @Test
+ fun textInterpolation() {
+ val startFont = Font.Builder(sFont)
+ .setFontVariationSettings("'wght' 100, 'ital' 0, 'GRAD' 200")
+ .build()
+ val endFont = Font.Builder(sFont)
+ .setFontVariationSettings("'wght' 900, 'ital' 1, 'GRAD' 700")
+ .build()
+
+ val interp = FontInterpolator()
+ assertSameAxes(startFont, interp.lerp(startFont, endFont, 0f))
+ assertSameAxes(endFont, interp.lerp(startFont, endFont, 1f))
+ assertSameAxes("'wght' 500, 'ital' 0.5, 'GRAD' 450", interp.lerp(startFont, endFont, 0.5f))
+ }
+
+ @Test
+ fun textInterpolation_DefaultValue() {
+ val startFont = Font.Builder(sFont)
+ .setFontVariationSettings("'wght' 100")
+ .build()
+ val endFont = Font.Builder(sFont)
+ .setFontVariationSettings("'ital' 1")
+ .build()
+
+ val interp = FontInterpolator()
+ assertSameAxes("'wght' 250, 'ital' 0.5", interp.lerp(startFont, endFont, 0.5f))
+ }
+
+ @Test
+ fun testInterpCache() {
+ val startFont = Font.Builder(sFont)
+ .setFontVariationSettings("'wght' 100")
+ .build()
+ val endFont = Font.Builder(sFont)
+ .setFontVariationSettings("'ital' 1")
+ .build()
+
+ val interp = FontInterpolator()
+ val resultFont = interp.lerp(startFont, endFont, 0.5f)
+ val cachedFont = interp.lerp(startFont, endFont, 0.5f)
+ assertThat(resultFont).isSameInstanceAs(cachedFont)
+ }
+
+ @Test
+ fun testAxesCache() {
+ val startFont = Font.Builder(sFont)
+ .setFontVariationSettings("'wght' 100")
+ .build()
+ val endFont = Font.Builder(sFont)
+ .setFontVariationSettings("'ital' 1")
+ .build()
+
+ val interp = FontInterpolator()
+ val resultFont = interp.lerp(startFont, endFont, 0.5f)
+ val reversedFont = interp.lerp(endFont, startFont, 0.5f)
+ assertThat(resultFont).isSameInstanceAs(reversedFont)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index caab2abd7ec6..51cbff8f309b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -93,6 +93,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -102,7 +103,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -159,12 +159,15 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private StatusBarStateController mStatusBarStateController;
@Mock
private AuthController mAuthController;
+ @Captor
+ private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
// Direct executor
private Executor mBackgroundExecutor = Runnable::run;
private TestableLooper mTestableLooper;
private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor;
private TestableContext mSpiedContext;
private MockitoSession mMockitoSession;
+ private StatusBarStateController.StateListener mStatusBarStateListener;
@Before
public void setup() {
@@ -201,7 +204,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
when(mTelephonyManager.getServiceStateForSubscriber(anyInt()))
.thenReturn(new ServiceState());
when(mLockPatternUtils.getLockSettings()).thenReturn(mLockSettings);
- when(mAuthController.isUdfpsEnrolled()).thenReturn(false);
+ when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
mSpiedContext.addMockSystemService(TrustManager.class, mTrustManager);
mSpiedContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
mSpiedContext.addMockSystemService(BiometricManager.class, mBiometricManager);
@@ -221,6 +224,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper = TestableLooper.get(this);
allowTestableLooperAsMainThread();
mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);
+
+ verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
+ mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
}
@After
@@ -475,8 +481,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Test
public void testTriesToAuthenticate_whenBouncer() {
- mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
- mTestableLooper.processAllMessages();
+ setKeyguardBouncerVisibility(true);
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
verify(mFaceManager).isHardwareDetected();
@@ -493,10 +498,10 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Test
public void skipsAuthentication_whenStatusBarShadeLocked() {
- when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
-
+ mStatusBarStateListener.onStateChanged(StatusBarState.SHADE_LOCKED);
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
+
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
}
@@ -536,8 +541,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt());
// Stop scanning when bouncer becomes visible
- mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true /* showingBouncer */);
- mTestableLooper.processAllMessages();
+ setKeyguardBouncerVisibility(true);
clearInvocations(mFaceManager);
mKeyguardUpdateMonitor.requestFaceAuth();
verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt());
@@ -768,6 +772,85 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
orderVerify.verify(callback).onRingerModeChanged(AudioManager.RINGER_MODE_VIBRATE);
}
+ @Test
+ public void testStartUdfpsServiceBeginsOnKeyguard() {
+ // GIVEN
+ // - bouncer isn't showing
+ // - status bar state is on the keyguard
+ // - user has authenticated since boot
+ setKeyguardBouncerVisibility(false /* isVisible */);
+ mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+
+ // THEN we should listen for udfps
+ assertThat(mKeyguardUpdateMonitor.shouldListenForUdfps()).isEqualTo(true);
+ }
+
+ @Test
+ public void testStartUdfpsServiceOnShadeLocked() {
+ // GIVEN
+ // - bouncer isn't showing
+ // - user has authenticated since boot
+ setKeyguardBouncerVisibility(false /* isVisible */);
+ when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+
+ // WHEN the status bar state changes to SHADE_LOCKED
+ mStatusBarStateListener.onStateChanged(StatusBarState.SHADE_LOCKED);
+
+ // THEN we shouldn't listen for udfps
+ assertThat(mKeyguardUpdateMonitor.shouldListenForUdfps()).isEqualTo(false);
+ }
+
+ @Test
+ public void testStartUdfpsServiceOnFullscreenUserSwitcher() {
+ // GIVEN
+ // - bouncer isn't showing
+ // - user has authenticated since boot
+ setKeyguardBouncerVisibility(false /* isVisible */);
+ when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+
+ // WHEN the status bar state changes to FULLSCREEN_USER_SWITCHER
+ mStatusBarStateListener.onStateChanged(StatusBarState.FULLSCREEN_USER_SWITCHER);
+
+ // THEN we shouldn't listen for udfps
+ assertThat(mKeyguardUpdateMonitor.shouldListenForUdfps()).isEqualTo(false);
+ }
+
+ @Test
+ public void testStartUdfpsServiceNoAuthenticationSinceLastBoot() {
+ // GIVEN
+ // - bouncer isn't showing
+ // - status bar state is on the keyguard
+ setKeyguardBouncerVisibility(false /* isVisible */);
+ mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD);
+
+ // WHEN user hasn't authenticated since last boot
+ when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(false);
+
+ // THEN we shouldn't listen for udfps
+ assertThat(mKeyguardUpdateMonitor.shouldListenForUdfps()).isEqualTo(false);
+ }
+
+ @Test
+ public void testStartUdfpsServiceOnBouncerNotVisible() {
+ // GIVEN
+ // - status bar state is on the keyguard
+ // - user has authenticated since boot
+ mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
+
+ // WHEN the bouncer is showing
+ setKeyguardBouncerVisibility(true /* isVisible */);
+
+ // THEN we shouldn't listen for udfps
+ assertThat(mKeyguardUpdateMonitor.shouldListenForUdfps()).isEqualTo(false);
+ }
+
+ private void setKeyguardBouncerVisibility(boolean isVisible) {
+ mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isVisible);
+ mTestableLooper.processAllMessages();
+ }
+
private void setBroadcastReceiverPendingResult(BroadcastReceiver receiver) {
BroadcastReceiver.PendingResult pendingResult =
new BroadcastReceiver.PendingResult(Activity.RESULT_OK,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt
new file mode 100644
index 000000000000..516d015c0c1c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/TextAnimatorTest.kt
@@ -0,0 +1,111 @@
+/*
+ * 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.animation.ValueAnimator
+import android.graphics.Paint
+import android.testing.AndroidTestingRunner
+import android.text.Layout
+import android.text.StaticLayout
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.inOrder
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+import kotlin.math.ceil
+
+private val PAINT = TextPaint().apply {
+ textSize = 32f
+}
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class TextAnimatorTest : SysuiTestCase() {
+
+ private fun makeLayout(text: String, paint: TextPaint): Layout {
+ val width = ceil(Layout.getDesiredWidth(text, 0, text.length, paint)).toInt()
+ return StaticLayout.Builder.obtain(text, 0, text.length, paint, width).build()
+ }
+
+ @Test
+ fun testAnimationStarted() {
+ val layout = makeLayout("Hello, World", PAINT)
+ val valueAnimator = mock(ValueAnimator::class.java)
+ val textInterpolator = mock(TextInterpolator::class.java)
+ val paint = mock(Paint::class.java)
+ `when`(textInterpolator.targetPaint).thenReturn(paint)
+
+ val textAnimator = TextAnimator(layout, {}).apply {
+ this.textInterpolator = textInterpolator
+ this.animator = valueAnimator
+ }
+
+ textAnimator.setTextStyle(
+ weight = 400,
+ animate = true
+ )
+
+ // If animation is requested, the base state should be rebased and the target state should
+ // be updated.
+ val order = inOrder(textInterpolator)
+ order.verify(textInterpolator).rebase()
+ order.verify(textInterpolator).onTargetPaintModified()
+
+ // In case of animation, should not shape the base state since the animation should start
+ // from current state.
+ verify(textInterpolator, never()).onBasePaintModified()
+
+ // Then, animation should be started.
+ verify(valueAnimator, times(1)).start()
+ }
+
+ @Test
+ fun testAnimationNotStarted() {
+ val layout = makeLayout("Hello, World", PAINT)
+ val valueAnimator = mock(ValueAnimator::class.java)
+ val textInterpolator = mock(TextInterpolator::class.java)
+ val paint = mock(Paint::class.java)
+ `when`(textInterpolator.targetPaint).thenReturn(paint)
+
+ val textAnimator = TextAnimator(layout, {}).apply {
+ this.textInterpolator = textInterpolator
+ this.animator = valueAnimator
+ }
+
+ textAnimator.setTextStyle(
+ weight = 400,
+ animate = false
+ )
+
+ // If animation is not requested, the progress should be 1 which is end of animation and the
+ // base state is rebased to target state by calling rebase.
+ val order = inOrder(textInterpolator)
+ order.verify(textInterpolator).onTargetPaintModified()
+ order.verify(textInterpolator).progress = 1f
+ order.verify(textInterpolator).rebase()
+
+ // Then, animation start should not be called.
+ verify(valueAnimator, never()).start()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt
new file mode 100644
index 000000000000..65ffcfc47380
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/TextInterpolatorTest.kt
@@ -0,0 +1,143 @@
+/*
+ * 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.graphics.Bitmap
+import android.graphics.Canvas
+import android.testing.AndroidTestingRunner
+import android.text.Layout
+import android.text.StaticLayout
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.math.ceil
+
+private const val TEXT = "Hello, World."
+private const val BMP_WIDTH = 400
+private const val BMP_HEIGHT = 300
+
+private val PAINT = TextPaint().apply {
+ textSize = 32f
+}
+
+private val START_PAINT = TextPaint(PAINT).apply {
+ fontVariationSettings = "'wght' 400"
+}
+
+private val END_PAINT = TextPaint(PAINT).apply {
+ fontVariationSettings = "'wght' 700"
+}
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class TextInterpolatorTest : SysuiTestCase() {
+
+ private fun makeLayout(text: String, paint: TextPaint): Layout {
+ val width = ceil(Layout.getDesiredWidth(text, 0, text.length, paint)).toInt()
+ return StaticLayout.Builder.obtain(text, 0, text.length, paint, width).build()
+ }
+
+ @Test
+ fun testStartState() {
+ val layout = makeLayout(TEXT, PAINT)
+
+ val interp = TextInterpolator(layout)
+ interp.basePaint.set(START_PAINT)
+ interp.onBasePaintModified()
+
+ interp.targetPaint.set(END_PAINT)
+ interp.onTargetPaintModified()
+
+ // Just after created TextInterpolator, it should have 0 progress.
+ assertThat(interp.progress).isEqualTo(0f)
+ val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ val expected = makeLayout(TEXT, START_PAINT).toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+ assertThat(expected.sameAs(actual)).isTrue()
+ }
+
+ @Test
+ fun testEndState() {
+ val layout = makeLayout(TEXT, PAINT)
+
+ val interp = TextInterpolator(layout)
+ interp.basePaint.set(START_PAINT)
+ interp.onBasePaintModified()
+
+ interp.targetPaint.set(END_PAINT)
+ interp.onTargetPaintModified()
+
+ interp.progress = 1f
+ val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ val expected = makeLayout(TEXT, END_PAINT).toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+ assertThat(expected.sameAs(actual)).isTrue()
+ }
+
+ @Test
+ fun testMiddleState() {
+ val layout = makeLayout(TEXT, PAINT)
+
+ val interp = TextInterpolator(layout)
+ interp.basePaint.set(START_PAINT)
+ interp.onBasePaintModified()
+
+ interp.targetPaint.set(END_PAINT)
+ interp.onTargetPaintModified()
+
+ // We cannot expect exact text layout of the middle position since we don't use text shaping
+ // result for the middle state for performance reason. Just check it is not equals to start
+ // end state.
+ interp.progress = 0.5f
+ val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+ assertThat(actual.sameAs(makeLayout(TEXT, START_PAINT).toBitmap(BMP_WIDTH, BMP_HEIGHT)))
+ .isFalse()
+ assertThat(actual.sameAs(makeLayout(TEXT, END_PAINT).toBitmap(BMP_WIDTH, BMP_HEIGHT)))
+ .isFalse()
+ }
+
+ @Test
+ fun testRebase() {
+ val layout = makeLayout(TEXT, PAINT)
+
+ val interp = TextInterpolator(layout)
+ interp.basePaint.set(START_PAINT)
+ interp.onBasePaintModified()
+
+ interp.targetPaint.set(END_PAINT)
+ interp.onTargetPaintModified()
+
+ interp.progress = 0.5f
+ val expected = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+ // Rebase base state to the current state of progress 0.5.
+ interp.rebase()
+ assertThat(interp.progress).isEqualTo(0f)
+ val actual = interp.toBitmap(BMP_WIDTH, BMP_HEIGHT)
+
+ assertThat(expected.sameAs(actual)).isTrue()
+ }
+}
+
+private fun Layout.toBitmap(width: Int, height: Int) =
+ Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8).also { draw(Canvas(it)) }!!
+
+private fun TextInterpolator.toBitmap(width: Int, height: Int) =
+ Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8).also { draw(Canvas(it)) } \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index a39bc702900e..f28322f4d5bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -275,6 +275,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
@Test
public void performA11yActions_visible_expectedResults() {
+ final int displayId = mContext.getDisplayId();
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(2.5f, Float.NaN,
Float.NaN);
@@ -284,10 +285,10 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
assertTrue(
mMirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_out, null));
// Minimum scale is 2.0.
- assertEquals(2.0f, mWindowMagnificationController.getScale(), 0f);
+ verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(2.0f));
assertTrue(mMirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_in, null));
- assertEquals(3.0f, mWindowMagnificationController.getScale(), 0f);
+ verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(3.5f));
// TODO: Verify the final state when the mirror surface is visible.
assertTrue(mMirrorView.performAccessibilityAction(R.id.accessibility_action_move_up, null));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index 4a0e216ae87e..ad1ce76cc36c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -18,6 +18,7 @@ package com.android.systemui.accessibility;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@@ -42,7 +43,6 @@ 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;
@SmallTest
@@ -56,6 +56,8 @@ public class WindowMagnificationTest extends SysuiTestCase {
private ModeSwitchesController mModeSwitchesController;
@Mock
private NavigationModeController mNavigationModeController;
+ @Mock
+ private IWindowMagnificationConnectionCallback mConnectionCallback;
private CommandQueue mCommandQueue;
private WindowMagnification mWindowMagnification;
@@ -63,6 +65,12 @@ public class WindowMagnificationTest extends SysuiTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
getContext().addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager);
+ doAnswer(invocation -> {
+ IWindowMagnificationConnection connection = invocation.getArgument(0);
+ connection.setConnectionCallback(mConnectionCallback);
+ return null;
+ }).when(mAccessibilityManager).setWindowMagnificationConnection(
+ any(IWindowMagnificationConnection.class));
mCommandQueue = new CommandQueue(getContext());
mWindowMagnification = new WindowMagnification(getContext(),
@@ -87,25 +95,29 @@ public class WindowMagnificationTest extends SysuiTestCase {
@Test
public void onWindowMagnifierBoundsChanged() throws RemoteException {
- final IWindowMagnificationConnectionCallback connectionCallback = Mockito.mock(
- IWindowMagnificationConnectionCallback.class);
final Rect testBounds = new Rect(0, 0, 500, 600);
- doAnswer(invocation -> {
- IWindowMagnificationConnection connection = invocation.getArgument(0);
- connection.setConnectionCallback(connectionCallback);
- return null;
- }).when(mAccessibilityManager).setWindowMagnificationConnection(
- any(IWindowMagnificationConnection.class));
mCommandQueue.requestWindowMagnificationConnection(true);
waitForIdleSync();
mWindowMagnification.onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY, testBounds);
- verify(connectionCallback).onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY,
+ verify(mConnectionCallback).onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY,
testBounds);
}
@Test
+ public void onPerformScaleAction_enabled_notifyCallback() throws RemoteException {
+ final float newScale = 4.0f;
+ mCommandQueue.requestWindowMagnificationConnection(true);
+ waitForIdleSync();
+
+ mWindowMagnification.onPerformScaleAction(Display.DEFAULT_DISPLAY, newScale);
+
+ verify(mConnectionCallback).onPerformScaleAction(eq(Display.DEFAULT_DISPLAY),
+ eq(newScale));
+ }
+
+ @Test
public void onConfigurationChanged_updateModeSwitches() {
final Configuration config = new Configuration();
config.densityDpi = Configuration.DENSITY_DPI_ANY;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
index b907cdb54bbf..043bd5cd6ba5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceViewTest.java
@@ -50,8 +50,12 @@ public class AuthBiometricFaceViewTest extends SysuiTestCase {
private TestableFaceView mFaceView;
@Mock private Button mNegativeButton;
- @Mock private Button mPositiveButton;
+ @Mock private Button mCancelButton;
+ @Mock private Button mUseCredentialButton;
+
+ @Mock private Button mConfirmButton;
@Mock private Button mTryAgainButton;
+
@Mock private TextView mErrorView;
@Before
@@ -60,9 +64,14 @@ public class AuthBiometricFaceViewTest extends SysuiTestCase {
mFaceView = new TestableFaceView(mContext);
mFaceView.mIconController = mock(TestableFaceView.TestableIconController.class);
mFaceView.setCallback(mCallback);
+
mFaceView.mNegativeButton = mNegativeButton;
- mFaceView.mPositiveButton = mPositiveButton;
+ mFaceView.mCancelButton = mCancelButton;
+ mFaceView.mUseCredentialButton = mUseCredentialButton;
+
+ mFaceView.mConfirmButton = mConfirmButton;
mFaceView.mTryAgainButton = mTryAgainButton;
+
mFaceView.mIndicatorView = mErrorView;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
index 91dbd6011e22..49282ee360e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
@@ -22,11 +22,16 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.biometrics.PromptInfo;
+import android.hardware.biometrics.SensorProperties;
+import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -55,13 +60,18 @@ public class AuthBiometricViewTest extends SysuiTestCase {
@Mock private AuthPanelController mPanelController;
@Mock private Button mNegativeButton;
+ @Mock private Button mCancelButton;
+ @Mock private Button mUseCredentialButton;
+
@Mock private Button mPositiveButton;
@Mock private Button mTryAgainButton;
+
@Mock private TextView mTitleView;
@Mock private TextView mSubtitleView;
@Mock private TextView mDescriptionView;
@Mock private TextView mIndicatorView;
@Mock private ImageView mIconView;
+ @Mock private View mIconHolderView;
private TestableBiometricView mBiometricView;
@@ -83,15 +93,31 @@ public class AuthBiometricViewTest extends SysuiTestCase {
@Test
public void testOnAuthenticationSucceeded_confirmationRequired_updatesDialogContents() {
- initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector());
+ final Button negativeButton = new Button(mContext);
+ final Button cancelButton = new Button(mContext);
+ initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector() {
+ @Override
+ public Button getNegativeButton() {
+ return negativeButton;
+ }
+
+ @Override
+ public Button getCancelButton() {
+ return cancelButton;
+ }
+ });
mBiometricView.setRequireConfirmation(true);
mBiometricView.onAuthenticationSucceeded();
waitForIdleSync();
assertEquals(AuthBiometricView.STATE_PENDING_CONFIRMATION, mBiometricView.mState);
verify(mCallback, never()).onAction(anyInt());
- verify(mBiometricView.mNegativeButton).setText(eq(R.string.cancel));
- verify(mBiometricView.mPositiveButton).setEnabled(eq(true));
+
+ assertEquals(View.GONE, negativeButton.getVisibility());
+ assertEquals(View.VISIBLE, cancelButton.getVisibility());
+ assertTrue(cancelButton.isEnabled());
+
+ verify(mBiometricView.mConfirmButton).setEnabled(eq(true));
verify(mIndicatorView).setText(eq(R.string.biometric_dialog_tap_confirm));
verify(mIndicatorView).setVisibility(eq(View.VISIBLE));
}
@@ -101,7 +127,7 @@ public class AuthBiometricViewTest extends SysuiTestCase {
Button button = new Button(mContext);
initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector() {
@Override
- public Button getPositiveButton() {
+ public Button getConfirmButton() {
return button;
}
});
@@ -131,18 +157,26 @@ public class AuthBiometricViewTest extends SysuiTestCase {
}
@Test
- public void testNegativeButton_whenPendingConfirmation_sendsActionUserCanceled() {
- Button button = new Button(mContext);
+ public void testCancelButton_whenPendingConfirmation_sendsActionUserCanceled() {
+ Button cancelButton = new Button(mContext);
+ Button negativeButton = new Button(mContext);
initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector() {
@Override
public Button getNegativeButton() {
- return button;
+ return negativeButton;
+ }
+ @Override
+ public Button getCancelButton() {
+ return cancelButton;
}
});
mBiometricView.setRequireConfirmation(true);
mBiometricView.onAuthenticationSucceeded();
- button.performClick();
+
+ assertEquals(View.GONE, negativeButton.getVisibility());
+
+ cancelButton.performClick();
waitForIdleSync();
verify(mCallback).onAction(AuthBiometricView.Callback.ACTION_USER_CANCELED);
@@ -200,6 +234,7 @@ public class AuthBiometricViewTest extends SysuiTestCase {
@Test
public void testBackgroundClicked_whenSmallDialog_neverSendsUserCanceled() {
initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector());
+ mBiometricView.mLayoutParams = new AuthDialog.LayoutParams(0, 0);
mBiometricView.updateSize(AuthDialog.SIZE_SMALL);
View view = new View(mContext);
@@ -275,21 +310,54 @@ public class AuthBiometricViewTest extends SysuiTestCase {
}
@Test
- public void testNegativeButton_whenDeviceCredentialAllowed() throws InterruptedException {
- Button negativeButton = new Button(mContext);
+ public void testCredentialButton_whenDeviceCredentialAllowed() {
+ final Button negativeButton = new Button(mContext);
+ final Button useCredentialButton = new Button(mContext);
initDialog(mContext, true /* allowDeviceCredential */, mCallback, new MockInjector() {
@Override
public Button getNegativeButton() {
return negativeButton;
}
+
+ @Override
+ public Button getUseCredentialButton() {
+ return useCredentialButton;
+ }
});
- negativeButton.performClick();
+ assertEquals(View.GONE, negativeButton.getVisibility());
+ useCredentialButton.performClick();
waitForIdleSync();
verify(mCallback).onAction(AuthBiometricView.Callback.ACTION_USE_DEVICE_CREDENTIAL);
}
+ @Test
+ public void testUdfpsBottomSpacerCalculation() {
+ final int displayHeightPx = 3000;
+ final int navbarHeightPx = 10;
+ final int dialogBottomMarginPx = 20;
+
+ final View buttonBar = mock(View.class);
+ when(buttonBar.getMeasuredHeight()).thenReturn(100);
+
+ final View textIndicator = mock(View.class);
+ when(textIndicator.getMeasuredHeight()).thenReturn(200);
+
+ final int sensorLocationX = 540;
+ final int sensorLocationY = 1600;
+ final int sensorRadius = 100;
+ final FingerprintSensorPropertiesInternal props = new FingerprintSensorPropertiesInternal(
+ 0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
+ FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
+ true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY,
+ sensorRadius);
+
+ assertEquals(970, AuthBiometricUdfpsView.calculateBottomSpacerHeight(
+ displayHeightPx, navbarHeightPx, dialogBottomMarginPx, buttonBar, textIndicator,
+ props));
+ }
+
private PromptInfo buildPromptInfo(boolean allowDeviceCredential) {
PromptInfo promptInfo = new PromptInfo();
promptInfo.setTitle("Title");
@@ -328,7 +396,17 @@ public class AuthBiometricViewTest extends SysuiTestCase {
}
@Override
- public Button getPositiveButton() {
+ public Button getCancelButton() {
+ return mCancelButton;
+ }
+
+ @Override
+ public Button getUseCredentialButton() {
+ return mUseCredentialButton;
+ }
+
+ @Override
+ public Button getConfirmButton() {
return mPositiveButton;
}
@@ -363,6 +441,11 @@ public class AuthBiometricViewTest extends SysuiTestCase {
}
@Override
+ public View getIconHolderView() {
+ return mIconHolderView;
+ }
+
+ @Override
public int getDelayAfterError() {
return 0; // Keep this at 0 for tests to invoke callback immediately.
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 42bb005b5144..ec0aa4ca89ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -22,7 +22,6 @@ import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -513,30 +512,6 @@ public class AuthControllerTest extends SysuiTestCase {
verify(mUdfpsController).onCancelAodInterrupt();
}
- @Test
- public void testOnFullyShown_DelegatesToUdfpsController() {
- mAuthController.onFullyShown();
- verify(mUdfpsController).setBouncerVisibility(eq(true));
- }
-
- @Test
- public void testOnFullyHidden_DelegatesToUdfpsController() {
- mAuthController.onFullyHidden();
- verify(mUdfpsController).setBouncerVisibility(eq(false));
- }
-
- @Test
- public void testOnStartingToShow_NeverDelegatesToUdfpsController() {
- mAuthController.onStartingToShow();
- verify(mUdfpsController).setBouncerVisibility(eq(true));
- }
-
- @Test
- public void testOnStartingToHide_NeverDelegatesToUdfpsController() {
- mAuthController.onStartingToHide();
- verify(mUdfpsController, never()).setBouncerVisibility(anyBoolean());
- }
-
// Helpers
private void showDialog(int[] sensorIds, boolean credentialAllowed) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 82ffd46f7164..648c31924a20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -21,7 +21,6 @@ import static junit.framework.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -90,6 +89,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
private WindowManager mWindowManager;
@Mock
private StatusBarStateController mStatusBarStateController;
+
private FakeSettings mSystemSettings;
private FakeExecutor mFgExecutor;
@@ -173,41 +173,6 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
- public void showUdfpsOverlay_bouncerShowing() throws RemoteException {
- // GIVEN that the bouncer is showing
- mUdfpsController.setBouncerVisibility(/* isShowing */ true);
- // WHEN a request to show the overlay is received
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
- mFgExecutor.runAllReady();
- // THEN the overlay is not attached
- verify(mWindowManager, never()).addView(eq(mUdfpsView), any());
- }
-
- @Test
- public void setBouncerVisibility_overlayDetached() throws RemoteException {
- // GIVEN that the overlay has been requested
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
- // WHEN the bouncer becomes visible
- mUdfpsController.setBouncerVisibility(/* isShowing */ true);
- mFgExecutor.runAllReady();
- // THEN the overlay is detached
- verify(mWindowManager).removeView(eq(mUdfpsView));
- }
-
- @Test
- public void setBouncerVisibility_overlayAttached() throws RemoteException {
- // GIVEN that the bouncer is visible
- mUdfpsController.setBouncerVisibility(/* isShowing */ true);
- // AND the overlay has been requested
- mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
- // WHEN the bouncer is closed
- mUdfpsController.setBouncerVisibility(/* isShowing */ false);
- mFgExecutor.runAllReady();
- // THEN the overlay is attached
- verify(mWindowManager).addView(eq(mUdfpsView), any());
- }
-
- @Test
public void fingerDown() throws RemoteException {
// Configure UdfpsView to accept the ACTION_DOWN event
when(mUdfpsView.isScrimShowing()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ToggleRangeTemplateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ToggleRangeTemplateTest.kt
new file mode 100644
index 000000000000..31e09549a2b5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ToggleRangeTemplateTest.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.service.controls.templates.RangeTemplate
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ToggleRangeTemplateTest : SysuiTestCase() {
+
+ @Test
+ fun testLargeRangeNearestStep() {
+ val trt = ToggleRangeBehavior()
+ trt.rangeTemplate = RangeTemplate("range", -100000f, 100000f, 0f, 5f, null)
+
+ assertEquals(255f, trt.findNearestStep(253f), 0.1f)
+ }
+
+ @Test
+ fun testLargeRangeNearestStepWithNegativeValues() {
+ val trt = ToggleRangeBehavior()
+ trt.rangeTemplate = RangeTemplate("range", -100000f, 100000f, 0f, 5f, null)
+
+ assertEquals(-7855f, trt.findNearestStep(-7853.2f), 0.1f)
+ }
+
+ @Test
+ fun testFractionalRangeNearestStep() {
+ val trt = ToggleRangeBehavior()
+ trt.rangeTemplate = RangeTemplate("range", 10f, 11f, 10f, .01f, null)
+
+ assertEquals(10.54f, trt.findNearestStep(10.543f), 0.01f)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index ad5f987b59e7..32c360f3d2cb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -59,6 +59,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.After;
@@ -96,6 +97,7 @@ public class NavigationBarControllerTest extends SysuiTestCase {
mock(SysUiState.class),
mock(BroadcastDispatcher.class),
mock(CommandQueue.class),
+ Optional.of(mock(Pip.class)),
Optional.of(mock(SplitScreen.class)),
Optional.of(mock(Recents.class)),
() -> mock(StatusBar.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index f308e9e479e1..57eac74401dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -76,6 +76,7 @@ import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.utils.leaks.LeakCheckedTest;
+import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
@@ -223,6 +224,7 @@ public class NavigationBarTest extends SysuiTestCase {
mMockSysUiState,
mBroadcastDispatcher,
mCommandQueue,
+ Optional.of(mock(Pip.class)),
Optional.of(mock(SplitScreen.class)),
Optional.of(mock(Recents.class)),
() -> mock(StatusBar.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
index 3494bd61b656..fa29fd4f94ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java
@@ -49,7 +49,6 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.recents.OverviewProxyService;
import org.junit.Before;
@@ -66,7 +65,6 @@ public class KeyButtonViewTest extends SysuiTestCase {
private KeyButtonView mKeyButtonView;
private MetricsLogger mMetricsLogger;
- private Bubbles mBubbles;
private UiEventLogger mUiEventLogger;
private InputManager mInputManager = mock(InputManager.class);
@Captor
@@ -76,7 +74,6 @@ public class KeyButtonViewTest extends SysuiTestCase {
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
- mBubbles = mDependency.injectMockDependency(Bubbles.class);
mDependency.injectMockDependency(OverviewProxyService.class);
mUiEventLogger = mDependency.injectMockDependency(UiEventLogger.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
new file mode 100644
index 000000000000..3e44fa4a9b2b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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.people.widget;
+
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import static java.util.Objects.requireNonNull;
+
+import android.app.NotificationChannel;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.appwidget.IAppWidgetService;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
+import com.android.systemui.statusbar.notification.collection.NoManSimulator;
+import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.util.time.FakeSystemClock;
+
+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;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
+ private static final long MIN_LINGER_DURATION = 5;
+
+ private static final String TEST_PACKAGE_A = "com.test.package_a";
+ private static final String TEST_PACKAGE_B = "com.test.package_b";
+ private static final String TEST_CHANNEL_ID = "channel_id";
+ private static final String TEST_CHANNEL_NAME = "channel_name";
+ private static final String TEST_PARENT_CHANNEL_ID = "parent_channel_id";
+ private static final String TEST_CONVERSATION_ID = "conversation_id";
+
+ private PeopleSpaceWidgetManager mManager;
+
+ @Mock private NotificationListener mListenerService;
+ @Mock private IAppWidgetService mIAppWidgetService;
+ @Mock private Context mContext;
+
+ @Captor private ArgumentCaptor<NotificationHandler> mListenerCaptor;
+
+ private final NoManSimulator mNoMan = new NoManSimulator();
+ private final FakeSystemClock mClock = new FakeSystemClock();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mManager =
+ new PeopleSpaceWidgetManager(mContext);
+ mManager.setAppWidgetManager(mIAppWidgetService);
+ mManager.attach(mListenerService);
+
+ verify(mListenerService).addNotificationHandler(mListenerCaptor.capture());
+ NotificationHandler serviceListener = requireNonNull(mListenerCaptor.getValue());
+ mNoMan.addListener(serviceListener);
+ }
+
+
+ @Test
+ public void testDoNotNotifyAppWidgetIfNoWidgets() throws RemoteException {
+ int[] widgetIdsArray = {};
+ when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+ NotifEvent notif1 = mNoMan.postNotif(
+ new NotificationEntryBuilder()
+ .setId(0)
+ .setPkg(TEST_PACKAGE_A));
+ mClock.advanceTime(MIN_LINGER_DURATION);
+
+ verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
+ verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
+
+ }
+
+ @Test
+ public void testNotifyAppWidgetIfNotificationPosted() throws RemoteException {
+ int[] widgetIdsArray = {1};
+ when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+ NotifEvent notif1 = mNoMan.postNotif(
+ new NotificationEntryBuilder()
+ .setId(0)
+ .setPkg(TEST_PACKAGE_A));
+ mClock.advanceTime(MIN_LINGER_DURATION);
+
+ verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
+ verify(mIAppWidgetService, times(1))
+ .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
+
+ }
+
+ @Test
+ public void testNotifyAppWidgetTwiceIfTwoNotificationsPosted() throws RemoteException {
+ int[] widgetIdsArray = {1, 2};
+ when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+ NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(1));
+ mClock.advanceTime(4);
+ NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_B)
+ .setId(2));
+
+ verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
+ verify(mIAppWidgetService, times(2))
+ .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
+ }
+
+ @Test
+ public void testNotifyAppWidgetTwiceIfNotificationPostedAndRemoved() throws RemoteException {
+ int[] widgetIdsArray = {1, 2};
+ when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+ NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_A)
+ .setId(1));
+ mClock.advanceTime(4);
+ NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn, 0);
+
+ verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
+ verify(mIAppWidgetService, times(2))
+ .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
+ }
+
+ @Test
+ public void testDoNotNotifyAppWidgetIfNonConversationChannelModified() throws RemoteException {
+ int[] widgetIdsArray = {1};
+ when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+ NotificationChannel channel =
+ mNoMan.createNotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME);
+
+ mNoMan.issueChannelModification(TEST_PACKAGE_A,
+ UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH);
+ mClock.advanceTime(MIN_LINGER_DURATION);
+
+ verify(mIAppWidgetService, never()).getAppWidgetIds(any());
+ verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
+
+ }
+
+ @Test
+ public void testNotifyAppWidgetIfConversationChannelModified() throws RemoteException {
+ int[] widgetIdsArray = {1};
+ when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
+
+ NotificationChannel channel =
+ mNoMan.createNotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME);
+ channel.setConversationId(TEST_PARENT_CHANNEL_ID, TEST_CONVERSATION_ID);
+
+ mNoMan.issueChannelModification(TEST_PACKAGE_A,
+ UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH);
+ mClock.advanceTime(MIN_LINGER_DURATION);
+
+ verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
+ verify(mIAppWidgetService, times(1))
+ .notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
+
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
index 803919200150..c050b628e98d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java
@@ -52,7 +52,7 @@ public class QSDetailTest extends SysuiTestCase {
private MetricsLogger mMetricsLogger;
private QSDetail mQsDetail;
- private QSPanel mQsPanel;
+ private QSPanelController mQsPanelController;
private QuickStatusBarHeader mQuickHeader;
private ActivityStarter mActivityStarter;
private DetailAdapter mMockDetailAdapter;
@@ -68,9 +68,9 @@ public class QSDetailTest extends SysuiTestCase {
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
mQsDetail = (QSDetail) LayoutInflater.from(mContext).inflate(R.layout.qs_detail, null);
- mQsPanel = mock(QSPanel.class);
+ mQsPanelController = mock(QSPanelController.class);
mQuickHeader = mock(QuickStatusBarHeader.class);
- mQsDetail.setQsPanel(mQsPanel, mQuickHeader, mock(QSFooter.class));
+ mQsDetail.setQsPanel(mQsPanelController, mQuickHeader, mock(QSFooter.class));
mMockDetailAdapter = mock(DetailAdapter.class);
when(mMockDetailAdapter.createDetailView(any(), any(), any()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index 065f236d19b3..2dfd38832997 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -40,6 +40,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.phone.MultiUserSwitch;
import com.android.systemui.statusbar.phone.SettingsButton;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.UserInfoController;
@@ -75,6 +76,8 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
private QSPanelController mQSPanelController;
@Mock
private ClipboardManager mClipboardManager;
+ @Mock
+ private QuickQSPanelController mQuickQSPanelController;
private FakeTunerService mFakeTunerService;
private MetricsLogger mMetricsLogger = new FakeMetricsLogger();
@@ -84,6 +87,8 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
private TextView mBuildText;
@Mock
private View mEdit;
+ @Mock
+ private MultiUserSwitch mMultiUserSwitch;
private QSFooterViewController mController;
@@ -105,10 +110,12 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
when(mView.findViewById(R.id.settings_button)).thenReturn(mSettingsButton);
when(mView.findViewById(R.id.build)).thenReturn(mBuildText);
when(mView.findViewById(android.R.id.edit)).thenReturn(mEdit);
+ when(mView.findViewById(R.id.multi_user_switch)).thenReturn(mMultiUserSwitch);
mController = new QSFooterViewController(mView, mUserManager, mUserInfoController,
mActivityStarter, mDeviceProvisionedController, mUserTracker, mQSPanelController,
- mFakeTunerService, mMetricsLogger);
+ new QSDetailDisplayer(), mQuickQSPanelController, mFakeTunerService,
+ mMetricsLogger);
mController.init();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 90609ccb48d6..a6b0330743b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -43,6 +43,7 @@ import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.dagger.QSFragmentComponent;
import com.android.systemui.qs.logging.QSLogger;
@@ -82,6 +83,10 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
private QSFragmentComponent mQsFragmentComponent;
@Mock
private QSPanelController mQSPanelController;
+ @Mock
+ private MediaHost mQSMediaHost;
+ @Mock
+ private MediaHost mQQSMediaHost;
public QSFragmentTest() {
super(QSFragment.class);
@@ -167,6 +172,9 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
mock(QSTileHost.class),
mock(StatusBarStateController.class),
commandQueue,
+ new QSDetailDisplayer(),
+ mQSMediaHost,
+ mQQSMediaHost,
mQsComponentFactory);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index bf0e0841de9a..0fe44ad412e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -19,9 +19,12 @@ package com.android.systemui.qs;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -38,6 +41,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTileView;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import org.junit.Before;
@@ -61,6 +65,12 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
@Mock
private QSTileHost mQSTileHost;
@Mock
+ private QSCustomizerController mQSCustomizerController;
+ @Mock
+ private QSTileRevealController.Factory mQSTileRevealControllerFactory;
+ @Mock
+ private QSTileRevealController mQSTileRevealController;
+ @Mock
private MediaHost mMediaHost;
@Mock
private MetricsLogger mMetricsLogger;
@@ -70,15 +80,23 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
QSTileImpl mQSTile;
@Mock
QSTileView mQSTileView;
+ @Mock
+ PagedTileLayout mPagedTileLayout;
private QSPanelControllerBase<QSPanel> mController;
/** Implementation needed to ensure we have a reflectively-available class name. */
- private static class TestableQSPanelControllerBase extends QSPanelControllerBase<QSPanel> {
+ private class TestableQSPanelControllerBase extends QSPanelControllerBase<QSPanel> {
protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host,
- MetricsLogger metricsLogger,
- UiEventLogger uiEventLogger, DumpManager dumpManager) {
- super(view, host, metricsLogger, uiEventLogger, dumpManager);
+ QSCustomizerController qsCustomizerController, MediaHost mediaHost,
+ MetricsLogger metricsLogger, UiEventLogger uiEventLogger, DumpManager dumpManager) {
+ super(view, host, qsCustomizerController, mediaHost,
+ metricsLogger, uiEventLogger, dumpManager);
+ }
+
+ @Override
+ protected QSTileRevealController createTileRevealController() {
+ return mQSTileRevealController;
}
}
@@ -86,21 +104,60 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
- when(mQSPanel.getMediaHost()).thenReturn(mMediaHost);
when(mQSPanel.isAttachedToWindow()).thenReturn(true);
when(mQSPanel.getDumpableTag()).thenReturn("QSPanel");
when(mQSPanel.openPanelEvent()).thenReturn(QSEvent.QS_PANEL_EXPANDED);
when(mQSPanel.closePanelEvent()).thenReturn(QSEvent.QS_PANEL_COLLAPSED);
+ when(mQSPanel.createRegularTileLayout()).thenReturn(mPagedTileLayout);
when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile));
when(mQSTileHost.createTileView(eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
+ when(mQSTileRevealControllerFactory.create(any(), any()))
+ .thenReturn(mQSTileRevealController);
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
- mMetricsLogger, mUiEventLogger, mDumpManager);
+ mQSCustomizerController, mMediaHost, mMetricsLogger, mUiEventLogger, mDumpManager);
mController.init();
+ reset(mQSTileRevealController);
}
@Test
+ public void testSetRevealExpansion_preAttach() {
+ mController.onViewDetached();
+
+ QSPanelControllerBase<QSPanel> controller = new QSPanelControllerBase<QSPanel>(
+ mQSPanel, mQSTileHost, mQSCustomizerController, mMediaHost, mMetricsLogger,
+ mUiEventLogger, mDumpManager) {
+ @Override
+ protected QSTileRevealController createTileRevealController() {
+ return mQSTileRevealController;
+ }
+ };
+
+ // Nothing happens until attached
+ controller.setRevealExpansion(0);
+ verify(mQSTileRevealController, never()).setExpansion(anyFloat());
+ controller.setRevealExpansion(0.5f);
+ verify(mQSTileRevealController, never()).setExpansion(anyFloat());
+ controller.setRevealExpansion(1);
+ verify(mQSTileRevealController, never()).setExpansion(anyFloat());
+
+ controller.init();
+ verify(mQSTileRevealController).setExpansion(1);
+ }
+
+ @Test
+ public void testSetRevealExpansion_postAttach() {
+ mController.setRevealExpansion(0);
+ verify(mQSTileRevealController).setExpansion(0);
+ mController.setRevealExpansion(0.5f);
+ verify(mQSTileRevealController).setExpansion(0.5f);
+ mController.setRevealExpansion(1);
+ verify(mQSTileRevealController).setExpansion(1);
+ }
+
+
+ @Test
public void testSetExpanded_Metrics() {
mController.setExpanded(true);
verify(mMetricsLogger).visibility(eq(MetricsEvent.QS_PANEL), eq(true));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
index 0ba0214d2173..9090b9bc0e6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.java
@@ -35,10 +35,13 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTileView;
+import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.settings.BrightnessController;
-import com.android.systemui.settings.ToggleSlider;
+import com.android.systemui.settings.brightness.BrightnessController;
+import com.android.systemui.settings.brightness.BrightnessSlider;
+import com.android.systemui.settings.brightness.ToggleSlider;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.animation.DisappearParameters;
import org.junit.Before;
import org.junit.Test;
@@ -58,6 +61,12 @@ public class QSPanelControllerTest extends SysuiTestCase {
@Mock
private QSTileHost mQSTileHost;
@Mock
+ private QSCustomizerController mQSCustomizerController;
+ @Mock
+ private QSTileRevealController.Factory mQSTileRevealControllerFactory;
+ @Mock
+ private QSTileRevealController mQSTileRevealController;
+ @Mock
private MediaHost mMediaHost;
@Mock
private MetricsLogger mMetricsLogger;
@@ -72,9 +81,16 @@ public class QSPanelControllerTest extends SysuiTestCase {
@Mock
private BrightnessController mBrightnessController;
@Mock
+ private BrightnessSlider.Factory mToggleSliderViewControllerFactory;
+ @Mock
+ private BrightnessSlider mBrightnessSlider;
+ @Mock
QSTileImpl mQSTile;
@Mock
QSTileView mQSTileView;
+ @Mock
+ PagedTileLayout mPagedTileLayout;
+
private QSPanelController mController;
@@ -82,17 +98,23 @@ public class QSPanelControllerTest extends SysuiTestCase {
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
- when(mQSPanel.getMediaHost()).thenReturn(mMediaHost);
when(mQSPanel.isAttachedToWindow()).thenReturn(true);
when(mQSPanel.getDumpableTag()).thenReturn("QSPanel");
+ when(mQSPanel.createRegularTileLayout()).thenReturn(mPagedTileLayout);
when(mQSTileHost.getTiles()).thenReturn(Collections.singleton(mQSTile));
when(mQSTileHost.createTileView(eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
+ when(mToggleSliderViewControllerFactory.create(any(), any()))
+ .thenReturn(mBrightnessSlider);
when(mBrightnessControllerFactory.create(any(ToggleSlider.class)))
.thenReturn(mBrightnessController);
+ when(mQSTileRevealControllerFactory.create(any(), any()))
+ .thenReturn(mQSTileRevealController);
+ when(mMediaHost.getDisappearParameters()).thenReturn(new DisappearParameters());
mController = new QSPanelController(mQSPanel, mQSSecurityFooter, mTunerService,
- mQSTileHost, mDumpManager, mMetricsLogger, mUiEventLogger,
- mBrightnessControllerFactory);
+ mQSTileHost, mQSCustomizerController, mMediaHost, mQSTileRevealControllerFactory,
+ mDumpManager, mMetricsLogger, mUiEventLogger, mBrightnessControllerFactory,
+ mToggleSliderViewControllerFactory);
mController.init();
}
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 e38d54b90f69..450ffac08138 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
@@ -39,7 +39,6 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.ActivityStarter;
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.policy.SecurityController;
@@ -65,12 +64,8 @@ public class QSPanelTest extends SysuiTestCase {
@Mock
private QSTileHost mHost;
@Mock
- private QSCustomizer mCustomizer;
- @Mock
private QSTileImpl dndTile;
@Mock
- private QSTileImpl mNonTile;
- @Mock
private QSPanelControllerBase.TileRecord mDndTileRecord;
@Mock
private QSLogger mQSLogger;
@@ -84,7 +79,6 @@ public class QSPanelTest extends SysuiTestCase {
@Mock
private ActivityStarter mActivityStarter;
private UiEventLoggerFake mUiEventLogger;
- private String mCachedSpecs = "";
@Before
public void setup() throws Exception {
@@ -113,8 +107,6 @@ public class QSPanelTest extends SysuiTestCase {
when(dndTile.getTileSpec()).thenReturn("dnd");
when(mHost.getTiles()).thenReturn(Collections.emptyList());
when(mHost.createTileView(any(), anyBoolean())).thenReturn(mQSTileView);
-
- mQsPanel.setCustomizer(mCustomizer);
mQsPanel.addTile(mDndTileRecord);
mQsPanel.setCallback(mCallback);
});
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index c82aee48ab91..6fa6f31984f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -23,8 +23,9 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.Context;
import android.content.pm.UserInfo;
+import android.os.Handler;
+import android.os.Looper;
import android.provider.Settings;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -38,16 +39,18 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.SecurityController;
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;
/*
* Compile and run the whole SystemUI test suite:
@@ -73,22 +76,23 @@ public class QSSecurityFooterTest extends SysuiTestCase {
private TextView mFooterText;
private TestableImageView mFooterIcon;
private QSSecurityFooter mFooter;
- private SecurityController mSecurityController = mock(SecurityController.class);
+ @Mock
+ private SecurityController mSecurityController;
+ @Mock
private UserTracker mUserTracker;
+ @Mock
+ private ActivityStarter mActivityStarter;
@Before
public void setUp() {
- mDependency.injectTestDependency(SecurityController.class, mSecurityController);
- mDependency.injectTestDependency(Dependency.BG_LOOPER,
- TestableLooper.get(this).getLooper());
- mUserTracker = mock(UserTracker.class);
+ MockitoAnnotations.initMocks(this);
+ Looper looper = TestableLooper.get(this).getLooper();
when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class));
- mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE,
- new LayoutInflaterBuilder(mContext)
- .replace("ImageView", TestableImageView.class)
- .build());
- mFooter = new QSSecurityFooter(null, mContext, mUserTracker);
- mRootView = (ViewGroup) mFooter.getView();
+ mRootView = (ViewGroup) new LayoutInflaterBuilder(mContext)
+ .replace("ImageView", TestableImageView.class)
+ .build().inflate(R.layout.quick_settings_footer, null, false);
+ mFooter = new QSSecurityFooter(mRootView, mContext, mUserTracker, new Handler(looper),
+ mActivityStarter, mSecurityController, looper);
mFooterText = mRootView.findViewById(R.id.footer_text);
mFooterIcon = mRootView.findViewById(R.id.footer_icon);
mFooter.setHostEnvironment(null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index 26b5d26387b4..d1cc75708a19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -21,6 +21,7 @@ import android.testing.AndroidTestingRunner
import android.view.View
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.colorextraction.SysuiColorExtractor
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.demomode.DemoModeController
@@ -89,6 +90,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
@Mock
private lateinit var privacyLogger: PrivacyLogger
@Mock
+ private lateinit var colorExtractor: SysuiColorExtractor
+ @Mock
private lateinit var iconContainer: StatusIconContainer
@Mock
private lateinit var qsCarrierGroup: QSCarrierGroup
@@ -127,7 +130,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
userTracker,
quickQSPanelController,
qsCarrierGroupControllerBuilder,
- privacyLogger
+ privacyLogger,
+ colorExtractor
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
index 204de929e331..3d53062d7d02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
@@ -15,7 +15,6 @@
package com.android.systemui.qs.customize;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
@@ -31,6 +30,8 @@ import com.android.systemui.qs.QSTileHost;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.util.Collections;
@@ -40,17 +41,20 @@ import java.util.Collections;
public class TileAdapterTest extends SysuiTestCase {
private TileAdapter mTileAdapter;
+ @Mock
+ private QSTileHost mQSTileHost;
@Before
public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
TestableLooper.get(this).runWithLooper(() -> mTileAdapter =
- new TileAdapter(mContext, new UiEventLoggerFake()));
+ new TileAdapter(mContext, mQSTileHost, new UiEventLoggerFake()));
}
@Test
public void testResetNotifiesHost() {
- QSTileHost host = mock(QSTileHost.class);
- mTileAdapter.resetTileSpecs(host, Collections.emptyList());
- verify(host).changeTiles(any(), any());
+ mTileAdapter.resetTileSpecs(Collections.emptyList());
+ verify(mQSTileHost).changeTiles(any(), any());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
new file mode 100644
index 000000000000..78af20f9db31
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.qs.tiles;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.provider.Settings;
+import android.service.quicksettings.Tile;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.settings.FakeSettings;
+
+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(setAsMainLooper = true)
+@SmallTest
+public class ReduceBrightColorsTileTest extends SysuiTestCase {
+ @Mock
+ private QSTileHost mHost;
+ @Mock
+ private MetricsLogger mMetricsLogger;
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+ @Mock
+ private ActivityStarter mActivityStarter;
+ @Mock
+ private QSLogger mQSLogger;
+ @Mock
+ private UserTracker mUserTracker;
+
+ private FakeSettings mFakeSettings;
+ private TestableLooper mTestableLooper;
+ private ReduceBrightColorsTile mTile;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mTestableLooper = TestableLooper.get(this);
+
+ when(mHost.getContext()).thenReturn(mContext);
+ mFakeSettings = new FakeSettings();
+
+ mTile = new ReduceBrightColorsTile(
+ mHost,
+ mTestableLooper.getLooper(),
+ new Handler(mTestableLooper.getLooper()),
+ mMetricsLogger,
+ mStatusBarStateController,
+ mActivityStarter,
+ mQSLogger,
+ mUserTracker,
+ mFakeSettings
+ );
+ }
+
+ @Test
+ public void testNotActive() {
+ mTile.refreshState();
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_INACTIVE, mTile.getState().state);
+ assertEquals(mTile.getState().label.toString(),
+ mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
+ assertEquals(mTile.getState().secondaryLabel.toString(), "");
+ }
+
+ @Test
+ public void testActive() {
+ mFakeSettings.putIntForUser(
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED,
+ 1,
+ mUserTracker.getUserId());
+ mTile.refreshState();
+ mTestableLooper.processAllMessages();
+
+ assertActiveState();
+ }
+
+ @Test
+ public void testActive_clicked_isActive() {
+ mTile.refreshState();
+ mTestableLooper.processAllMessages();
+ // Validity check
+ assertEquals(Tile.STATE_INACTIVE, mTile.getState().state);
+
+ mTile.handleClick();
+ mTile.refreshState();
+ mTestableLooper.processAllMessages();
+
+ assertActiveState();
+ }
+
+ private void assertActiveState() {
+ assertEquals(Tile.STATE_ACTIVE, mTile.getState().state);
+ assertEquals(mTile.getState().label.toString(),
+ mContext.getString(R.string.quick_settings_reduce_bright_colors_label));
+
+ final int intensity = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0, mUserTracker.getUserId());
+
+ assertEquals(
+ mContext.getString(
+ R.string.quick_settings_reduce_bright_colors_secondary_label, intensity),
+ mTile.getState().secondaryLabel.toString());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
index de176b84ac4c..9a1126f2aa3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
@@ -24,14 +24,12 @@ import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASO
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.app.PendingIntent;
import android.content.Context;
@@ -54,8 +52,6 @@ import org.mockito.stubbing.Answer;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@RunWith(AndroidTestingRunner.class)
@@ -67,8 +63,6 @@ public class ActionProxyReceiverTest extends SysuiTestCase {
@Mock
private ActivityManagerWrapper mMockActivityManagerWrapper;
@Mock
- private Future mMockFuture;
- @Mock
private ScreenshotSmartActions mMockScreenshotSmartActions;
@Mock
private PendingIntent mMockPendingIntent;
@@ -80,9 +74,6 @@ public class ActionProxyReceiverTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mIntent = new Intent(mContext, ActionProxyReceiver.class)
.putExtra(ScreenshotController.EXTRA_ACTION_INTENT, mMockPendingIntent);
-
- when(mMockActivityManagerWrapper.closeSystemWindows(anyString())).thenReturn(mMockFuture);
- when(mMockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(null);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java
new file mode 100644
index 000000000000..a75c39c33f14
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeScrollCaptureConnection.java
@@ -0,0 +1,142 @@
+/*
+ * 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.screenshot;
+
+import android.content.pm.ActivityInfo;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.HardwareRenderer;
+import android.graphics.Paint;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RenderNode;
+import android.os.RemoteException;
+import android.view.IScrollCaptureCallbacks;
+import android.view.IScrollCaptureConnection;
+import android.view.Surface;
+
+/**
+ * An IScrollCaptureConnection which returns a sequence of solid filled rectangles in the
+ * locations requested, in alternating colors.
+ */
+class FakeScrollCaptureConnection extends IScrollCaptureConnection.Stub {
+ private final int[] mColors = {Color.RED, Color.GREEN, Color.BLUE};
+ private IScrollCaptureCallbacks mCallbacks;
+ private Surface mSurface;
+ private Paint mPaint;
+ private int mNextColor;
+ private HwuiContext mHwuiContext;
+
+ FakeScrollCaptureConnection(IScrollCaptureCallbacks cb) {
+ mCallbacks = cb;
+ }
+
+ @Override
+ public void startCapture(Surface surface) {
+ mSurface = surface;
+ mHwuiContext = new HwuiContext(false, surface);
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setStyle(Paint.Style.FILL);
+ try {
+ mCallbacks.onCaptureStarted();
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ @Override
+ public void requestImage(Rect rect) {
+ Canvas canvas = mHwuiContext.lockCanvas(rect.width(), rect.height());
+ mPaint.setColor(mColors[mNextColor]);
+ canvas.drawRect(rect, mPaint);
+ mNextColor = (mNextColor++) % mColors.length;
+ long frameNumber = mSurface.getNextFrameNumber();
+ mHwuiContext.unlockAndPost(canvas);
+ try {
+ mCallbacks.onCaptureBufferSent(frameNumber, rect);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ @Override
+ public void endCapture() {
+ try {
+ mCallbacks.onConnectionClosed();
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ } finally {
+ mHwuiContext.destroy();
+ mSurface = null;
+ mCallbacks = null;
+ }
+ }
+
+ // From android.view.Surface, but issues render requests synchronously with waitForPresent(true)
+ private static final class HwuiContext {
+ private final RenderNode mRenderNode;
+ private final HardwareRenderer mHardwareRenderer;
+ private RecordingCanvas mCanvas;
+ private final boolean mIsWideColorGamut;
+
+ HwuiContext(boolean isWideColorGamut, Surface surface) {
+ mRenderNode = RenderNode.create("HwuiCanvas", null);
+ mRenderNode.setClipToBounds(false);
+ mRenderNode.setForceDarkAllowed(false);
+ mIsWideColorGamut = isWideColorGamut;
+
+ mHardwareRenderer = new HardwareRenderer();
+ mHardwareRenderer.setContentRoot(mRenderNode);
+ mHardwareRenderer.setSurface(surface, true);
+ mHardwareRenderer.setColorMode(
+ isWideColorGamut
+ ? ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT
+ : ActivityInfo.COLOR_MODE_DEFAULT);
+ mHardwareRenderer.setLightSourceAlpha(0.0f, 0.0f);
+ mHardwareRenderer.setLightSourceGeometry(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+
+ Canvas lockCanvas(int width, int height) {
+ if (mCanvas != null) {
+ throw new IllegalStateException("Surface was already locked!");
+ }
+ mCanvas = mRenderNode.beginRecording(width, height);
+ return mCanvas;
+ }
+
+ void unlockAndPost(Canvas canvas) {
+ if (canvas != mCanvas) {
+ throw new IllegalArgumentException("canvas object must be the same instance that "
+ + "was previously returned by lockCanvas");
+ }
+ mRenderNode.endRecording();
+ mCanvas = null;
+ mHardwareRenderer.createRenderRequest()
+ .setVsyncTime(System.nanoTime())
+ .setWaitForPresent(true) // sync!
+ .syncAndDraw();
+ }
+
+ void destroy() {
+ mHardwareRenderer.destroy();
+ }
+
+ boolean isWideColorGamut() {
+ return mIsWideColorGamut;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
new file mode 100644
index 000000000000..4aa730efa91e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.screenshot;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import static java.util.Objects.requireNonNull;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.os.RemoteException;
+import android.testing.AndroidTestingRunner;
+import android.view.Display;
+import android.view.IScrollCaptureCallbacks;
+import android.view.IWindowManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.screenshot.ScrollCaptureClient.CaptureResult;
+import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
+import com.android.systemui.screenshot.ScrollCaptureClient.Session;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.stubbing.Answer;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class ScrollCaptureClientTest extends SysuiTestCase {
+ private Context mContext;
+ private IWindowManager mWm;
+
+ @Spy private TestableConsumer<Session> mSessionConsumer;
+ @Spy private TestableConsumer<Connection> mConnectionConsumer;
+ @Spy private TestableConsumer<CaptureResult> mResultConsumer;
+ @Mock private Runnable mRunnable;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ DisplayManager displayManager = requireNonNull(
+ context.getSystemService(DisplayManager.class));
+ mContext = context.createDisplayContext(
+ displayManager.getDisplay(Display.DEFAULT_DISPLAY));
+ mWm = mock(IWindowManager.class);
+ }
+
+ @Test
+ public void testBasicClientFlow() throws RemoteException {
+ doAnswer((Answer<Void>) invocation -> {
+ IScrollCaptureCallbacks cb = invocation.getArgument(3);
+ cb.onConnected(
+ new FakeScrollCaptureConnection(cb),
+ /* scrollBounds */ new Rect(0, 0, 100, 100),
+ /* positionInWindow */ new Point(0, 0));
+ return null;
+ }).when(mWm).requestScrollCapture(/* displayId */ anyInt(), /* token */ isNull(),
+ /* taskId */ anyInt(), any(IScrollCaptureCallbacks.class));
+
+ // Create client
+ ScrollCaptureClient client = new ScrollCaptureClient(mContext, mWm);
+
+ client.request(Display.DEFAULT_DISPLAY, mConnectionConsumer);
+ verify(mConnectionConsumer, timeout(100)).accept(any(Connection.class));
+
+ Connection conn = mConnectionConsumer.getValue();
+
+ conn.start(5, mSessionConsumer);
+ verify(mSessionConsumer, timeout(100)).accept(any(Session.class));
+
+ Session session = mSessionConsumer.getValue();
+ Rect request = new Rect(0, 0, session.getMaxTileWidth(), session.getMaxTileHeight());
+
+ session.requestTile(request, mResultConsumer);
+ verify(mResultConsumer, timeout(100)).accept(any(CaptureResult.class));
+
+ CaptureResult result = mResultConsumer.getValue();
+ assertThat(result.requested).isEqualTo(request);
+ assertThat(result.captured).isEqualTo(result.requested);
+ assertThat(result.image).isNotNull();
+
+ session.end(mRunnable);
+ verify(mRunnable, timeout(100)).run();
+
+ // TODO verify image
+ // TODO test threading
+ // TODO test failures
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TestableConsumer.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TestableConsumer.java
new file mode 100644
index 000000000000..a554e5f583e7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TestableConsumer.java
@@ -0,0 +1,33 @@
+/*
+ * 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.screenshot;
+
+import java.util.function.Consumer;
+
+/** Accepts and retains the most recent value for verification */
+class TestableConsumer<T> implements Consumer<T> {
+ T mValue;
+
+ @Override
+ public void accept(T t) {
+ mValue = t;
+ }
+
+ public T getValue() {
+ return mValue;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt
new file mode 100644
index 000000000000..0cc2072b367f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderTest.kt
@@ -0,0 +1,316 @@
+/*
+ * 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.settings.brightness
+
+import android.testing.AndroidTestingRunner
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import android.widget.CompoundButton
+import android.widget.SeekBar
+import androidx.test.filters.SmallTest
+import com.android.settingslib.RestrictedLockUtils
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.policy.BrightnessMirrorController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.isNull
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.notNull
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class BrightnessSliderTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var rootView: View
+ @Mock
+ private lateinit var brightnessSliderView: BrightnessSliderView
+ @Mock
+ private lateinit var enforcedAdmin: RestrictedLockUtils.EnforcedAdmin
+ @Mock
+ private lateinit var mirrorController: BrightnessMirrorController
+ @Mock
+ private lateinit var mirror: ToggleSlider
+ @Mock
+ private lateinit var motionEvent: MotionEvent
+ @Mock
+ private lateinit var listener: ToggleSlider.Listener
+
+ @Captor
+ private lateinit var seekBarChangeCaptor: ArgumentCaptor<SeekBar.OnSeekBarChangeListener>
+ @Mock
+ private lateinit var seekBar: SeekBar
+ @Captor
+ private lateinit var checkedChangeCaptor: ArgumentCaptor<CompoundButton.OnCheckedChangeListener>
+ @Mock
+ private lateinit var compoundButton: CompoundButton
+
+ private lateinit var mController: BrightnessSlider
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ whenever(mirrorController.toggleSlider).thenReturn(mirror)
+ whenever(motionEvent.copy()).thenReturn(motionEvent)
+
+ mController = BrightnessSlider(rootView, brightnessSliderView, true)
+ mController.init()
+ mController.setOnChangedListener(listener)
+ }
+
+ @After
+ fun tearDown() {
+ mController.onViewDetached()
+ }
+
+ @Test
+ fun testListenersAddedOnAttach() {
+ mController.onViewAttached()
+
+ verify(brightnessSliderView).setOnCheckedChangeListener(notNull())
+ verify(brightnessSliderView).setOnSeekBarChangeListener(notNull())
+ }
+
+ @Test
+ fun testAllListenersRemovedOnDettach() {
+ mController.onViewAttached()
+ mController.onViewDetached()
+
+ verify(brightnessSliderView).setOnSeekBarChangeListener(isNull())
+ verify(brightnessSliderView).setOnCheckedChangeListener(isNull())
+ verify(brightnessSliderView).setOnDispatchTouchEventListener(isNull())
+ }
+
+ @Test
+ fun testEnforceAdminRelayed() {
+ mController.setEnforcedAdmin(enforcedAdmin)
+ verify(brightnessSliderView).setEnforcedAdmin(enforcedAdmin)
+ }
+
+ @Test
+ fun testNullMirrorControllerNotTrackingTouch() {
+ mController.setMirrorControllerAndMirror(null)
+
+ verify(brightnessSliderView, never()).max
+ verify(brightnessSliderView, never()).value
+ verify(brightnessSliderView, never()).isChecked
+ verify(brightnessSliderView).setOnDispatchTouchEventListener(isNull())
+ }
+
+ @Test
+ fun testNullMirrorNotTrackingTouch() {
+ whenever(mirrorController.toggleSlider).thenReturn(null)
+
+ mController.setMirrorControllerAndMirror(mirrorController)
+
+ verify(brightnessSliderView, never()).max
+ verify(brightnessSliderView, never()).value
+ verify(brightnessSliderView, never()).isChecked
+ verify(brightnessSliderView).setOnDispatchTouchEventListener(isNull())
+ }
+
+ @Test
+ fun testSettingMirrorControllerReliesValuesAndSetsTouchTracking() {
+ val maxValue = 100
+ val progress = 30
+ val checked = true
+ whenever(brightnessSliderView.max).thenReturn(maxValue)
+ whenever(brightnessSliderView.value).thenReturn(progress)
+ whenever(brightnessSliderView.isChecked).thenReturn(checked)
+
+ mController.setMirrorControllerAndMirror(mirrorController)
+
+ verify(mirror).max = maxValue
+ verify(mirror).isChecked = checked
+ verify(mirror).value = progress
+ verify(brightnessSliderView).setOnDispatchTouchEventListener(notNull())
+ }
+
+ @Test
+ fun testSettingMirrorWhenNotUseMirrorIsNoOp() {
+ val otherController = BrightnessSlider(rootView, brightnessSliderView, false)
+ otherController.init()
+
+ otherController.setMirrorControllerAndMirror(mirrorController)
+
+ verify(brightnessSliderView, never()).max
+ verify(brightnessSliderView, never()).value
+ verify(brightnessSliderView, never()).isChecked
+ verify(brightnessSliderView, never()).setOnDispatchTouchEventListener(
+ any(BrightnessSliderView.DispatchTouchEventListener::class.java))
+ }
+
+ @Test
+ fun testSetCheckedRelayed_true() {
+ mController.isChecked = true
+ verify(brightnessSliderView).isChecked = true
+ }
+
+ @Test
+ fun testSetCheckedRelayed_false() {
+ mController.isChecked = false
+ verify(brightnessSliderView).isChecked = false
+ }
+
+ @Test
+ fun testGetChecked() {
+ whenever(brightnessSliderView.isChecked).thenReturn(true)
+
+ assertThat(mController.isChecked).isTrue()
+
+ whenever(brightnessSliderView.isChecked).thenReturn(false)
+
+ assertThat(mController.isChecked).isFalse()
+ }
+
+ @Test
+ fun testSetMaxRelayed() {
+ mController.max = 120
+ verify(brightnessSliderView).max = 120
+ }
+
+ @Test
+ fun testGetMax() {
+ whenever(brightnessSliderView.max).thenReturn(40)
+
+ assertThat(mController.max).isEqualTo(40)
+ }
+
+ @Test
+ fun testSetValue() {
+ mController.value = 30
+ verify(brightnessSliderView).value = 30
+ }
+
+ @Test
+ fun testGetValue() {
+ whenever(brightnessSliderView.value).thenReturn(20)
+
+ assertThat(mController.value).isEqualTo(20)
+ }
+
+ @Test
+ fun testMirrorEventWithMirror() {
+ mController.setMirrorControllerAndMirror(mirrorController)
+
+ mController.mirrorTouchEvent(motionEvent)
+
+ verify(mirror).mirrorTouchEvent(motionEvent)
+ verify(brightnessSliderView, never()).dispatchTouchEvent(any(MotionEvent::class.java))
+ }
+
+ @Test
+ fun testMirrorEventWithoutMirror_dispatchToView() {
+ mController.mirrorTouchEvent(motionEvent)
+
+ verify(brightnessSliderView).dispatchTouchEvent(motionEvent)
+ }
+
+ @Test
+ fun testSeekBarProgressChanged() {
+ mController.onViewAttached()
+ whenever(brightnessSliderView.isChecked).thenReturn(true)
+
+ verify(brightnessSliderView).setOnSeekBarChangeListener(capture(seekBarChangeCaptor))
+
+ seekBarChangeCaptor.value.onProgressChanged(seekBar, 23, true)
+
+ verify(listener).onChanged(anyBoolean(), eq(true), eq(23), eq(false))
+ }
+
+ @Test
+ fun testSeekBarTrackingStarted() {
+ val parent = mock(ViewGroup::class.java)
+ whenever(brightnessSliderView.value).thenReturn(42)
+ whenever(brightnessSliderView.parent).thenReturn(parent)
+ whenever(brightnessSliderView.isChecked).thenReturn(true)
+
+ mController.onViewAttached()
+ mController.setMirrorControllerAndMirror(mirrorController)
+ verify(brightnessSliderView).setOnSeekBarChangeListener(capture(seekBarChangeCaptor))
+
+ seekBarChangeCaptor.value.onStartTrackingTouch(seekBar)
+
+ verify(listener).onChanged(eq(true), eq(true), eq(42), eq(false))
+ verify(mirrorController).showMirror()
+ verify(mirrorController).setLocation(parent)
+ }
+
+ @Test
+ fun testSeekBarTrackingStopped() {
+ whenever(brightnessSliderView.value).thenReturn(23)
+ whenever(brightnessSliderView.isChecked).thenReturn(true)
+
+ mController.onViewAttached()
+ mController.setMirrorControllerAndMirror(mirrorController)
+ verify(brightnessSliderView).setOnSeekBarChangeListener(capture(seekBarChangeCaptor))
+
+ seekBarChangeCaptor.value.onStopTrackingTouch(seekBar)
+
+ verify(listener).onChanged(eq(false), eq(true), eq(23), eq(true))
+ verify(mirrorController).hideMirror()
+ }
+
+ @Test
+ fun testButtonCheckedChanged_false() {
+ val checked = false
+
+ mController.onViewAttached()
+ mController.setMirrorControllerAndMirror(mirrorController)
+ verify(brightnessSliderView).setOnCheckedChangeListener(capture(checkedChangeCaptor))
+
+ checkedChangeCaptor.value.onCheckedChanged(compoundButton, checked)
+
+ verify(brightnessSliderView).enableSlider(!checked)
+ verify(listener).onChanged(anyBoolean(), eq(checked), anyInt(), eq(false))
+ // Called once with false when the mirror is set
+ verify(mirror, times(2)).isChecked = checked
+ }
+
+ @Test
+ fun testButtonCheckedChanged_true() {
+ val checked = true
+
+ mController.onViewAttached()
+ mController.setMirrorControllerAndMirror(mirrorController)
+ verify(brightnessSliderView).setOnCheckedChangeListener(capture(checkedChangeCaptor))
+
+ checkedChangeCaptor.value.onCheckedChanged(compoundButton, checked)
+
+ verify(brightnessSliderView).enableSlider(!checked)
+ verify(listener).onChanged(anyBoolean(), eq(checked), anyInt(), eq(false))
+ verify(mirror).isChecked = checked
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 10eca00feec4..7fb7b8667a1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -36,7 +36,6 @@ import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.DynamicChildBindController;
@@ -54,6 +53,7 @@ import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.wm.shell.bubbles.Bubbles;
import com.google.android.collect.Lists;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index cd46dda772e3..05cf33a3729c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -42,7 +42,6 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -54,6 +53,7 @@ import com.android.systemui.statusbar.notification.people.PeopleNotificationIden
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.wm.shell.bubbles.Bubbles;
import org.junit.After;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
index c113df0b4ee7..1bfe10c5263b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NoManSimulator.java
@@ -16,8 +16,12 @@
package com.android.systemui.statusbar.notification.collection;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+
import static org.junit.Assert.assertNotNull;
+import android.app.NotificationChannel;
+import android.os.UserHandle;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
@@ -72,6 +76,17 @@ public class NoManSimulator {
}
}
+ public NotificationChannel createNotificationChannel(String id, String name) {
+ return new NotificationChannel(id, name, IMPORTANCE_DEFAULT);
+ }
+
+ public void issueChannelModification(
+ String pkg, UserHandle user, NotificationChannel channel, int modificationType) {
+ for (NotificationHandler listener : mListeners) {
+ listener.onNotificationChannelModified(pkg, user, channel, modificationType);
+ }
+ }
+
public void setRanking(String key, Ranking ranking) {
mRankings.put(key, ranking);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 4698b8e50efb..f7dfe0b434a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -76,12 +76,12 @@ import com.android.settingslib.notification.ConversationIconFactory;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.BubblesTestActivity;
import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.systemui.wmshell.BubblesTestActivity;
import org.junit.Before;
import org.junit.Rule;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 48375e02f64f..baae8fda18f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -45,8 +45,6 @@ import android.widget.RemoteViews;
import com.android.systemui.R;
import com.android.systemui.TestableDependency;
-import com.android.systemui.bubbles.Bubbles;
-import com.android.systemui.bubbles.BubblesTestActivity;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.FalsingManager;
@@ -71,6 +69,8 @@ import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.InflatedSmartReplies;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.systemui.wmshell.BubblesTestActivity;
+import com.android.wm.shell.bubbles.Bubbles;
import org.mockito.ArgumentCaptor;
@@ -432,7 +432,8 @@ public class NotificationTestHelper {
mStatusBarStateController,
mPeopleNotificationIdentifier,
mock(OnUserInteractionCallback.class),
- Optional.of(mock(BubblesManager.class)));
+ Optional.of(mock(BubblesManager.class)),
+ mock(NotificationGutsManager.class));
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 4fb45ec18178..1b05ad7f8b5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -50,7 +50,6 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.keyguard.dagger.KeyguardBouncerComponent;
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.biometrics.AuthController;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.FalsingManager;
@@ -79,8 +78,6 @@ public class KeyguardBouncerTest extends SysuiTestCase {
@Mock
private DismissCallbackRegistry mDismissCallbackRegistry;
@Mock
- private AuthController mAuthController;
- @Mock
private KeyguardHostViewController mKeyguardHostViewController;
@Mock
private KeyguardBouncer.BouncerExpansionCallback mExpansionCallback;
@@ -131,7 +128,7 @@ public class KeyguardBouncerTest extends SysuiTestCase {
final ViewGroup container = new FrameLayout(getContext());
mBouncer = new KeyguardBouncer.Factory(getContext(), mViewMediatorCallback,
- mDismissCallbackRegistry, mFalsingManager, mAuthController,
+ mDismissCallbackRegistry, mFalsingManager,
mKeyguardStateController, mKeyguardUpdateMonitor,
mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
mKeyguardBouncerComponentFactory)
@@ -210,12 +207,6 @@ public class KeyguardBouncerTest extends SysuiTestCase {
}
@Test
- public void testShow_notifiesAuthControllerStartingToShow() {
- mBouncer.show(/* resetSecuritySelection */ false);
- verify(mAuthController).onStartingToShow();
- }
-
- @Test
public void testSetExpansion_notifiesFalsingManager() {
mBouncer.ensureView();
mBouncer.setExpansion(0.5f);
@@ -246,38 +237,6 @@ public class KeyguardBouncerTest extends SysuiTestCase {
}
@Test
- public void testSetExpansion_notifiesAuthControllerFullyShown() {
- mBouncer.ensureView();
- mBouncer.setExpansion(0.1f);
- mBouncer.setExpansion(0f);
- verify(mAuthController).onFullyShown();
- }
-
- @Test
- public void testSetExpansion_notifiesAuthControllerStartingToHide() {
- mBouncer.ensureView();
- mBouncer.setExpansion(0f);
- mBouncer.setExpansion(0.1f);
- verify(mAuthController).onStartingToHide();
- }
-
- @Test
- public void testSetExpansion_notifiesAuthControllerFullyHidden() {
- mBouncer.ensureView();
- mBouncer.setExpansion(0.9f);
- mBouncer.setExpansion(1f);
- verify(mAuthController).onFullyHidden();
- }
-
- @Test
- public void testSetExpansion_negativeAuthControllerStartingToShow() {
- mBouncer.ensureView();
- mBouncer.setExpansion(1f);
- mBouncer.setExpansion(0.9f);
- verify(mAuthController, never()).onStartingToShow();
- }
-
- @Test
public void testHide_notifiesFalsingManager() {
mBouncer.hide(false);
verify(mFalsingManager).onBouncerHidden();
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 72a0258e148a..aca34242e5fa 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
@@ -32,7 +32,6 @@ 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.biometrics.AuthController;
import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -81,25 +80,21 @@ public class LockscreenIconControllerTest extends SysuiTestCase {
private Resources mResources;
@Mock
private HeadsUpManagerPhone mHeadsUpManagerPhone;
- @Mock
- private AuthController mAuthController;
private LockscreenLockIconController mLockIconController;
private OnAttachStateChangeListener mOnAttachStateChangeListener;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mAuthController.isUdfpsEnrolled()).thenReturn(false);
when(mLockIcon.getContext()).thenReturn(mContext);
mLockIconController = new LockscreenLockIconController(
mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils,
mShadeController, mAccessibilityController, mKeyguardIndicationController,
mStatusBarStateController, mConfigurationController, mNotificationWakeUpCoordinator,
mKeyguardBypassController, mDockManager, mKeyguardStateController, mResources,
- mHeadsUpManagerPhone, mAuthController);
+ mHeadsUpManagerPhone);
ArgumentCaptor<OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor =
ArgumentCaptor.forClass(OnAttachStateChangeListener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index b0086ef1d4fb..7c8b413833eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -37,7 +37,6 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -48,6 +47,7 @@ import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCal
import com.android.systemui.statusbar.notification.row.RowContentBindParams;
import com.android.systemui.statusbar.notification.row.RowContentBindStage;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.wm.shell.bubbles.Bubbles;
import org.junit.Before;
import org.junit.Rule;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
index f81672ab6a37..3e9fd5189129 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
@@ -30,12 +30,12 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.wm.shell.bubbles.Bubbles;
import org.junit.Before;
import org.junit.Rule;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index a1d419cfb6c7..858227fe7129 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -27,7 +27,6 @@ import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -35,6 +34,7 @@ import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
+import com.android.wm.shell.bubbles.Bubbles;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 3b123f65d886..e9e6b3e57b32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -21,6 +21,7 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.inOrder;
@@ -63,6 +64,7 @@ import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -204,7 +206,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- when(mAuthController.isUdfpsEnrolled()).thenReturn(false);
+ when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
when(mHeadsUpCallback.getContext()).thenReturn(mContext);
when(mView.getResources()).thenReturn(mResources);
when(mResources.getConfiguration()).thenReturn(mConfiguration);
@@ -213,6 +215,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mDisplayMetrics.density = 100;
when(mResources.getBoolean(R.bool.config_enableNotificationShadeDrag)).thenReturn(true);
when(mView.getContext()).thenReturn(getContext());
+ when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch);
when(mView.findViewById(R.id.notification_stack_scroller))
.thenReturn(mNotificationStackScrollLayout);
@@ -272,7 +275,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mKeyguardStatusViewComponentFactory,
mGroupManager,
mNotificationAreaController,
- mAuthController);
+ mAuthController,
+ new QSDetailDisplayer());
mNotificationPanelViewController.initDependencies(
mStatusBar,
mNotificationShelfController);
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 9f096dada6f2..710122d83b22 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
@@ -83,7 +83,6 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoModeController;
@@ -98,6 +97,7 @@ import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -146,6 +146,7 @@ import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
@@ -260,6 +261,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private PhoneStatusBarPolicy mPhoneStatusBarPolicy;
@Mock private DemoModeController mDemoModeController;
@Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy;
+ @Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
private ShadeController mShadeController;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private InitController mInitController = new InitController();
@@ -337,7 +339,7 @@ public class StatusBarTest extends SysuiTestCase {
mShadeController = new ShadeControllerImpl(mCommandQueue,
mStatusBarStateController, mNotificationShadeWindowController,
mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class),
- () -> mStatusBar, () -> mAssistManager, Optional.of(() -> mBubbles));
+ () -> mStatusBar, () -> mAssistManager, Optional.of(mBubbles));
mStatusBar = new StatusBar(
mContext,
@@ -419,7 +421,8 @@ public class StatusBarTest extends SysuiTestCase {
mDemoModeController,
mNotificationShadeDepthControllerLazy,
mStatusBarTouchableRegionManager,
- mNotificationIconAreaController);
+ mNotificationIconAreaController,
+ mBrightnessSliderFactory);
when(mNotificationShadeWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
mLockIconContainer);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
index c99deb606459..edaff5ff0f10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
@@ -15,22 +15,24 @@
*/
package com.android.systemui.theme;
-import static com.android.systemui.theme.ThemeOverlayManager.ANDROID_PACKAGE;
-import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_COLOR;
-import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_FONT;
-import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_ANDROID;
-import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_LAUNCHER;
-import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_SETTINGS;
-import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_SYSUI;
-import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_ICON_THEME_PICKER;
-import static com.android.systemui.theme.ThemeOverlayManager.OVERLAY_CATEGORY_SHAPE;
-import static com.android.systemui.theme.ThemeOverlayManager.SETTINGS_PACKAGE;
-import static com.android.systemui.theme.ThemeOverlayManager.SYSTEM_USER_CATEGORIES;
-import static com.android.systemui.theme.ThemeOverlayManager.SYSUI_PACKAGE;
-import static com.android.systemui.theme.ThemeOverlayManager.THEME_CATEGORIES;
+import static com.android.systemui.theme.ThemeOverlayApplier.ANDROID_PACKAGE;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_FONT;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_ANDROID;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_LAUNCHER;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_SETTINGS;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_SYSUI;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ICON_THEME_PICKER;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SHAPE;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
+import static com.android.systemui.theme.ThemeOverlayApplier.SETTINGS_PACKAGE;
+import static com.android.systemui.theme.ThemeOverlayApplier.SYSTEM_USER_CATEGORIES;
+import static com.android.systemui.theme.ThemeOverlayApplier.SYSUI_PACKAGE;
+import static com.android.systemui.theme.ThemeOverlayApplier.THEME_CATEGORIES;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -44,6 +46,7 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
import com.google.android.collect.Maps;
import com.google.common.collect.Lists;
@@ -63,7 +66,7 @@ import java.util.Set;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class ThemeOverlayManagerTest extends SysuiTestCase {
+public class ThemeOverlayApplierTest extends SysuiTestCase {
private static final String TEST_DISABLED_PREFIX = "com.example.";
private static final String TEST_ENABLED_PREFIX = "com.example.enabled.";
@@ -82,26 +85,32 @@ public class ThemeOverlayManagerTest extends SysuiTestCase {
@Mock
OverlayManager mOverlayManager;
+ @Mock
+ DumpManager mDumpManager;
- private ThemeOverlayManager mManager;
+ private ThemeOverlayApplier mManager;
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
- mManager = new ThemeOverlayManager(mOverlayManager, MoreExecutors.directExecutor(),
- LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE);
+ mManager = new ThemeOverlayApplier(mOverlayManager, MoreExecutors.directExecutor(),
+ LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE, mDumpManager);
when(mOverlayManager.getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM))
.thenReturn(Lists.newArrayList(
- createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_COLOR,
- ANDROID_PACKAGE, OVERLAY_CATEGORY_COLOR, false),
+ createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ACCENT_COLOR,
+ ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, false),
+ createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE,
+ ANDROID_PACKAGE, OVERLAY_CATEGORY_SYSTEM_PALETTE, false),
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_FONT,
ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, false),
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_SHAPE,
ANDROID_PACKAGE, OVERLAY_CATEGORY_SHAPE, false),
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_ICON_ANDROID,
ANDROID_PACKAGE, OVERLAY_CATEGORY_ICON_ANDROID, false),
- createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_COLOR,
- ANDROID_PACKAGE, OVERLAY_CATEGORY_COLOR, true),
+ createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ACCENT_COLOR,
+ ANDROID_PACKAGE, OVERLAY_CATEGORY_ACCENT_COLOR, true),
+ createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SYSTEM_PALETTE,
+ ANDROID_PACKAGE, OVERLAY_CATEGORY_SYSTEM_PALETTE, true),
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_FONT,
ANDROID_PACKAGE, OVERLAY_CATEGORY_FONT, true),
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_SHAPE,
@@ -132,6 +141,8 @@ public class ThemeOverlayManagerTest extends SysuiTestCase {
THEMEPICKER_PACKAGE, OVERLAY_CATEGORY_ICON_THEME_PICKER, false),
createOverlayInfo(TEST_ENABLED_PREFIX + OVERLAY_CATEGORY_ICON_THEME_PICKER,
THEMEPICKER_PACKAGE, OVERLAY_CATEGORY_ICON_THEME_PICKER, true)));
+ clearInvocations(mOverlayManager);
+ verify(mDumpManager).registerDumpable(any(), any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
new file mode 100644
index 000000000000..aee884022d95
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -0,0 +1,173 @@
+/*
+ * 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.theme;
+
+import static com.android.systemui.theme.ThemeOverlayApplier.MONET_ACCENT_COLOR_PACKAGE;
+import static com.android.systemui.theme.ThemeOverlayApplier.MONET_SYSTEM_PALETTE_PACKAGE;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_ACCENT_COLOR;
+import static com.android.systemui.theme.ThemeOverlayApplier.OVERLAY_CATEGORY_SYSTEM_PALETTE;
+import static com.android.systemui.theme.ThemeOverlayController.USE_LOCK_SCREEN_WALLPAPER;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.app.WallpaperColors;
+import android.app.WallpaperManager;
+import android.graphics.Color;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.settings.SecureSettings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class ThemeOverlayControllerTest extends SysuiTestCase {
+
+ private ThemeOverlayController mThemeOverlayController;
+ @Mock
+ private Executor mBgExecutor;
+ @Mock
+ private Executor mMainExecutor;
+ @Mock
+ private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ private Handler mBgHandler;
+ @Mock
+ private ThemeOverlayApplier mThemeOverlayApplier;
+ @Mock
+ private SecureSettings mSecureSettings;
+ @Mock
+ private WallpaperManager mWallpaperManager;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private DumpManager mDumpManager;
+ @Captor
+ private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallback;
+ @Captor
+ private ArgumentCaptor<WallpaperManager.OnColorsChangedListener> mColorsListener;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mThemeOverlayController = new ThemeOverlayController(null /* context */,
+ mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier,
+ mSecureSettings, mWallpaperManager, mUserManager, mKeyguardStateController,
+ mDumpManager);
+
+ mThemeOverlayController.start();
+ if (USE_LOCK_SCREEN_WALLPAPER) {
+ verify(mKeyguardStateController).addCallback(
+ mKeyguardStateControllerCallback.capture());
+ }
+ verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null),
+ eq(UserHandle.USER_ALL));
+ verify(mDumpManager).registerDumpable(any(), any());
+
+ List<Integer> colorList = List.of(Color.RED, Color.BLUE);
+ when(mThemeOverlayApplier.getAvailableAccentColors()).thenReturn(colorList);
+ when(mThemeOverlayApplier.getAvailableSystemColors()).thenReturn(colorList);
+ }
+
+ @Test
+ public void start_checksWallpaper() {
+ ArgumentCaptor<Runnable> registrationRunnable = ArgumentCaptor.forClass(Runnable.class);
+ verify(mBgExecutor).execute(registrationRunnable.capture());
+
+ registrationRunnable.getValue().run();
+ verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_LOCK));
+ verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_SYSTEM));
+ }
+
+ @Test
+ public void onWallpaperColorsChanged_setsTheme() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ ArgumentCaptor<Map<String, String>> themeOverlays = ArgumentCaptor.forClass(Map.class);
+
+ verify(mThemeOverlayApplier).getAvailableSystemColors();
+ verify(mThemeOverlayApplier).getAvailableAccentColors();
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(themeOverlays.capture(), any());
+
+ // Assert that we received the colors that we were expecting
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
+ .isEqualTo(MONET_SYSTEM_PALETTE_PACKAGE
+ + Integer.toHexString(Color.RED).toUpperCase());
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR))
+ .isEqualTo(MONET_ACCENT_COLOR_PACKAGE
+ + Integer.toHexString(Color.BLUE).toUpperCase());
+
+ // Should not ask again if changed to same value
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ verifyNoMoreInteractions(mThemeOverlayApplier);
+ }
+
+ @Test
+ public void onWallpaperColorsChanged_preservesWallpaperPickerTheme() {
+ // Should ask for a new theme when wallpaper colors change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+
+ String jsonString =
+ "{\"android.theme.customization.system_palette\":\"override.package.name\"}";
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ ArgumentCaptor<Map<String, String>> themeOverlays = ArgumentCaptor.forClass(Map.class);
+
+ verify(mThemeOverlayApplier).getAvailableSystemColors();
+ verify(mThemeOverlayApplier).getAvailableAccentColors();
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(themeOverlays.capture(), any());
+
+ // Assert that we received the colors that we were expecting
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
+ .isEqualTo("override.package.name");
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 88d04011e738..230aeab4183c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -45,9 +45,6 @@ import android.app.INotificationManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.pm.LauncherApps;
-import android.content.res.Configuration;
-import android.graphics.Insets;
-import android.graphics.Rect;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.face.FaceManager;
import android.os.Handler;
@@ -64,14 +61,6 @@ import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.Bubble;
-import com.android.systemui.bubbles.BubbleData;
-import com.android.systemui.bubbles.BubbleDataRepository;
-import com.android.systemui.bubbles.BubbleEntry;
-import com.android.systemui.bubbles.BubbleLogger;
-import com.android.systemui.bubbles.BubblePositioner;
-import com.android.systemui.bubbles.BubbleStackView;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -102,6 +91,14 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.bubbles.Bubble;
+import com.android.wm.shell.bubbles.BubbleData;
+import com.android.wm.shell.bubbles.BubbleDataRepository;
+import com.android.wm.shell.bubbles.BubbleEntry;
+import com.android.wm.shell.bubbles.BubbleLogger;
+import com.android.wm.shell.bubbles.BubbleOverflow;
+import com.android.wm.shell.bubbles.BubbleStackView;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.google.common.collect.ImmutableList;
@@ -206,8 +203,8 @@ public class BubblesTest extends SysuiTestCase {
private WindowManagerShellWrapper mWindowManagerShellWrapper;
@Mock
private BubbleLogger mBubbleLogger;
- @Mock
- private BubblePositioner mPositioner;
+
+ private TestableBubblePositioner mPositioner;
private BubbleData mBubbleData;
@@ -255,12 +252,8 @@ public class BubblesTest extends SysuiTestCase {
mSysUiStateBubblesExpanded =
(sysUiFlags & QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED) != 0);
- mBubbleData = new BubbleData(mContext, mBubbleLogger);
-
- Rect availableRect = new Rect(0, 0, 1000, 5000);
- when(mPositioner.getAvailableRect()).thenReturn(availableRect);
- when(mPositioner.getOrientation()).thenReturn(Configuration.ORIENTATION_PORTRAIT);
- when(mPositioner.getInsets()).thenReturn(Insets.of(0, 0, 0, 0));
+ mPositioner = new TestableBubblePositioner(mContext, mWindowManager);
+ mBubbleData = new BubbleData(mContext, mBubbleLogger, mPositioner);
TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
@@ -585,7 +578,7 @@ public class BubblesTest extends SysuiTestCase {
}
@Test
- public void testRemoveLastExpandedCollapses() {
+ public void testRemoveLastExpanded_selectsOverflow() {
// Mark it as a bubble and add it explicitly
mEntryListener.onPendingEntryAdded(mRow.getEntry());
mEntryListener.onPendingEntryAdded(mRow2.getEntry());
@@ -625,10 +618,38 @@ public class BubblesTest extends SysuiTestCase {
stackView.getExpandedBubble().getKey()).getKey(),
Bubbles.DISMISS_USER_GESTURE);
- // Make sure state changes and collapse happens
+ // Overflow should be selected
+ assertEquals(mBubbleData.getSelectedBubble().getKey(), BubbleOverflow.KEY);
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true, BubbleOverflow.KEY);
+ assertTrue(mBubbleController.hasBubbles());
+ assertTrue(mSysUiStateBubblesExpanded);
+ }
+
+ @Test
+ public void testRemoveLastExpandedEmptyOverflow_collapses() {
+ // Mark it as a bubble and add it explicitly
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
+
+ // Expand
+ BubbleStackView stackView = mBubbleController.getStackView();
+ mBubbleData.setExpanded(true);
+
+ assertTrue(mSysUiStateBubblesExpanded);
+ assertTrue(mBubbleController.isStackExpanded());
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+
+ // Block the bubble so it won't be in the overflow
+ mBubbleController.removeBubble(
+ mBubbleData.getBubbleInStackWithKey(
+ stackView.getExpandedBubble().getKey()).getKey(),
+ Bubbles.DISMISS_BLOCKED);
+
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
- assertFalse(mBubbleController.hasBubbles());
+ // We should be collapsed
+ verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
+ assertFalse(mBubbleController.hasBubbles());
assertFalse(mSysUiStateBubblesExpanded);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.java
index 43d2ad1dfe0a..f4d96a123624 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTestActivity.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.bubbles;
+package com.android.systemui.wmshell;
import android.app.Activity;
import android.content.Intent;
@@ -27,8 +27,7 @@ import com.android.systemui.R;
*/
public class BubblesTestActivity extends Activity {
- public static final String BUBBLE_ACTIVITY_OPENED =
- "com.android.systemui.bubbles.BUBBLE_ACTIVITY_OPENED";
+ public static final String BUBBLE_ACTIVITY_OPENED = "BUBBLE_ACTIVITY_OPENED";
@Override
public void onCreate(Bundle savedInstanceState) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index 99c8ca417778..bbcc30abe315 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -42,9 +42,6 @@ import android.app.INotificationManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.pm.LauncherApps;
-import android.content.res.Configuration;
-import android.graphics.Insets;
-import android.graphics.Rect;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.PowerManager;
@@ -60,13 +57,6 @@ import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.bubbles.BubbleData;
-import com.android.systemui.bubbles.BubbleDataRepository;
-import com.android.systemui.bubbles.BubbleEntry;
-import com.android.systemui.bubbles.BubbleLogger;
-import com.android.systemui.bubbles.BubblePositioner;
-import com.android.systemui.bubbles.BubbleStackView;
-import com.android.systemui.bubbles.Bubbles;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -95,6 +85,13 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.bubbles.BubbleData;
+import com.android.wm.shell.bubbles.BubbleDataRepository;
+import com.android.wm.shell.bubbles.BubbleEntry;
+import com.android.wm.shell.bubbles.BubbleLogger;
+import com.android.wm.shell.bubbles.BubbleOverflow;
+import com.android.wm.shell.bubbles.BubbleStackView;
+import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.common.FloatingContentCoordinator;
import org.junit.Before;
@@ -188,8 +185,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
private WindowManagerShellWrapper mWindowManagerShellWrapper;
@Mock
private BubbleLogger mBubbleLogger;
- @Mock
- private BubblePositioner mPositioner;
+
+ private TestableBubblePositioner mPositioner;
private BubbleData mBubbleData;
@@ -224,12 +221,8 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
- mBubbleData = new BubbleData(mContext, mBubbleLogger);
-
- Rect availableRect = new Rect(0, 0, 1000, 5000);
- when(mPositioner.getAvailableRect()).thenReturn(availableRect);
- when(mPositioner.getOrientation()).thenReturn(Configuration.ORIENTATION_PORTRAIT);
- when(mPositioner.getInsets()).thenReturn(Insets.of(0, 0, 0, 0));
+ mPositioner = new TestableBubblePositioner(mContext, mWindowManager);
+ mBubbleData = new BubbleData(mContext, mBubbleLogger, mPositioner);
TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
@@ -516,7 +509,7 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
}
@Test
- public void testRemoveLastExpandedCollapses() {
+ public void testRemoveLastExpanded_selectsOverflow() {
// Mark it as a bubble and add it explicitly
mEntryListener.onEntryAdded(mRow.getEntry());
mEntryListener.onEntryAdded(mRow2.getEntry());
@@ -554,11 +547,39 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
stackView.getExpandedBubble().getKey()).getKey(),
Bubbles.DISMISS_USER_GESTURE);
- // Make sure state changes and collapse happens
+ // Overflow should be selected
+ assertEquals(mBubbleData.getSelectedBubble().getKey(), BubbleOverflow.KEY);
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true, BubbleOverflow.KEY);
+ assertTrue(mBubbleController.hasBubbles());
+ }
+
+ @Test
+ public void testRemoveLastExpandedEmptyOverflow_collapses() {
+ // Mark it as a bubble and add it explicitly
+ mEntryListener.onEntryAdded(mRow.getEntry());
+ mBubbleController.updateBubble(mBubbleEntry);
+
+ // Expand
+ BubbleStackView stackView = mBubbleController.getStackView();
+ mBubbleData.setExpanded(true);
+
+ assertTrue(mBubbleController.isStackExpanded());
+ verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+
+ // Block the bubble so it won't be in the overflow
+ mBubbleController.removeBubble(
+ mBubbleData.getBubbleInStackWithKey(
+ stackView.getExpandedBubble().getKey()).getKey(),
+ Bubbles.DISMISS_BLOCKED);
+
+ verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
+
+ // We should be collapsed
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
assertFalse(mBubbleController.hasBubbles());
}
+
@Test
public void testAutoExpand_fails_noFlag() {
assertFalse(mBubbleController.isStackExpanded());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
index 2273bc48ce8b..fd39b6e5b1c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -22,13 +22,13 @@ import android.os.Handler;
import android.view.WindowManager;
import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.bubbles.BubbleController;
-import com.android.systemui.bubbles.BubbleData;
-import com.android.systemui.bubbles.BubbleDataRepository;
-import com.android.systemui.bubbles.BubbleLogger;
-import com.android.systemui.bubbles.BubblePositioner;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
+import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.bubbles.BubbleData;
+import com.android.wm.shell.bubbles.BubbleDataRepository;
+import com.android.wm.shell.bubbles.BubbleLogger;
+import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.common.FloatingContentCoordinator;
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.java
new file mode 100644
index 000000000000..24a7cd5c89ac
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableBubblePositioner.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.wmshell;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.view.WindowManager;
+
+import com.android.wm.shell.bubbles.BubblePositioner;
+
+public class TestableBubblePositioner extends BubblePositioner {
+
+ public TestableBubblePositioner(Context context,
+ WindowManager windowManager) {
+ super(context, windowManager);
+
+ updateInternal(Configuration.ORIENTATION_PORTRAIT,
+ Insets.of(0, 0, 0, 0),
+ new Rect(0, 0, 500, 1000));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index d0bf281f343f..a658469f9e2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -20,7 +20,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.pm.PackageManager;
import android.test.suitebuilder.annotation.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -31,13 +30,12 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.shared.system.InputConsumerController;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.wm.shell.ShellDump;
+import com.android.wm.shell.apppairs.AppPairs;
+import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedGestureHandler;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
@@ -56,14 +54,11 @@ import java.util.Optional;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class WMShellTest extends SysuiTestCase {
- InputConsumerController mInputConsumerController;
WMShell mWMShell;
@Mock CommandQueue mCommandQueue;
@Mock ConfigurationController mConfigurationController;
@Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock TaskStackChangeListeners mTaskStackChangeListeners;
- @Mock InputConsumerController mMockInputConsumerController;
@Mock NavigationModeController mNavigationModeController;
@Mock ScreenLifecycle mScreenLifecycle;
@Mock SysUiState mSysUiState;
@@ -71,19 +66,20 @@ public class WMShellTest extends SysuiTestCase {
@Mock PipTouchHandler mPipTouchHandler;
@Mock SplitScreen mSplitScreen;
@Mock OneHanded mOneHanded;
+ @Mock HideDisplayCutout mHideDisplayCutout;
@Mock ProtoTracer mProtoTracer;
@Mock ShellDump mShellDump;
+ @Mock AppPairs mAppPairs;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mInputConsumerController = InputConsumerController.getPipInputConsumer();
mWMShell = new WMShell(mContext, mCommandQueue, mConfigurationController,
- mInputConsumerController, mKeyguardUpdateMonitor, mTaskStackChangeListeners,
- mNavigationModeController, mScreenLifecycle, mSysUiState, Optional.of(mPip),
- Optional.of(mSplitScreen), Optional.of(mOneHanded), mProtoTracer,
- Optional.of(mShellDump));
+ mKeyguardUpdateMonitor, mNavigationModeController,
+ mScreenLifecycle, mSysUiState, Optional.of(mPip), Optional.of(mSplitScreen),
+ Optional.of(mOneHanded), Optional.of(mHideDisplayCutout), mProtoTracer,
+ Optional.of(mShellDump), Optional.of(mAppPairs));
when(mPip.getPipTouchHandler()).thenReturn(mPipTouchHandler);
}
@@ -100,8 +96,6 @@ public class WMShellTest extends SysuiTestCase {
mWMShell.initSplitScreen(mSplitScreen);
verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
- verify(mTaskStackChangeListeners).registerTaskStackListener(
- any(TaskStackChangeListener.class));
}
@Test
@@ -113,11 +107,17 @@ public class WMShellTest extends SysuiTestCase {
verify(mScreenLifecycle).addObserver(any(ScreenLifecycle.Observer.class));
verify(mNavigationModeController).addListener(
any(NavigationModeController.ModeChangedListener.class));
- verify(mTaskStackChangeListeners).registerTaskStackListener(
- any(TaskStackChangeListener.class));
verify(mOneHanded).registerGestureCallback(any(
OneHandedGestureHandler.OneHandedGestureEventCallback.class));
verify(mOneHanded).registerTransitionCallback(any(OneHandedTransitionCallback.class));
}
+
+ @Test
+ public void initHideDisplayCutout_registersCallbacks() {
+ mWMShell.initHideDisplayCutout(mHideDisplayCutout);
+
+ verify(mConfigurationController).addCallback(
+ any(ConfigurationController.ConfigurationListener.class));
+ }
}
diff --git a/packages/VpnDialogs/res/values-my/strings.xml b/packages/VpnDialogs/res/values-my/strings.xml
index a949fae1f74e..9d60ff42a7cd 100644
--- a/packages/VpnDialogs/res/values-my/strings.xml
+++ b/packages/VpnDialogs/res/values-my/strings.xml
@@ -30,7 +30,7 @@
<string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string>
<string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN ဆက်တင်များ ပြောင်းရန်"</string>
<string name="configure" msgid="4905518375574791375">"ပုံပေါ်စေသည်"</string>
- <string name="disconnect" msgid="971412338304200056">"ချိတ်ဆက်မှုဖြုတ်ရန်"</string>
+ <string name="disconnect" msgid="971412338304200056">"ချိတ်ဆက်ခြင်းရပ်ရန်"</string>
<string name="open_app" msgid="3717639178595958667">"အက်ပ်ကို ဖွင့်ရန်"</string>
<string name="dismiss" msgid="6192859333764711227">"ပယ်ရန်"</string>
</resources>
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
index 2c38dc330a62..25f4abe2cb14 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
@@ -111,9 +111,9 @@ class GestureManifold implements GestureMatcher.StateChangeListener {
// Shared state information.
private TouchState mState;
- GestureManifold(Context context, Listener listener, TouchState state) {
+ GestureManifold(Context context, Listener listener, TouchState state, Handler handler) {
mContext = context;
- mHandler = new Handler(context.getMainLooper());
+ mHandler = handler;
mListener = listener;
mState = state;
mMultiFingerGesturesEnabled = false;
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 5460e80a2802..b3977829d1c3 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -199,7 +199,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
new SendAccessibilityEventDelayed(
TYPE_TOUCH_INTERACTION_END, mDetermineUserIntentTimeout);
if (detector == null) {
- mGestureDetector = new GestureManifold(context, this, mState);
+ mGestureDetector = new GestureManifold(context, this, mState, mHandler);
} else {
mGestureDetector = detector;
}
@@ -245,6 +245,8 @@ public class TouchExplorer extends BaseEventStreamTransformation
mSendTouchInteractionEndDelayed.cancel();
// Clear the gesture detector
mGestureDetector.clear();
+ // Clear the offset data by long pressing.
+ mDispatcher.clear();
// Go to initial state.
mState.clear();
mAms.onTouchInteractionEnd();
@@ -389,7 +391,6 @@ public class TouchExplorer extends BaseEventStreamTransformation
public boolean onGestureStarted() {
// We have to perform gesture detection, so
// clear the current state and try to detect.
- mState.startGestureDetecting();
mSendHoverEnterAndMoveDelayed.cancel();
mSendHoverExitDelayed.cancel();
mExitGestureDetectionModeDelayed.post();
@@ -1193,7 +1194,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
private boolean shouldPerformGestureDetection(MotionEvent event) {
- if (mState.isDelegating()) {
+ if (mState.isDelegating() || mState.isDragging()) {
return false;
}
if (event.getActionMasked() == ACTION_DOWN) {
@@ -1286,6 +1287,15 @@ public class TouchExplorer extends BaseEventStreamTransformation
}
public void run() {
+ if (mReceivedPointerTracker.getReceivedPointerDownCount() > 1) {
+ // Multi-finger touch exploration doesn't make sense.
+ Slog.e(
+ LOG_TAG,
+ "Attempted touch exploration with "
+ + mReceivedPointerTracker.getReceivedPointerDownCount()
+ + " pointers down.");
+ return;
+ }
// Send an accessibility event to announce the touch exploration start.
mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START);
if (isSendMotionEventsEnabled()) {
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index 7a39bc29e8e5..6dabe76c7dc9 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -208,7 +208,9 @@ public class TouchState {
startGestureDetecting();
break;
case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:
- startTouchInteracting();
+ // Clear to make sure that we don't accidentally execute passthrough, and that we
+ // are ready for the next interaction.
+ clear();
break;
default:
break;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index b3fc07a8ab9c..6f81b5cfe3e6 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -37,7 +37,7 @@ import com.android.server.accessibility.AccessibilityManagerService;
* Handles all magnification controllers initialization, generic interactions
* and magnification mode transition.
*/
-public class MagnificationController {
+public class MagnificationController implements WindowMagnificationManager.Callback {
private static final boolean DEBUG = false;
private static final String TAG = "MagnificationController";
@@ -78,6 +78,14 @@ public class MagnificationController {
mWindowMagnificationMgr = windowMagnificationManager;
}
+ @Override
+ public void onPerformScaleAction(int displayId, float scale) {
+ getWindowMagnificationMgr().setScale(displayId, scale);
+ getWindowMagnificationMgr().persistScale(displayId);
+ mAms.onMagnificationScaleChanged(displayId,
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+ }
+
/**
* Transitions to the target Magnification mode with current center of the magnification mode
* if it is available.
@@ -223,7 +231,8 @@ public class MagnificationController {
synchronized (mLock) {
if (mWindowMagnificationMgr == null) {
mWindowMagnificationMgr = new WindowMagnificationManager(mContext,
- mAms.getCurrentUserIdLocked());
+ mAms.getCurrentUserIdLocked(),
+ this);
}
return mWindowMagnificationMgr;
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index ed3085f97ded..40668d8df568 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -16,6 +16,7 @@
package com.android.server.accessibility.magnification;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -79,9 +80,27 @@ public class WindowMagnificationManager implements
}
};
- public WindowMagnificationManager(Context context, int userId) {
+ /**
+ * Callback to handle magnification actions from system UI.
+ */
+ public interface Callback {
+
+ /**
+ * Called when the accessibility action of scale requests to be performed.
+ * It is invoked from System UI. And the action is provided by the mirror window.
+ *
+ * @param displayId The logical display id.
+ * @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ */
+ void onPerformScaleAction(int displayId, float scale);
+ }
+
+ private final Callback mCallback;
+
+ public WindowMagnificationManager(Context context, int userId, @NonNull Callback callback) {
mContext = context;
mUserId = userId;
+ mCallback = callback;
}
/**
@@ -498,6 +517,13 @@ public class WindowMagnificationManager implements
}
@Override
+ public void onPerformScaleAction(int displayId, float scale) {
+ synchronized (mLock) {
+ mCallback.onPerformScaleAction(displayId, scale);
+ }
+ }
+
+ @Override
public void binderDied() {
synchronized (mLock) {
Slog.w(TAG, "binderDied DeathRecipient :" + mExpiredDeathRecipient);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index ad85784ca066..a1ad72c47784 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -84,7 +84,6 @@ import com.android.internal.util.Preconditions;
import com.android.internal.util.SyncResultReceiver;
import com.android.server.FgThread;
import com.android.server.LocalServices;
-import com.android.server.SystemService.TargetUser;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -170,7 +169,7 @@ public final class AutofillManagerService
// beneath it is brought back to top. Ideally, we should just hide the UI and
// bring it back when the activity resumes.
synchronized (mLock) {
- visitServicesLocked((s) -> s.destroyFinishedSessionsLocked());
+ visitServicesLocked((s) -> s.forceRemoveFinishedSessionsLocked());
}
mUi.hideAll(null);
}
@@ -386,18 +385,18 @@ public final class AutofillManagerService
}
// Called by Shell command.
- void destroySessions(@UserIdInt int userId, IResultReceiver receiver) {
- Slog.i(TAG, "destroySessions() for userId " + userId);
+ void removeAllSessions(@UserIdInt int userId, IResultReceiver receiver) {
+ Slog.i(TAG, "removeAllSessions() for userId " + userId);
enforceCallingPermissionForManagement();
synchronized (mLock) {
if (userId != UserHandle.USER_ALL) {
AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
if (service != null) {
- service.destroySessionsLocked();
+ service.forceRemoveAllSessionsLocked();
}
} else {
- visitServicesLocked((s) -> s.destroySessionsLocked());
+ visitServicesLocked((s) -> s.forceRemoveAllSessionsLocked());
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 864ead1485b5..32126987376a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -215,14 +215,14 @@ final class AutofillManagerServiceImpl
@GuardedBy("mLock")
@Override // from PerUserSystemService
protected boolean updateLocked(boolean disabled) {
- destroySessionsLocked();
+ forceRemoveAllSessionsLocked();
final boolean enabledChanged = super.updateLocked(disabled);
if (enabledChanged) {
if (!isEnabledLocked()) {
final int sessionCount = mSessions.size();
for (int i = sessionCount - 1; i >= 0; i--) {
final Session session = mSessions.valueAt(i);
- session.removeSelfLocked();
+ session.removeFromServiceLocked();
}
}
sendStateToClients(/* resetClient= */ false);
@@ -442,7 +442,7 @@ final class AutofillManagerServiceImpl
if (sVerbose) Slog.v(TAG, "finishSessionLocked(): session finished on save? " + finished);
if (finished) {
- session.removeSelfLocked();
+ session.removeFromServiceLocked();
}
}
@@ -457,7 +457,7 @@ final class AutofillManagerServiceImpl
Slog.w(TAG, "cancelSessionLocked(): no session for " + sessionId + "(" + uid + ")");
return;
}
- session.removeSelfLocked();
+ session.removeFromServiceLocked();
}
@GuardedBy("mLock")
@@ -483,7 +483,7 @@ final class AutofillManagerServiceImpl
componentName.getPackageName());
Settings.Secure.putStringForUser(getContext().getContentResolver(),
Settings.Secure.AUTOFILL_SERVICE, null, mUserId);
- destroySessionsLocked();
+ forceRemoveAllSessionsLocked();
} else {
Slog.w(TAG, "disableOwnedServices(): ignored because current service ("
+ serviceInfo + ") does not match Settings (" + autoFillService + ")");
@@ -1107,35 +1107,41 @@ final class AutofillManagerServiceImpl
}
@GuardedBy("mLock")
- void destroySessionsLocked() {
- if (mSessions.size() == 0) {
+ void forceRemoveAllSessionsLocked() {
+ final int sessionCount = mSessions.size();
+ if (sessionCount == 0) {
mUi.destroyAll(null, null, false);
return;
}
- while (mSessions.size() > 0) {
- mSessions.valueAt(0).forceRemoveSelfLocked();
+
+ for (int i = sessionCount - 1; i >= 0; i--) {
+ mSessions.valueAt(i).forceRemoveFromServiceLocked();
}
}
@GuardedBy("mLock")
- void destroySessionsForAugmentedAutofillOnlyLocked() {
+ void forceRemoveForAugmentedOnlySessionsLocked() {
final int sessionCount = mSessions.size();
for (int i = sessionCount - 1; i >= 0; i--) {
- mSessions.valueAt(i).forceRemoveSelfIfForAugmentedAutofillOnlyLocked();
+ mSessions.valueAt(i).forceRemoveFromServiceIfForAugmentedOnlyLocked();
}
}
+ /**
+ * This method is called exclusively in response to {@code Intent.ACTION_CLOSE_SYSTEM_DIALOGS}.
+ * The method removes all sessions that are finished but showing SaveUI due to how SaveUI is
+ * managed (see b/64940307). Otherwise it will remove any augmented autofill generated windows.
+ */
// TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities
@GuardedBy("mLock")
- void destroyFinishedSessionsLocked() {
+ void forceRemoveFinishedSessionsLocked() {
final int sessionCount = mSessions.size();
for (int i = sessionCount - 1; i >= 0; i--) {
final Session session = mSessions.valueAt(i);
if (session.isSavingLocked()) {
if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id);
- session.forceRemoveSelfLocked();
- }
- else {
+ session.forceRemoveFromServiceLocked();
+ } else {
session.destroyAugmentedAutofillWindowsLocked();
}
}
@@ -1261,7 +1267,7 @@ final class AutofillManagerServiceImpl
Slog.v(TAG, "updateRemoteAugmentedAutofillService(): "
+ "destroying old remote service");
}
- destroySessionsForAugmentedAutofillOnlyLocked();
+ forceRemoveForAugmentedOnlySessionsLocked();
mRemoteAugmentedAutofillService.unbind();
mRemoteAugmentedAutofillService = null;
mRemoteAugmentedAutofillServiceInfo = null;
@@ -1663,7 +1669,7 @@ final class AutofillManagerServiceImpl
Slog.i(TAG, "Prune session " + sessionToRemove.id + " ("
+ sessionToRemove.getActivityTokenLocked() + ")");
}
- sessionToRemove.removeSelfLocked();
+ sessionToRemove.removeFromServiceLocked();
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index bbe37a5df4f4..68e6290c987a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -355,7 +355,7 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand {
latch.countDown();
}
};
- return requestSessionCommon(pw, latch, () -> mService.destroySessions(userId, receiver));
+ return requestSessionCommon(pw, latch, () -> mService.removeAllSessions(userId, receiver));
}
private int requestList(PrintWriter pw) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0302b2251f10..b48d71a51ce3 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -227,8 +227,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private boolean mHasCallback;
/**
- * Extras sent by service on {@code onFillRequest()} calls; the first non-null extra is saved
- * and used on subsequent {@code onFillRequest()} and {@code onSaveRequest()} calls.
+ * Extras sent by service on {@code onFillRequest()} calls; the most recent non-null extra is
+ * saved and used on subsequent {@code onFillRequest()} and {@code onSaveRequest()} calls.
*/
@GuardedBy("mLock")
private Bundle mClientState;
@@ -1086,7 +1086,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (showMessage) {
getUiForShowing().showError(message, this);
}
- removeSelf();
+ removeFromService();
}
// FillServiceCallbacks
@@ -1111,7 +1111,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
// Nothing left to do...
- removeSelf();
+ removeFromService();
}
// FillServiceCallbacks
@@ -1147,7 +1147,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (showMessage) {
getUiForShowing().showError(message, this);
}
- removeSelf();
+ removeFromService();
}
/**
@@ -1179,7 +1179,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@Override
public void onServiceDied(@NonNull RemoteFillService service) {
Slog.w(TAG, "removing session because service died");
- forceRemoveSelfLocked();
+ forceRemoveFromServiceLocked();
}
// AutoFillUiCallback
@@ -1199,7 +1199,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
fillInIntent = createAuthFillInIntentLocked(requestId, extras);
if (fillInIntent == null) {
- forceRemoveSelfLocked();
+ forceRemoveFromServiceLocked();
return;
}
}
@@ -1255,7 +1255,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
mHandler.sendMessage(obtainMessage(
- Session::removeSelf, this));
+ Session::removeFromService, this));
}
// AutoFillUiCallback
@@ -1327,7 +1327,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
@Override
public void cancelSession() {
synchronized (mLock) {
- removeSelfLocked();
+ removeFromServiceLocked();
}
}
@@ -1347,7 +1347,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return;
}
if (intent == null) {
- removeSelfLocked();
+ removeFromServiceLocked();
}
}
mHandler.sendMessage(obtainMessage(
@@ -1401,13 +1401,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// Typically happens when app explicitly called cancel() while the service was showing
// the auth UI.
Slog.w(TAG, "setAuthenticationResultLocked(" + authenticationId + "): no responses");
- removeSelf();
+ removeFromService();
return;
}
final FillResponse authenticatedResponse = mResponses.get(requestId);
if (authenticatedResponse == null || data == null) {
Slog.w(TAG, "no authenticated response");
- removeSelf();
+ removeFromService();
return;
}
@@ -1418,7 +1418,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final Dataset dataset = authenticatedResponse.getDatasets().get(datasetIdx);
if (dataset == null) {
Slog.w(TAG, "no dataset with index " + datasetIdx + " on fill response");
- removeSelf();
+ removeFromService();
return;
}
}
@@ -1504,7 +1504,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
Slog.d(TAG, "Rejecting empty/invalid auth result");
}
mService.resetLastAugmentedAutofillResponse();
- removeSelfLocked();
+ removeFromServiceLocked();
return;
}
@@ -2715,7 +2715,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return;
}
if (sDebug) Slog.d(TAG, "Finishing session because URL bar changed");
- forceRemoveSelfLocked(AutofillManager.STATE_UNKNOWN_COMPAT_MODE);
+ forceRemoveFromServiceLocked(AutofillManager.STATE_UNKNOWN_COMPAT_MODE);
return;
}
if (!Objects.equals(value, viewState.getCurrentValue())) {
@@ -3226,7 +3226,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
// Nothing to be done, but need to notify client.
notifyUnavailableToClient(AutofillManager.STATE_FINISHED, autofillableIds);
- removeSelf();
+ removeFromService();
} else {
if ((flags & FLAG_PASSWORD_INPUT_TYPE) != 0) {
if (sVerbose) {
@@ -3393,20 +3393,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
@GuardedBy("mLock")
- private void logAugmentedAutofillRequestLocked(int mode,
- ComponentName augmentedRemoteServiceName, AutofillId focusedId, boolean isWhitelisted,
- Boolean isInline) {
- final String historyItem =
- "aug:id=" + id + " u=" + uid + " m=" + mode
- + " a=" + ComponentName.flattenToShortString(mComponentName)
- + " f=" + focusedId
- + " s=" + augmentedRemoteServiceName
- + " w=" + isWhitelisted
- + " i=" + isInline;
- mService.getMaster().logRequestLocked(historyItem);
- }
-
- @GuardedBy("mLock")
private void cancelAugmentedAutofillLocked() {
final RemoteAugmentedAutofillService remoteService = mService
.getRemoteAugmentedAutofillServiceLocked();
@@ -3574,7 +3560,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState);
if (fillInIntent == null) {
- forceRemoveSelfLocked();
+ forceRemoveFromServiceLocked();
return;
}
final int authenticationId = AutofillManager.makeAuthenticationId(requestId,
@@ -3923,12 +3909,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
/**
- * Cleans up this session.
+ * Destroy this session and perform any clean up work.
*
* <p>Typically called in 2 scenarios:
*
* <ul>
- * <li>When the session naturally finishes (i.e., from {@link #removeSelfLocked()}.
+ * <li>When the session naturally finishes (i.e., from {@link #removeFromServiceLocked()}.
* <li>When the service hosting the session is finished (for example, because the user
* disabled it).
* </ul>
@@ -3990,32 +3976,32 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
/**
- * Cleans up this session and remove it from the service always, even if it does have a pending
+ * Destroy this session and remove it from the service always, even if it does have a pending
* Save UI.
*/
@GuardedBy("mLock")
- void forceRemoveSelfLocked() {
- forceRemoveSelfLocked(AutofillManager.STATE_UNKNOWN);
+ void forceRemoveFromServiceLocked() {
+ forceRemoveFromServiceLocked(AutofillManager.STATE_UNKNOWN);
}
@GuardedBy("mLock")
- void forceRemoveSelfIfForAugmentedAutofillOnlyLocked() {
+ void forceRemoveFromServiceIfForAugmentedOnlyLocked() {
if (sVerbose) {
- Slog.v(TAG, "forceRemoveSelfIfForAugmentedAutofillOnly(" + this.id + "): "
+ Slog.v(TAG, "forceRemoveFromServiceIfForAugmentedOnlyLocked(" + this.id + "): "
+ mForAugmentedAutofillOnly);
}
if (!mForAugmentedAutofillOnly) return;
- forceRemoveSelfLocked();
+ forceRemoveFromServiceLocked();
}
@GuardedBy("mLock")
- void forceRemoveSelfLocked(int clientState) {
- if (sVerbose) Slog.v(TAG, "forceRemoveSelfLocked(): " + mPendingSaveUi);
+ void forceRemoveFromServiceLocked(int clientState) {
+ if (sVerbose) Slog.v(TAG, "forceRemoveFromServiceLocked(): " + mPendingSaveUi);
final boolean isPendingSaveUi = isSaveUiPendingLocked();
mPendingSaveUi = null;
- removeSelfLocked();
+ removeFromServiceLocked();
mUi.destroyAll(mPendingSaveUi, this, false);
if (!isPendingSaveUi) {
try {
@@ -4036,28 +4022,28 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
/**
- * Thread-safe version of {@link #removeSelfLocked()}.
+ * Thread-safe version of {@link #removeFromServiceLocked()}.
*/
- private void removeSelf() {
+ private void removeFromService() {
synchronized (mLock) {
- removeSelfLocked();
+ removeFromServiceLocked();
}
}
/**
- * Cleans up this session and remove it from the service, but but only if it does not have a
+ * Destroy this session and remove it from the service, but but only if it does not have a
* pending Save UI.
*/
@GuardedBy("mLock")
- void removeSelfLocked() {
- if (sVerbose) Slog.v(TAG, "removeSelfLocked(" + this.id + "): " + mPendingSaveUi);
+ void removeFromServiceLocked() {
+ if (sVerbose) Slog.v(TAG, "removeFromServiceLocked(" + this.id + "): " + mPendingSaveUi);
if (mDestroyed) {
- Slog.w(TAG, "Call to Session#removeSelfLocked() rejected - session: "
+ Slog.w(TAG, "Call to Session#removeFromServiceLocked() rejected - session: "
+ id + " destroyed");
return;
}
if (isSaveUiPendingLocked()) {
- Slog.i(TAG, "removeSelfLocked() ignored, waiting for pending save ui");
+ Slog.i(TAG, "removeFromServiceLocked() ignored, waiting for pending save ui");
return;
}
@@ -4139,6 +4125,20 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
requestLog.addTaggedData(tag, value);
}
+ @GuardedBy("mLock")
+ private void logAugmentedAutofillRequestLocked(int mode,
+ ComponentName augmentedRemoteServiceName, AutofillId focusedId, boolean isWhitelisted,
+ Boolean isInline) {
+ final String historyItem =
+ "aug:id=" + id + " u=" + uid + " m=" + mode
+ + " a=" + ComponentName.flattenToShortString(mComponentName)
+ + " f=" + focusedId
+ + " s=" + augmentedRemoteServiceName
+ + " w=" + isWhitelisted
+ + " i=" + isInline;
+ mService.getMaster().logRequestLocked(historyItem);
+ }
+
private void wtf(@Nullable Exception e, String fmt, Object...args) {
final String message = String.format(fmt, args);
synchronized (mLock) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index ff47a83b0115..fb3c61bc54bc 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -110,6 +110,7 @@ java_library_static {
"android.hardware.tv.cec-V1.0-java",
"android.hardware.weaver-V1.0-java",
"android.hardware.biometrics.face-V1.1-java",
+ "android.hardware.biometrics.face-java",
"android.hardware.biometrics.fingerprint-V2.3-java",
"android.hardware.biometrics.fingerprint-java",
"android.hardware.oemlock-V1.0-java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 22423fe00b6c..d586f0017a1e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -135,8 +135,6 @@ import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.net.netlink.InetDiagMessage;
import android.net.shared.PrivateDnsConfig;
-import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult;
-import android.net.util.LinkPropertiesUtils.CompareResult;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
import android.os.BasicShellCommandHandler;
@@ -192,6 +190,8 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.XmlUtils;
+import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
+import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.AutodestructReference;
import com.android.server.connectivity.DataConnectionStats;
@@ -235,6 +235,7 @@ import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
@@ -1105,23 +1106,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
intentFilter.addAction(Intent.ACTION_USER_ADDED);
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
- mContext.registerReceiverAsUser(
+
+ final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
+ userAllContext.registerReceiver(
mIntentReceiver,
- UserHandle.ALL,
intentFilter,
null /* broadcastPermission */,
mHandler);
- mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM,
- new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);
+ mContext.createContextAsUser(UserHandle.SYSTEM, 0 /* flags */).registerReceiver(
+ mUserPresentReceiver,
+ new IntentFilter(Intent.ACTION_USER_PRESENT),
+ null /* broadcastPermission */,
+ null /* scheduler */);
// Listen to package add and removal events for all users.
intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
- mContext.registerReceiverAsUser(
+ userAllContext.registerReceiver(
mIntentReceiver,
- UserHandle.ALL,
intentFilter,
null /* broadcastPermission */,
mHandler);
@@ -1129,8 +1133,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Listen to lockdown VPN reset.
intentFilter = new IntentFilter();
intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
- mContext.registerReceiverAsUser(
- mIntentReceiver, UserHandle.ALL, intentFilter, NETWORK_STACK, mHandler);
+ userAllContext.registerReceiver(
+ mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
try {
mNMS.registerObserver(mDataActivityObserver);
@@ -1913,10 +1917,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
if (DBG) log("Adding legacy route " + bestRoute +
" for UID/PID " + uid + "/" + Binder.getCallingPid());
+
+ final String dst = bestRoute.getDestinationLinkAddress().toString();
+ final String nextHop = bestRoute.hasGateway()
+ ? bestRoute.getGateway().getHostAddress() : "";
try {
- mNMS.addLegacyRouteForNetId(netId, bestRoute, uid);
- } catch (Exception e) {
- // never crash - catch them all
+ mNetd.networkAddLegacyRoute(netId, bestRoute.getInterface(), dst, nextHop , uid);
+ } catch (RemoteException | ServiceSpecificException e) {
if (DBG) loge("Exception trying to add a route: " + e);
return false;
}
@@ -5259,7 +5266,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Try creating lockdown tracker, since user present usually means
// unlocked keystore.
updateLockdownVpn();
- mContext.unregisterReceiver(this);
+ // Use the same context that registered receiver before to unregister it. Because use
+ // different context to unregister receiver will cause exception.
+ context.unregisterReceiver(this);
}
};
@@ -5353,7 +5362,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
* Also used to notice when the calling process dies so we can self-expire
*/
private class NetworkRequestInfo implements IBinder.DeathRecipient {
+ final List<NetworkRequest> mRequests;
final NetworkRequest request;
+
// The network currently satisfying this request, or null if none. Must only be touched
// on the handler thread. This only makes sense for network requests and not for listens,
// as defined by NetworkRequest#isRequest(). For listens, this is always null.
@@ -5368,6 +5379,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequestInfo(NetworkRequest r, PendingIntent pi) {
request = r;
+ mRequests = initializeRequests(r);
ensureNetworkRequestHasType(request);
mPendingIntent = pi;
messenger = null;
@@ -5381,6 +5393,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
super();
messenger = m;
request = r;
+ mRequests = initializeRequests(r);
ensureNetworkRequestHasType(request);
mBinder = binder;
mPid = getCallingPid();
@@ -5399,6 +5412,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
this(r, null);
}
+ private List<NetworkRequest> initializeRequests(NetworkRequest r) {
+ final ArrayList<NetworkRequest> tempRequests = new ArrayList<>();
+ tempRequests.add(new NetworkRequest(r));
+ return Collections.unmodifiableList(tempRequests);
+ }
+
+
private void enforceRequestCountLimit() {
synchronized (mUidToNetworkRequestCount) {
int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
@@ -6426,8 +6446,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
&& !nai.networkAgentConfig.allowBypass
&& nc.getOwnerUid() != Process.SYSTEM_UID
&& lp.getInterfaceName() != null
- && (lp.hasIPv4DefaultRoute() || lp.hasIpv4UnreachableDefaultRoute())
- && (lp.hasIPv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
+ && (lp.hasIpv4DefaultRoute() || lp.hasIpv4UnreachableDefaultRoute())
+ && (lp.hasIpv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
}
private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
diff --git a/services/core/java/com/android/server/ContextHubSystemService.java b/services/core/java/com/android/server/ContextHubSystemService.java
index c6853a5119ec..a35351958f43 100644
--- a/services/core/java/com/android/server/ContextHubSystemService.java
+++ b/services/core/java/com/android/server/ContextHubSystemService.java
@@ -20,7 +20,7 @@ import android.content.Context;
import android.util.Log;
import com.android.internal.util.ConcurrentUtils;
-import com.android.server.location.ContextHubService;
+import com.android.server.location.contexthub.ContextHubService;
import java.util.concurrent.Future;
diff --git a/services/core/java/com/android/server/CountryDetectorService.java b/services/core/java/com/android/server/CountryDetectorService.java
index b0132d35fa3b..a2a7dd35371f 100644
--- a/services/core/java/com/android/server/CountryDetectorService.java
+++ b/services/core/java/com/android/server/CountryDetectorService.java
@@ -33,8 +33,8 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
-import com.android.server.location.ComprehensiveCountryDetector;
-import com.android.server.location.CountryDetectorBase;
+import com.android.server.location.countrydetector.ComprehensiveCountryDetector;
+import com.android.server.location.countrydetector.CountryDetectorBase;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -43,10 +43,9 @@ import java.util.HashMap;
/**
* This class detects the country that the user is in. The default country detection is made through
- * {@link com.android.server.location.ComprehensiveCountryDetector}. It is possible to overlay the
- * detection algorithm by overlaying the attribute R.string.config_customCountryDetector with the
- * custom class name to use instead. The custom class must extend
- * {@link com.android.server.location.CountryDetectorBase}
+ * {@link ComprehensiveCountryDetector}. It is possible to overlay the detection algorithm by
+ * overlaying the attribute R.string.config_customCountryDetector with the custom class name to use
+ * instead. The custom class must extend {@link CountryDetectorBase}
*
* @hide
*/
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 78bd4cdd4eab..84f40cb4b84f 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -25,7 +25,6 @@ import android.net.Uri;
import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
-import android.net.util.nsd.DnsSdTxtRecord;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
@@ -42,6 +41,7 @@ import com.android.internal.util.AsyncChannel;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.net.module.util.DnsSdTxtRecord;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index e675d8d458c7..f07954609603 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -68,6 +68,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -117,6 +118,9 @@ public class PackageWatchdog {
static final int DEFAULT_TRIGGER_FAILURE_COUNT = 5;
@VisibleForTesting
static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
+ // Sliding window for tracking how many mitigation calls were made for a package.
+ @VisibleForTesting
+ static final long DEFAULT_DEESCALATION_WINDOW_MS = TimeUnit.HOURS.toMillis(1);
// Whether explicit health checks are enabled or not
private static final boolean DEFAULT_EXPLICIT_HEALTH_CHECK_ENABLED = true;
@@ -388,6 +392,7 @@ public class PackageWatchdog {
// Observer that will receive failure for versionedPackage
PackageHealthObserver currentObserverToNotify = null;
int currentObserverImpact = Integer.MAX_VALUE;
+ MonitoredPackage currentMonitoredPackage = null;
// Find observer with least user impact
for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
@@ -396,19 +401,33 @@ public class PackageWatchdog {
if (registeredObserver != null
&& observer.onPackageFailureLocked(
versionedPackage.getPackageName())) {
+ MonitoredPackage p = observer.getMonitoredPackage(
+ versionedPackage.getPackageName());
+ int mitigationCount = 1;
+ if (p != null) {
+ mitigationCount = p.getMitigationCountLocked() + 1;
+ }
int impact = registeredObserver.onHealthCheckFailed(
- versionedPackage, failureReason);
+ versionedPackage, failureReason, mitigationCount);
if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
&& impact < currentObserverImpact) {
currentObserverToNotify = registeredObserver;
currentObserverImpact = impact;
+ currentMonitoredPackage = p;
}
}
}
// Execute action with least user impact
if (currentObserverToNotify != null) {
- currentObserverToNotify.execute(versionedPackage, failureReason);
+ int mitigationCount = 1;
+ if (currentMonitoredPackage != null) {
+ currentMonitoredPackage.noteMitigationCallLocked();
+ mitigationCount =
+ currentMonitoredPackage.getMitigationCountLocked();
+ }
+ currentObserverToNotify.execute(versionedPackage,
+ failureReason, mitigationCount);
}
}
}
@@ -429,7 +448,7 @@ public class PackageWatchdog {
PackageHealthObserver registeredObserver = observer.registeredObserver;
if (registeredObserver != null) {
int impact = registeredObserver.onHealthCheckFailed(
- failingPackage, failureReason);
+ failingPackage, failureReason, 1);
if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
&& impact < currentObserverImpact) {
currentObserverToNotify = registeredObserver;
@@ -438,7 +457,7 @@ public class PackageWatchdog {
}
}
if (currentObserverToNotify != null) {
- currentObserverToNotify.execute(failingPackage, failureReason);
+ currentObserverToNotify.execute(failingPackage, failureReason, 1);
}
}
@@ -559,6 +578,8 @@ public class PackageWatchdog {
* @param versionedPackage the package that is failing. This may be null if a native
* service is crashing.
* @param failureReason the type of failure that is occurring.
+ * @param mitigationCount the number of times mitigation has been called for this package
+ * (including this time).
*
*
* @return any one of {@link PackageHealthObserverImpact} to express the impact
@@ -566,7 +587,8 @@ public class PackageWatchdog {
*/
@PackageHealthObserverImpact int onHealthCheckFailed(
@Nullable VersionedPackage versionedPackage,
- @FailureReasons int failureReason);
+ @FailureReasons int failureReason,
+ int mitigationCount);
/**
* Executes mitigation for {@link #onHealthCheckFailed}.
@@ -574,10 +596,12 @@ public class PackageWatchdog {
* @param versionedPackage the package that is failing. This may be null if a native
* service is crashing.
* @param failureReason the type of failure that is occurring.
+ * @param mitigationCount the number of times mitigation has been called for this package
+ * (including this time).
* @return {@code true} if action was executed successfully, {@code false} otherwise
*/
boolean execute(@Nullable VersionedPackage versionedPackage,
- @FailureReasons int failureReason);
+ @FailureReasons int failureReason, int mitigationCount);
/**
@@ -684,7 +708,7 @@ public class PackageWatchdog {
synchronized (mLock) {
for (int observerIdx = 0; observerIdx < mAllObservers.size(); observerIdx++) {
ObserverInternal observer = mAllObservers.valueAt(observerIdx);
- MonitoredPackage monitoredPackage = observer.packages.get(packageName);
+ MonitoredPackage monitoredPackage = observer.getMonitoredPackage(packageName);
if (monitoredPackage != null) {
int oldState = monitoredPackage.getHealthCheckStateLocked();
@@ -713,7 +737,8 @@ public class PackageWatchdog {
Slog.d(TAG, "Received supported packages " + supportedPackages);
Iterator<ObserverInternal> oit = mAllObservers.values().iterator();
while (oit.hasNext()) {
- Iterator<MonitoredPackage> pit = oit.next().packages.values().iterator();
+ Iterator<MonitoredPackage> pit = oit.next().getMonitoredPackages()
+ .values().iterator();
while (pit.hasNext()) {
MonitoredPackage monitoredPackage = pit.next();
String packageName = monitoredPackage.getName();
@@ -746,7 +771,7 @@ public class PackageWatchdog {
while (oit.hasNext()) {
ObserverInternal observer = oit.next();
Iterator<MonitoredPackage> pit =
- observer.packages.values().iterator();
+ observer.getMonitoredPackages().values().iterator();
while (pit.hasNext()) {
MonitoredPackage monitoredPackage = pit.next();
String packageName = monitoredPackage.getName();
@@ -804,7 +829,8 @@ public class PackageWatchdog {
private long getNextStateSyncMillisLocked() {
long shortestDurationMs = Long.MAX_VALUE;
for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
- ArrayMap<String, MonitoredPackage> packages = mAllObservers.valueAt(oIndex).packages;
+ ArrayMap<String, MonitoredPackage> packages = mAllObservers.valueAt(oIndex)
+ .getMonitoredPackages();
for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
MonitoredPackage mp = packages.valueAt(pIndex);
long duration = mp.getShortestScheduleDurationMsLocked();
@@ -838,7 +864,7 @@ public class PackageWatchdog {
if (!failedPackages.isEmpty()) {
onHealthCheckFailed(observer, failedPackages);
}
- if (observer.packages.isEmpty() && (observer.registeredObserver == null
+ if (observer.getMonitoredPackages().isEmpty() && (observer.registeredObserver == null
|| !observer.registeredObserver.isPersistent())) {
Slog.i(TAG, "Discarding observer " + observer.name + ". All packages expired");
it.remove();
@@ -857,7 +883,7 @@ public class PackageWatchdog {
VersionedPackage versionedPkg = it.next().mPackage;
Slog.i(TAG, "Explicit health check failed for package " + versionedPkg);
registeredObserver.execute(versionedPkg,
- PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
+ PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK, 1);
}
}
}
@@ -1054,7 +1080,7 @@ public class PackageWatchdog {
private static class ObserverInternal {
public final String name;
@GuardedBy("mLock")
- public final ArrayMap<String, MonitoredPackage> packages = new ArrayMap<>();
+ private final ArrayMap<String, MonitoredPackage> mPackages = new ArrayMap<>();
@Nullable
@GuardedBy("mLock")
public PackageHealthObserver registeredObserver;
@@ -1073,8 +1099,8 @@ public class PackageWatchdog {
try {
out.startTag(null, TAG_OBSERVER);
out.attribute(null, ATTR_NAME, name);
- for (int i = 0; i < packages.size(); i++) {
- MonitoredPackage p = packages.valueAt(i);
+ for (int i = 0; i < mPackages.size(); i++) {
+ MonitoredPackage p = mPackages.valueAt(i);
p.writeLocked(out);
}
out.endTag(null, TAG_OBSERVER);
@@ -1089,11 +1115,11 @@ public class PackageWatchdog {
public void updatePackagesLocked(List<MonitoredPackage> packages) {
for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
MonitoredPackage p = packages.get(pIndex);
- MonitoredPackage existingPackage = this.packages.get(p.getName());
+ MonitoredPackage existingPackage = getMonitoredPackage(p.getName());
if (existingPackage != null) {
existingPackage.updateHealthCheckDuration(p.mDurationMs);
} else {
- this.packages.put(p.getName(), p);
+ putMonitoredPackage(p);
}
}
}
@@ -1111,7 +1137,7 @@ public class PackageWatchdog {
@GuardedBy("mLock")
private Set<MonitoredPackage> prunePackagesLocked(long elapsedMs) {
Set<MonitoredPackage> failedPackages = new ArraySet<>();
- Iterator<MonitoredPackage> it = packages.values().iterator();
+ Iterator<MonitoredPackage> it = mPackages.values().iterator();
while (it.hasNext()) {
MonitoredPackage p = it.next();
int oldState = p.getHealthCheckStateLocked();
@@ -1134,12 +1160,12 @@ public class PackageWatchdog {
*/
@GuardedBy("mLock")
public boolean onPackageFailureLocked(String packageName) {
- if (packages.get(packageName) == null && registeredObserver.isPersistent()
+ if (getMonitoredPackage(packageName) == null && registeredObserver.isPersistent()
&& registeredObserver.mayObservePackage(packageName)) {
- packages.put(packageName, sPackageWatchdog.newMonitoredPackage(
+ putMonitoredPackage(sPackageWatchdog.newMonitoredPackage(
packageName, DEFAULT_OBSERVING_DURATION_MS, false));
}
- MonitoredPackage p = packages.get(packageName);
+ MonitoredPackage p = getMonitoredPackage(packageName);
if (p != null) {
return p.onFailureLocked();
}
@@ -1147,6 +1173,40 @@ public class PackageWatchdog {
}
/**
+ * Returns the map of packages monitored by this observer.
+ *
+ * @return a mapping of package names to {@link MonitoredPackage} objects.
+ */
+ @GuardedBy("mLock")
+ public ArrayMap<String, MonitoredPackage> getMonitoredPackages() {
+ return mPackages;
+ }
+
+ /**
+ * Returns the {@link MonitoredPackage} associated with a given package name if the
+ * package is being monitored by this observer.
+ *
+ * @param packageName: the name of the package.
+ * @return the {@link MonitoredPackage} object associated with the package name if one
+ * exists, {@code null} otherwise.
+ */
+ @GuardedBy("mLock")
+ @Nullable
+ public MonitoredPackage getMonitoredPackage(String packageName) {
+ return mPackages.get(packageName);
+ }
+
+ /**
+ * Associates a {@link MonitoredPackage} with the observer.
+ *
+ * @param p: the {@link MonitoredPackage} to store.
+ */
+ @GuardedBy("mLock")
+ public void putMonitoredPackage(MonitoredPackage p) {
+ mPackages.put(p.getName(), p);
+ }
+
+ /**
* Returns one ObserverInternal from the {@code parser} and advances its state.
*
* <p>Note that this method is <b>not</b> thread safe. It should only be called from
@@ -1201,8 +1261,8 @@ public class PackageWatchdog {
public void dump(IndentingPrintWriter pw) {
boolean isPersistent = registeredObserver != null && registeredObserver.isPersistent();
pw.println("Persistent: " + isPersistent);
- for (String packageName : packages.keySet()) {
- MonitoredPackage p = packages.get(packageName);
+ for (String packageName : mPackages.keySet()) {
+ MonitoredPackage p = getMonitoredPackage(packageName);
pw.println(packageName + ": ");
pw.increaseIndent();
pw.println("# Failures: " + p.mFailureHistory.size());
@@ -1257,6 +1317,10 @@ public class PackageWatchdog {
// Times when package failures happen sorted in ascending order
@GuardedBy("mLock")
private final LongArrayQueue mFailureHistory = new LongArrayQueue();
+ // Times when an observer was called to mitigate this package's failure. Sorted in
+ // ascending order.
+ @GuardedBy("mLock")
+ private final LongArrayQueue mMitigationCalls = new LongArrayQueue();
// One of STATE_[ACTIVE|INACTIVE|PASSED|FAILED]. Updated on construction and after
// methods that could change the health check state: handleElapsedTimeLocked and
// tryPassHealthCheckLocked
@@ -1322,6 +1386,33 @@ public class PackageWatchdog {
}
/**
+ * Notes the timestamp of a mitigation call into the observer.
+ */
+ @GuardedBy("mLock")
+ public void noteMitigationCallLocked() {
+ mMitigationCalls.addLast(mSystemClock.uptimeMillis());
+ }
+
+ /**
+ * Prunes any mitigation calls outside of the de-escalation window, and returns the
+ * number of calls that are in the window afterwards.
+ *
+ * @return the number of mitigation calls made in the de-escalation window.
+ */
+ @GuardedBy("mLock")
+ public int getMitigationCountLocked() {
+ try {
+ final long now = mSystemClock.uptimeMillis();
+ while (now - mMitigationCalls.peekFirst() > DEFAULT_DEESCALATION_WINDOW_MS) {
+ mMitigationCalls.removeFirst();
+ }
+ } catch (NoSuchElementException ignore) {
+ }
+
+ return mMitigationCalls.size();
+ }
+
+ /**
* Sets the initial health check duration.
*
* @return the new health check state
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 9fc8f0b5a3c3..d04949ac54db 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -56,6 +56,7 @@ import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -76,6 +77,8 @@ public class RescueParty {
static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
@VisibleForTesting
static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
+ static final String PROP_ATTEMPTING_FACTORY_RESET = "sys.attempting_factory_reset";
+ static final String PROP_MAX_RESCUE_LEVEL_ATTEMPTED = "sys.max_rescue_level_attempted";
@VisibleForTesting
static final int LEVEL_NONE = 0;
@VisibleForTesting
@@ -92,6 +95,8 @@ public class RescueParty {
static final String TAG = "RescueParty";
@VisibleForTesting
static final long DEFAULT_OBSERVING_DURATION_MS = TimeUnit.DAYS.toMillis(2);
+ @VisibleForTesting
+ static final int DEVICE_CONFIG_RESET_MODE = Settings.RESET_MODE_TRUSTED_DEFAULTS;
private static final String NAME = "rescue-party-observer";
@@ -100,6 +105,10 @@ public class RescueParty {
private static final String PROP_VIRTUAL_DEVICE = "ro.hardware.virtual_device";
private static final String PROP_DEVICE_CONFIG_DISABLE_FLAG =
"persist.device_config.configuration.disable_rescue_party";
+ private static final String PROP_DISABLE_FACTORY_RESET_FLAG =
+ "persist.device_config.configuration.disable_rescue_party_factory_reset";
+ // The DeviceConfig namespace containing all RescueParty switches.
+ private static final String NAMESPACE_CONFIGURATION = "configuration";
private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
| ApplicationInfo.FLAG_SYSTEM;
@@ -150,7 +159,7 @@ public class RescueParty {
* Check if we're currently attempting to reboot for a factory reset.
*/
public static boolean isAttemptingFactoryReset() {
- return SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) == LEVEL_FACTORY_RESET;
+ return SystemProperties.getBoolean(PROP_ATTEMPTING_FACTORY_RESET, false);
}
/**
@@ -215,18 +224,48 @@ public class RescueParty {
if (SettingsToPropertiesMapper.isNativeFlagsResetPerformed()) {
String[] resetNativeCategories = SettingsToPropertiesMapper.getResetNativeCategories();
for (int i = 0; i < resetNativeCategories.length; i++) {
- DeviceConfig.resetToDefaults(Settings.RESET_MODE_TRUSTED_DEFAULTS,
+ // Don't let RescueParty reset the namespace for RescueParty switches.
+ if (NAMESPACE_CONFIGURATION.equals(resetNativeCategories[i])) {
+ continue;
+ }
+ DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE,
resetNativeCategories[i]);
}
}
}
+ private static int getMaxRescueLevel() {
+ return SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)
+ ? LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS : LEVEL_FACTORY_RESET;
+ }
+
+ /**
+ * Get the rescue level to perform if this is the n-th attempt at mitigating failure.
+ *
+ * @param mitigationCount: the mitigation attempt number (1 = first attempt etc.)
+ * @return the rescue level for the n-th mitigation attempt.
+ */
+ private static int getRescueLevel(int mitigationCount) {
+ if (mitigationCount == 1) {
+ return LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS;
+ } else if (mitigationCount == 2) {
+ return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES;
+ } else if (mitigationCount == 3) {
+ return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
+ } else if (mitigationCount >= 4) {
+ return getMaxRescueLevel();
+ } else {
+ Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
+ return LEVEL_NONE;
+ }
+ }
+
/**
* Get the next rescue level. This indicates the next level of mitigation that may be taken.
*/
private static int getNextRescueLevel() {
return MathUtils.constrain(SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) + 1,
- LEVEL_NONE, LEVEL_FACTORY_RESET);
+ LEVEL_NONE, getMaxRescueLevel());
}
/**
@@ -245,7 +284,11 @@ public class RescueParty {
private static void executeRescueLevel(Context context, @Nullable String failedPackage) {
final int level = SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE);
if (level == LEVEL_NONE) return;
+ executeRescueLevel(context, failedPackage, level);
+ }
+ private static void executeRescueLevel(Context context, @Nullable String failedPackage,
+ int level) {
Slog.w(TAG, "Attempting rescue level " + levelToString(level));
try {
executeRescueLevelInternal(context, level, failedPackage);
@@ -260,19 +303,53 @@ public class RescueParty {
private static void executeRescueLevelInternal(Context context, int level, @Nullable
String failedPackage) throws Exception {
FrameworkStatsLog.write(FrameworkStatsLog.RESCUE_PARTY_RESET_REPORTED, level);
+ // Try our best to reset all settings possible, and once finished
+ // rethrow any exception that we encountered
+ Exception res = null;
switch (level) {
case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
- resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, failedPackage);
+ try {
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS,
+ level);
+ } catch (Exception e) {
+ res = e;
+ }
+ try {
+ resetDeviceConfig(context, /*isScoped=*/true, failedPackage);
+ } catch (Exception e) {
+ res = e;
+ }
break;
case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
- resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, failedPackage);
+ try {
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES,
+ level);
+ } catch (Exception e) {
+ res = e;
+ }
+ try {
+ resetDeviceConfig(context, /*isScoped=*/true, failedPackage);
+ } catch (Exception e) {
+ res = e;
+ }
break;
case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
- resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, failedPackage);
+ try {
+ resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS,
+ level);
+ } catch (Exception e) {
+ res = e;
+ }
+ try {
+ resetDeviceConfig(context, /*isScoped=*/false, failedPackage);
+ } catch (Exception e) {
+ res = e;
+ }
break;
case LEVEL_FACTORY_RESET:
// Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
// when device shutting down.
+ SystemProperties.set(PROP_ATTEMPTING_FACTORY_RESET, "true");
Runnable runnable = new Runnable() {
@Override
public void run() {
@@ -287,6 +364,10 @@ public class RescueParty {
thread.start();
break;
}
+
+ if (res != null) {
+ throw res;
+ }
}
private static void logRescueException(int level, Throwable t) {
@@ -309,27 +390,18 @@ public class RescueParty {
}
}
- private static int getPackageUid(Context context, String packageName) {
- try {
- return context.getPackageManager().getPackageUid(packageName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- // Since UIDs are always >= 0, this value means the UID could not be determined.
- return -1;
+ private static void resetAllSettingsIfNecessary(Context context, int mode,
+ int level) throws Exception {
+ // No need to reset Settings again if they are already reset in the current level once.
+ if (SystemProperties.getInt(PROP_MAX_RESCUE_LEVEL_ATTEMPTED, LEVEL_NONE) >= level) {
+ return;
}
- }
-
- private static void resetAllSettings(Context context, int mode, @Nullable String failedPackage)
- throws Exception {
+ SystemProperties.set(PROP_MAX_RESCUE_LEVEL_ATTEMPTED, Integer.toString(level));
// Try our best to reset all settings possible, and once finished
// rethrow any exception that we encountered
Exception res = null;
final ContentResolver resolver = context.getContentResolver();
try {
- resetDeviceConfig(context, mode, failedPackage);
- } catch (Exception e) {
- res = new RuntimeException("Failed to reset config settings", e);
- }
- try {
Settings.Global.resetToDefaultsAsUser(resolver, null, mode, UserHandle.USER_SYSTEM);
} catch (Exception e) {
res = new RuntimeException("Failed to reset global settings", e);
@@ -346,37 +418,57 @@ public class RescueParty {
}
}
- private static void resetDeviceConfig(Context context, int resetMode,
- @Nullable String failedPackage) {
- if (!shouldPerformScopedResets() || failedPackage == null) {
- DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null);
- } else {
- performScopedReset(context, resetMode, failedPackage);
+ private static void resetDeviceConfig(Context context, boolean isScoped,
+ @Nullable String failedPackage) throws Exception {
+ final ContentResolver resolver = context.getContentResolver();
+ try {
+ if (!isScoped || failedPackage == null) {
+ resetAllAffectedNamespaces(context);
+ } else {
+ performScopedReset(context, failedPackage);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to reset config settings", e);
}
}
- private static boolean shouldPerformScopedResets() {
- int rescueLevel = MathUtils.constrain(
- SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE),
- LEVEL_NONE, LEVEL_FACTORY_RESET);
- return rescueLevel <= LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES;
+ private static void resetAllAffectedNamespaces(Context context) {
+ RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
+ Set<String> allAffectedNamespaces = rescuePartyObserver.getAllAffectedNamespaceSet();
+
+ Slog.w(TAG,
+ "Performing reset for all affected namespaces: "
+ + Arrays.toString(allAffectedNamespaces.toArray()));
+ Iterator<String> it = allAffectedNamespaces.iterator();
+ while (it.hasNext()) {
+ String namespace = it.next();
+ // Don't let RescueParty reset the namespace for RescueParty switches.
+ if (NAMESPACE_CONFIGURATION.equals(namespace)) {
+ continue;
+ }
+ DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE, namespace);
+ }
}
- private static void performScopedReset(Context context, int resetMode,
- @NonNull String failedPackage) {
+ private static void performScopedReset(Context context, @NonNull String failedPackage) {
RescuePartyObserver rescuePartyObserver = RescuePartyObserver.getInstance(context);
Set<String> affectedNamespaces = rescuePartyObserver.getAffectedNamespaceSet(
failedPackage);
- if (affectedNamespaces == null) {
- DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null);
- } else {
+ // If we can't find namespaces affected for current package,
+ // skip this round of reset.
+ if (affectedNamespaces != null) {
Slog.w(TAG,
"Performing scoped reset for package: " + failedPackage
+ ", affected namespaces: "
+ Arrays.toString(affectedNamespaces.toArray()));
Iterator<String> it = affectedNamespaces.iterator();
while (it.hasNext()) {
- DeviceConfig.resetToDefaults(resetMode, it.next());
+ String namespace = it.next();
+ // Don't let RescueParty reset the namespace for RescueParty switches.
+ if (NAMESPACE_CONFIGURATION.equals(namespace)) {
+ continue;
+ }
+ DeviceConfig.resetToDefaults(DEVICE_CONFIG_RESET_MODE, namespace);
}
}
}
@@ -418,10 +510,10 @@ public class RescueParty {
@Override
public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
- @FailureReasons int failureReason) {
+ @FailureReasons int failureReason, int mitigationCount) {
if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
- return mapRescueLevelToUserImpact(getNextRescueLevel());
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
} else {
return PackageHealthObserverImpact.USER_IMPACT_NONE;
}
@@ -429,16 +521,15 @@ public class RescueParty {
@Override
public boolean execute(@Nullable VersionedPackage failedPackage,
- @FailureReasons int failureReason) {
+ @FailureReasons int failureReason, int mitigationCount) {
if (isDisabled()) {
return false;
}
if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
- int triggerUid = getPackageUid(mContext, failedPackage.getPackageName());
- incrementRescueLevel(triggerUid);
+ final int level = getRescueLevel(mitigationCount);
executeRescueLevel(mContext,
- failedPackage == null ? null : failedPackage.getPackageName());
+ failedPackage == null ? null : failedPackage.getPackageName(), level);
return true;
} else {
return false;
@@ -514,6 +605,10 @@ public class RescueParty {
return mCallingPackageNamespaceSetMap.get(failedPackage);
}
+ private synchronized Set<String> getAllAffectedNamespaceSet() {
+ return new HashSet<String>(mNamespaceCallingPackageSetMap.keySet());
+ }
+
private synchronized Set<String> getCallingPackagesSet(String namespace) {
return mNamespaceCallingPackageSetMap.get(namespace);
}
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index b78b5d945a08..3ccb6e5b730b 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -185,9 +185,49 @@ public class ServiceWatcher implements ServiceConnection {
private final Handler mHandler;
private final Intent mIntent;
+ private final PackageMonitor mPackageMonitor = new PackageMonitor() {
+ @Override
+ public boolean onPackageChanged(String packageName, int uid, String[] components) {
+ return true;
+ }
+
+ @Override
+ public void onSomePackagesChanged() {
+ onBestServiceChanged(false);
+ }
+ };
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action == null) {
+ return;
+ }
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ if (userId == UserHandle.USER_NULL) {
+ return;
+ }
+
+ switch (action) {
+ case Intent.ACTION_USER_SWITCHED:
+ onUserSwitched(userId);
+ break;
+ case Intent.ACTION_USER_UNLOCKED:
+ onUserUnlocked(userId);
+ break;
+ default:
+ break;
+ }
+
+ }
+ };
+
@Nullable private final OnBindRunner mOnBind;
@Nullable private final Runnable mOnUnbind;
+ // write from caller thread only, read anywhere
+ private volatile boolean mRegistered;
+
// read/write from handler thread only
private int mCurrentUserId;
@@ -225,77 +265,65 @@ public class ServiceWatcher implements ServiceConnection {
}
/**
- * Register this class, which will start the process of determining the best matching service
- * and maintaining a binding to it. Will return false and fail if there are no possible matching
- * services at the time this functions is called.
+ * Returns true if there is at least one component that could satisfy the ServiceWatcher's
+ * constraints.
*/
- public boolean register() {
- if (mContext.getPackageManager().queryIntentServicesAsUser(mIntent,
+ public boolean checkServiceResolves() {
+ return !mContext.getPackageManager().queryIntentServicesAsUser(mIntent,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY,
- UserHandle.USER_SYSTEM).isEmpty()) {
- return false;
- }
+ UserHandle.USER_SYSTEM).isEmpty();
+ }
- new PackageMonitor() {
- @Override
- public boolean onPackageChanged(String packageName, int uid, String[] components) {
- return true;
- }
+ /**
+ * Starts the process of determining the best matching service and maintaining a binding to it.
+ */
+ public void register() {
+ Preconditions.checkState(!mRegistered);
- @Override
- public void onSomePackagesChanged() {
- onBestServiceChanged(false);
- }
- }.register(mContext, UserHandle.ALL, true, mHandler);
+ mPackageMonitor.register(mContext, UserHandle.ALL, true, mHandler);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action == null) {
- return;
- }
- int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId == UserHandle.USER_NULL) {
- return;
- }
+ mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, intentFilter, null,
+ mHandler);
- switch (action) {
- case Intent.ACTION_USER_SWITCHED:
- onUserSwitched(userId);
- break;
- case Intent.ACTION_USER_UNLOCKED:
- onUserUnlocked(userId);
- break;
- default:
- break;
- }
+ mCurrentUserId = ActivityManager.getCurrentUser();
- }
- }, UserHandle.ALL, intentFilter, null, mHandler);
+ mRegistered = true;
- mCurrentUserId = ActivityManager.getCurrentUser();
+ mHandler.post(() -> onBestServiceChanged(false));
+ }
+
+ /**
+ * Stops the process of determining the best matching service and releases any binding.
+ */
+ public void unregister() {
+ Preconditions.checkState(mRegistered);
+
+ mRegistered = false;
+
+ mPackageMonitor.unregister();
+ mContext.unregisterReceiver(mBroadcastReceiver);
mHandler.post(() -> onBestServiceChanged(false));
- return true;
}
private void onBestServiceChanged(boolean forceRebind) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentServicesAsUser(
- mIntent,
- GET_META_DATA | MATCH_DIRECT_BOOT_AUTO | MATCH_SYSTEM_ONLY,
- mCurrentUserId);
-
ServiceInfo bestServiceInfo = ServiceInfo.NONE;
- for (ResolveInfo resolveInfo : resolveInfos) {
- ServiceInfo serviceInfo = new ServiceInfo(resolveInfo, mCurrentUserId);
- if (serviceInfo.compareTo(bestServiceInfo) > 0) {
- bestServiceInfo = serviceInfo;
+
+ if (mRegistered) {
+ List<ResolveInfo> resolveInfos = mContext.getPackageManager().queryIntentServicesAsUser(
+ mIntent,
+ GET_META_DATA | MATCH_DIRECT_BOOT_AUTO | MATCH_SYSTEM_ONLY,
+ mCurrentUserId);
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ ServiceInfo serviceInfo = new ServiceInfo(resolveInfo, mCurrentUserId);
+ if (serviceInfo.compareTo(bestServiceInfo) > 0) {
+ bestServiceInfo = serviceInfo;
+ }
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 770e8de66bd7..eb55512b4d83 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -78,6 +78,7 @@ import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.LocalLog;
import android.util.Pair;
@@ -2564,12 +2565,33 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
TelephonyUtils.dataStateToString(pdcs.getState()));
intent.putExtra(PHONE_CONSTANTS_DATA_APN_KEY, pdcs.getApnSetting().getApnName());
intent.putExtra(PHONE_CONSTANTS_DATA_APN_TYPE_KEY,
- ApnSetting.getApnTypesStringFromBitmask(pdcs.getApnSetting().getApnTypeBitmask()));
+ getApnTypesStringFromBitmask(pdcs.getApnSetting().getApnTypeBitmask()));
intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, slotIndex);
intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL, Manifest.permission.READ_PHONE_STATE);
}
+ /**
+ * Reimplementation of {@link ApnSetting#getApnTypesStringFromBitmask}.
+ */
+ @VisibleForTesting
+ public static String getApnTypesStringFromBitmask(int apnTypeBitmask) {
+ List<String> types = new ArrayList<>();
+ int remainingApnTypes = apnTypeBitmask;
+ // special case for DEFAULT since it's not a pure bit
+ if ((remainingApnTypes & ApnSetting.TYPE_DEFAULT) == ApnSetting.TYPE_DEFAULT) {
+ types.add(ApnSetting.TYPE_DEFAULT_STRING);
+ remainingApnTypes &= ~ApnSetting.TYPE_DEFAULT;
+ }
+ while (remainingApnTypes != 0) {
+ int highestApnTypeBit = Integer.highestOneBit(remainingApnTypes);
+ String apnString = ApnSetting.getApnTypeString(highestApnTypeBit);
+ if (!TextUtils.isEmpty(apnString)) types.add(apnString);
+ remainingApnTypes &= ~highestApnTypeBit;
+ }
+ return TextUtils.join(",", types);
+ }
+
private void enforceNotifyPermissionOrCarrierPrivilege(String method) {
if (checkNotifyPermission()) {
return;
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 7051452f25cc..f49f1b15c93a 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -20,6 +20,8 @@ import static android.app.UiModeManager.DEFAULT_PRIORITY;
import static android.app.UiModeManager.MODE_NIGHT_AUTO;
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
import static android.app.UiModeManager.MODE_NIGHT_YES;
+import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
+import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
import static android.os.UserHandle.USER_SYSTEM;
import static android.util.TimeUtils.isTimeBetween;
@@ -30,6 +32,7 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.AlarmManager;
+import android.app.IOnProjectionStateChangeListener;
import android.app.IUiModeManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -48,10 +51,12 @@ import android.net.Uri;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -65,8 +70,10 @@ import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.util.ArraySet;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.DisableCarModeActivity;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
@@ -83,7 +90,9 @@ import java.time.DateTimeException;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -97,7 +106,9 @@ final class UiModeManagerService extends SystemService {
private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
private static final String SYSTEM_PROPERTY_DEVICE_THEME = "persist.sys.theme";
- final Object mLock = new Object();
+ private final Injector mInjector;
+ private final Object mLock = new Object();
+
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -162,17 +173,25 @@ final class UiModeManagerService extends SystemService {
private final LocalService mLocalService = new LocalService();
private PowerManagerInternal mLocalPowerManager;
+ @GuardedBy("mLock")
+ @Nullable
+ private SparseArray<List<ProjectionHolder>> mProjectionHolders;
+ @GuardedBy("mLock")
+ @Nullable
+ private SparseArray<RemoteCallbackList<IOnProjectionStateChangeListener>> mProjectionListeners;
+
public UiModeManagerService(Context context) {
- super(context);
- mConfiguration.setToDefaults();
+ this(context, /* setupWizardComplete= */ false, /* tm= */ null, new Injector());
}
@VisibleForTesting
protected UiModeManagerService(Context context, boolean setupWizardComplete,
- TwilightManager tm) {
- this(context);
+ TwilightManager tm, Injector injector) {
+ super(context);
+ mConfiguration.setToDefaults();
mSetupWizardComplete = setupWizardComplete;
mTwilightManager = tm;
+ mInjector = injector;
}
private static Intent buildHomeIntent(String category) {
@@ -639,7 +658,7 @@ final class UiModeManagerService extends SystemService {
// If the caller is the system, we will allow the DISABLE_CAR_MODE_ALL_PRIORITIES car
// mode flag to be specified; this is so that the user can disable car mode at all
// priorities using the persistent notification.
- boolean isSystemCaller = Binder.getCallingUid() == Process.SYSTEM_UID;
+ boolean isSystemCaller = mInjector.getCallingUid() == Process.SYSTEM_UID;
final int carModeFlags =
isSystemCaller ? flags : flags & ~UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES;
@@ -853,8 +872,308 @@ final class UiModeManagerService extends SystemService {
Binder.restoreCallingIdentity(ident);
}
}
+
+ @Override
+ public boolean requestProjection(IBinder binder,
+ @UiModeManager.ProjectionType int projectionType,
+ @NonNull String callingPackage) {
+ assertLegit(callingPackage);
+ assertSingleProjectionType(projectionType);
+ enforceProjectionTypePermissions(projectionType);
+ synchronized (mLock) {
+ if (mProjectionHolders == null) {
+ mProjectionHolders = new SparseArray<>(1);
+ }
+ if (!mProjectionHolders.contains(projectionType)) {
+ mProjectionHolders.put(projectionType, new ArrayList<>(1));
+ }
+ List<ProjectionHolder> currentHolders = mProjectionHolders.get(projectionType);
+
+ // For all projection types, it's a noop if already held.
+ for (int i = 0; i < currentHolders.size(); ++i) {
+ if (callingPackage.equals(currentHolders.get(i).mPackageName)) {
+ return true;
+ }
+ }
+
+ // Enforce projection type-specific restrictions here.
+
+ // Automotive projection can only be set if it is currently unset. The case where it
+ // is already set by the calling package is taken care of above.
+ if (projectionType == PROJECTION_TYPE_AUTOMOTIVE && !currentHolders.isEmpty()) {
+ return false;
+ }
+
+ ProjectionHolder projectionHolder = new ProjectionHolder(callingPackage,
+ projectionType, binder,
+ UiModeManagerService.this::releaseProjectionUnchecked);
+ if (!projectionHolder.linkToDeath()) {
+ return false;
+ }
+ currentHolders.add(projectionHolder);
+ Slog.d(TAG, "Package " + callingPackage + " set projection type "
+ + projectionType + ".");
+ onProjectionStateChangedLocked(projectionType);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean releaseProjection(@UiModeManager.ProjectionType int projectionType,
+ @NonNull String callingPackage) {
+ assertLegit(callingPackage);
+ assertSingleProjectionType(projectionType);
+ enforceProjectionTypePermissions(projectionType);
+ return releaseProjectionUnchecked(projectionType, callingPackage);
+ }
+
+ @Override
+ public @UiModeManager.ProjectionType int getActiveProjectionTypes() {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PROJECTION_STATE, "getActiveProjectionTypes");
+ @UiModeManager.ProjectionType int projectionTypeFlag = PROJECTION_TYPE_NONE;
+ synchronized (mLock) {
+ if (mProjectionHolders != null) {
+ for (int i = 0; i < mProjectionHolders.size(); ++i) {
+ if (!mProjectionHolders.valueAt(i).isEmpty()) {
+ projectionTypeFlag = projectionTypeFlag | mProjectionHolders.keyAt(i);
+ }
+ }
+ }
+ }
+ return projectionTypeFlag;
+ }
+
+ @Override
+ public List<String> getProjectingPackages(
+ @UiModeManager.ProjectionType int projectionType) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PROJECTION_STATE, "getProjectionState");
+ synchronized (mLock) {
+ List<String> packageNames = new ArrayList<>();
+ populateWithRelevantActivePackageNames(projectionType, packageNames);
+ return packageNames;
+ }
+ }
+
+ public void addOnProjectionStateChangeListener(IOnProjectionStateChangeListener listener,
+ @UiModeManager.ProjectionType int projectionType) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PROJECTION_STATE,
+ "registerProjectionStateListener");
+ if (projectionType == PROJECTION_TYPE_NONE) {
+ return;
+ }
+ synchronized (mLock) {
+ if (mProjectionListeners == null) {
+ mProjectionListeners = new SparseArray<>(1);
+ }
+ if (!mProjectionListeners.contains(projectionType)) {
+ mProjectionListeners.put(projectionType, new RemoteCallbackList<>());
+ }
+ if (mProjectionListeners.get(projectionType).register(listener)) {
+ // If any of those types are active, send a callback immediately.
+ List<String> packageNames = new ArrayList<>();
+ @UiModeManager.ProjectionType int activeProjectionTypes =
+ populateWithRelevantActivePackageNames(projectionType, packageNames);
+ if (!packageNames.isEmpty()) {
+ try {
+ listener.onProjectionStateChanged(activeProjectionTypes, packageNames);
+ } catch (RemoteException e) {
+ Slog.w(TAG,
+ "Failed a call to onProjectionStateChanged() during listener "
+ + "registration.");
+ }
+ }
+ }
+ }
+ }
+
+
+ public void removeOnProjectionStateChangeListener(
+ IOnProjectionStateChangeListener listener) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PROJECTION_STATE,
+ "unregisterProjectionStateListener");
+ synchronized (mLock) {
+ if (mProjectionListeners != null) {
+ for (int i = 0; i < mProjectionListeners.size(); ++i) {
+ mProjectionListeners.valueAt(i).unregister(listener);
+ }
+ }
+ }
+ }
};
+ private void enforceProjectionTypePermissions(@UiModeManager.ProjectionType int p) {
+ if ((p & PROJECTION_TYPE_AUTOMOTIVE) != 0) {
+ getContext().enforceCallingPermission(
+ android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION,
+ "toggleProjection");
+ }
+ }
+
+ private static void assertSingleProjectionType(@UiModeManager.ProjectionType int p) {
+ // To be a single projection type it must be greater than zero and an exact power of two.
+ boolean projectionTypeIsPowerOfTwoOrZero = (p & p - 1) == 0;
+ if (p <= 0 || !projectionTypeIsPowerOfTwoOrZero) {
+ throw new IllegalArgumentException("Must specify exactly one projection type.");
+ }
+ }
+
+ private static List<String> toPackageNameList(Collection<ProjectionHolder> c) {
+ List<String> packageNames = new ArrayList<>();
+ for (ProjectionHolder p : c) {
+ packageNames.add(p.mPackageName);
+ }
+ return packageNames;
+ }
+
+ /**
+ * Populates a list with the package names that have set any of the given projection types.
+ * @param projectionType the projection types to include
+ * @param packageNames the list to populate with package names
+ * @return the active projection types
+ */
+ @GuardedBy("mLock")
+ @UiModeManager.ProjectionType
+ private int populateWithRelevantActivePackageNames(
+ @UiModeManager.ProjectionType int projectionType, List<String> packageNames) {
+ packageNames.clear();
+ @UiModeManager.ProjectionType int projectionTypeFlag = PROJECTION_TYPE_NONE;
+ if (mProjectionHolders != null) {
+ for (int i = 0; i < mProjectionHolders.size(); ++i) {
+ int key = mProjectionHolders.keyAt(i);
+ List<ProjectionHolder> holders = mProjectionHolders.valueAt(i);
+ if ((projectionType & key) != 0) {
+ if (packageNames.addAll(toPackageNameList(holders))) {
+ projectionTypeFlag = projectionTypeFlag | key;
+ }
+ }
+ }
+ }
+ return projectionTypeFlag;
+ }
+
+ private boolean releaseProjectionUnchecked(@UiModeManager.ProjectionType int projectionType,
+ @NonNull String pkg) {
+ synchronized (mLock) {
+ boolean removed = false;
+ if (mProjectionHolders != null) {
+ List<ProjectionHolder> holders = mProjectionHolders.get(projectionType);
+ if (holders != null) {
+ // Iterate backward so we can safely remove while iterating.
+ for (int i = holders.size() - 1; i >= 0; --i) {
+ ProjectionHolder holder = holders.get(i);
+ if (pkg.equals(holder.mPackageName)) {
+ holder.unlinkToDeath();
+ Slog.d(TAG, "Projection type " + projectionType + " released by "
+ + pkg + ".");
+ holders.remove(i);
+ removed = true;
+ }
+ }
+ }
+ }
+ if (removed) {
+ onProjectionStateChangedLocked(projectionType);
+ } else {
+ Slog.w(TAG, pkg + " tried to release projection type " + projectionType
+ + " but was not set by that package.");
+ }
+ return removed;
+ }
+ }
+
+ private static class ProjectionHolder implements IBinder.DeathRecipient {
+ private final String mPackageName;
+ private final @UiModeManager.ProjectionType int mProjectionType;
+ private final IBinder mBinder;
+ private final ProjectionReleaser mProjectionReleaser;
+
+ private ProjectionHolder(String packageName,
+ @UiModeManager.ProjectionType int projectionType, IBinder binder,
+ ProjectionReleaser projectionReleaser) {
+ mPackageName = packageName;
+ mProjectionType = projectionType;
+ mBinder = binder;
+ mProjectionReleaser = projectionReleaser;
+ }
+
+ private boolean linkToDeath() {
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "linkToDeath failed for projection requester: " + mPackageName + ".",
+ e);
+ return false;
+ }
+ return true;
+ }
+
+ private void unlinkToDeath() {
+ mBinder.unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ Slog.w(TAG, "Projection holder " + mPackageName
+ + " died. Releasing projection type " + mProjectionType + ".");
+ mProjectionReleaser.release(mProjectionType, mPackageName);
+ }
+
+ private interface ProjectionReleaser {
+ boolean release(@UiModeManager.ProjectionType int projectionType,
+ @NonNull String packageName);
+ }
+ }
+
+ private void assertLegit(@NonNull String packageName) {
+ if (!doesPackageHaveCallingUid(packageName)) {
+ throw new SecurityException("Caller claimed bogus packageName: " + packageName + ".");
+ }
+ }
+
+ private boolean doesPackageHaveCallingUid(@NonNull String packageName) {
+ try {
+ return getContext().getPackageManager().getPackageUid(packageName, 0)
+ == mInjector.getCallingUid();
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void onProjectionStateChangedLocked(
+ @UiModeManager.ProjectionType int changedProjectionType) {
+ if (mProjectionListeners == null) {
+ return;
+ }
+ for (int i = 0; i < mProjectionListeners.size(); ++i) {
+ int listenerProjectionType = mProjectionListeners.keyAt(i);
+ // Every listener that is affected must be called back with all the state they are
+ // listening for.
+ if ((changedProjectionType & listenerProjectionType) != 0) {
+ RemoteCallbackList<IOnProjectionStateChangeListener> listeners =
+ mProjectionListeners.valueAt(i);
+ List<String> packageNames = new ArrayList<>();
+ @UiModeManager.ProjectionType int activeProjectionTypes =
+ populateWithRelevantActivePackageNames(listenerProjectionType,
+ packageNames);
+ int listenerCount = listeners.beginBroadcast();
+ for (int j = 0; j < listenerCount; ++j) {
+ try {
+ listeners.getBroadcastItem(j).onProjectionStateChanged(
+ activeProjectionTypes, packageNames);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed a call to onProjectionStateChanged().");
+ }
+ }
+ listeners.finishBroadcast();
+ }
+ }
+ }
+
private void onCustomTimeUpdated(int user) {
persistNightMode(user);
if (mNightMode != MODE_NIGHT_CUSTOM) return;
@@ -1656,4 +1975,11 @@ final class UiModeManagerService extends SystemService {
}
}
}
+
+ @VisibleForTesting
+ public static class Injector {
+ public int getCallingUid() {
+ return Binder.getCallingUid();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActiveInstrumentation.java b/services/core/java/com/android/server/am/ActiveInstrumentation.java
index db63638bbfba..43474d5f22d4 100644
--- a/services/core/java/com/android/server/am/ActiveInstrumentation.java
+++ b/services/core/java/com/android/server/am/ActiveInstrumentation.java
@@ -70,6 +70,9 @@ class ActiveInstrumentation {
// The uid of the process who started this instrumentation.
int mSourceUid;
+ // True if instrumentation should take place without restarting the target process.
+ boolean mNoRestart;
+
ActiveInstrumentation(ActivityManagerService service) {
mService = service;
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4a338b37e41f..e1124ab50a39 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
import static android.os.Process.NFC_UID;
@@ -145,7 +146,7 @@ public final class ActiveServices {
private static final boolean SHOW_DUNGEON_NOTIFICATION = false;
public static final int FGS_FEATURE_DENIED = 0;
- public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 1;
+ public static final int FGS_FEATURE_ALLOWED_BY_UID_STATE = 1;
public static final int FGS_FEATURE_ALLOWED_BY_UID_VISIBLE = 2;
public static final int FGS_FEATURE_ALLOWED_BY_FLAG = 3;
public static final int FGS_FEATURE_ALLOWED_BY_SYSTEM_UID = 4;
@@ -154,10 +155,12 @@ public final class ActiveServices {
public static final int FGS_FEATURE_ALLOWED_BY_PERMISSION = 7;
public static final int FGS_FEATURE_ALLOWED_BY_WHITELIST = 8;
public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER = 9;
+ public static final int FGS_FEATURE_ALLOWED_BY_PROC_STATE = 10;
+ public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST = 11;
@IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
FGS_FEATURE_DENIED,
- FGS_FEATURE_ALLOWED_BY_PROC_STATE,
+ FGS_FEATURE_ALLOWED_BY_UID_STATE,
FGS_FEATURE_ALLOWED_BY_UID_VISIBLE,
FGS_FEATURE_ALLOWED_BY_FLAG,
FGS_FEATURE_ALLOWED_BY_SYSTEM_UID,
@@ -165,7 +168,9 @@ public final class ActiveServices {
FGS_FEATURE_ALLOWED_BY_TOKEN,
FGS_FEATURE_ALLOWED_BY_PERMISSION,
FGS_FEATURE_ALLOWED_BY_WHITELIST,
- FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER
+ FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER,
+ FGS_FEATURE_ALLOWED_BY_PROC_STATE,
+ FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST
})
@Retention(RetentionPolicy.SOURCE)
public @interface FgsFeatureRetCode {}
@@ -576,18 +581,11 @@ public final class ActiveServices {
if (r.mAllowStartForeground == FGS_FEATURE_DENIED
&& (mAm.mConstants.mFlagFgsStartRestrictionEnabled
|| isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
- if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
- && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
- // uid is on DeviceIdleController's allowlist.
- Slog.d(TAG, "startForegroundService() mAllowStartForeground false "
- + "but allowlist true: service " + r.shortInstanceName);
- } else {
- Slog.w(TAG, "startForegroundService() not allowed due to "
- + "mAllowStartForeground false: service "
- + r.shortInstanceName);
- showFgsBgRestrictedNotificationLocked(r);
- return null;
- }
+ Slog.w(TAG, "startForegroundService() not allowed due to "
+ + "mAllowStartForeground false: service "
+ + r.shortInstanceName);
+ showFgsBgRestrictedNotificationLocked(r);
+ return null;
}
}
}
@@ -1488,20 +1486,12 @@ public final class ActiveServices {
if (r.mAllowStartForeground == FGS_FEATURE_DENIED
&& (mAm.mConstants.mFlagFgsStartRestrictionEnabled
|| isChangeEnabled(FGS_BG_START_RESTRICTION_CHANGE_ID, r))) {
- if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
- && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
- // uid is on DeviceIdleController's allowlist.
- Slog.d(TAG, "Service.startForeground() "
- + "mAllowStartForeground false but allowlist true: service "
- + r.shortInstanceName);
- } else {
- Slog.w(TAG, "Service.startForeground() not allowed due to "
- + "mAllowStartForeground false: service "
- + r.shortInstanceName);
- showFgsBgRestrictedNotificationLocked(r);
- updateServiceForegroundLocked(r.app, true);
- ignoreForeground = true;
- }
+ Slog.w(TAG, "Service.startForeground() not allowed due to "
+ + "mAllowStartForeground false: service "
+ + r.shortInstanceName);
+ showFgsBgRestrictedNotificationLocked(r);
+ updateServiceForegroundLocked(r.app, true);
+ ignoreForeground = true;
}
}
}
@@ -4944,38 +4934,39 @@ public final class ActiveServices {
r.mAllowWhileInUsePermissionInFgs = true;
}
- if (!r.mAllowWhileInUsePermissionInFgs || (r.mAllowStartForeground == FGS_FEATURE_DENIED)) {
- final @FgsFeatureRetCode int temp = shouldAllowFgsFeatureLocked(callingPackage,
- callingPid, callingUid, intent, r, allowBackgroundActivityStarts);
+ if (!r.mAllowWhileInUsePermissionInFgs
+ || (r.mAllowStartForeground == FGS_FEATURE_DENIED)) {
+ final @FgsFeatureRetCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
+ callingPackage, callingPid, callingUid, r, allowBackgroundActivityStarts);
if (!r.mAllowWhileInUsePermissionInFgs) {
- r.mAllowWhileInUsePermissionInFgs = (temp != FGS_FEATURE_DENIED);
+ r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != FGS_FEATURE_DENIED);
}
if (r.mAllowStartForeground == FGS_FEATURE_DENIED) {
- r.mAllowStartForeground = temp;
+ r.mAllowStartForeground = shouldAllowFgsStartForegroundLocked(allowWhileInUse,
+ callingPackage, callingPid, callingUid, intent, r,
+ allowBackgroundActivityStarts);
}
}
}
/**
- * Should allow FGS feature or not.
+ * Should allow while-in-use permissions in FGS or not.
+ * A typical BG started FGS is not allowed to have while-in-use permissions.
* @param callingPackage caller app's package name.
* @param callingUid caller app's uid.
- * @param intent intent to start/bind service.
* @param r the service to start.
* @return {@link FgsFeatureRetCode}
*/
- private @FgsFeatureRetCode int shouldAllowFgsFeatureLocked(String callingPackage,
- int callingPid, int callingUid, Intent intent, ServiceRecord r,
+ private @FgsFeatureRetCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
+ int callingPid, int callingUid, ServiceRecord r,
boolean allowBackgroundActivityStarts) {
int ret = FGS_FEATURE_DENIED;
- final StringBuilder sb = new StringBuilder(64);
final int uidState = mAm.getUidState(callingUid);
if (ret == FGS_FEATURE_DENIED) {
// Is the calling UID at PROCESS_STATE_TOP or above?
if (uidState <= ActivityManager.PROCESS_STATE_TOP) {
- sb.append("uidState=").append(uidState);
- ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE;
+ ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
}
}
@@ -5010,7 +5001,6 @@ public final class ActiveServices {
}
if (isCallerSystem) {
- sb.append("callingUid=").append(callingAppId);
ret = FGS_FEATURE_ALLOWED_BY_SYSTEM_UID;
}
}
@@ -5049,6 +5039,53 @@ public final class ActiveServices {
ret = FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER;
}
}
+ return ret;
+ }
+
+ /**
+ * Should allow the FGS to start (AKA startForeground()) or not.
+ * The check in this method is in addition to check in
+ * {@link #shouldAllowFgsWhileInUsePermissionLocked}
+ * @param allowWhileInUse the return code from {@link #shouldAllowFgsWhileInUsePermissionLocked}
+ * @param callingPackage caller app's package name.
+ * @param callingUid caller app's uid.
+ * @param intent intent to start/bind service.
+ * @param r the service to start.
+ * @return {@link FgsFeatureRetCode}
+ */
+ private @FgsFeatureRetCode int shouldAllowFgsStartForegroundLocked(
+ @FgsFeatureRetCode int allowWhileInUse, String callingPackage, int callingPid,
+ int callingUid, Intent intent, ServiceRecord r, boolean allowBackgroundActivityStarts) {
+ int ret = allowWhileInUse;
+
+ final StringBuilder sb = new StringBuilder(64);
+ final int uidState = mAm.getUidState(callingUid);
+ if (ret == FGS_FEATURE_DENIED) {
+ // Is the calling UID at PROCESS_STATE_TOP or above?
+ if (uidState <= ActivityManager.PROCESS_STATE_TOP) {
+ sb.append("uidState=").append(uidState);
+ ret = FGS_FEATURE_ALLOWED_BY_UID_STATE;
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
+ for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
+ final ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i);
+ if (pr.uid == callingUid
+ && pr.mAllowStartFgsState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ ret = FGS_FEATURE_ALLOWED_BY_PROC_STATE;
+ break;
+ }
+ }
+ }
+
+ if (ret == FGS_FEATURE_DENIED) {
+ if (mAm.mConstants.mFlagFgsStartTempAllowListEnabled
+ && mAm.isOnDeviceIdleWhitelistLocked(r.appInfo.uid, false)) {
+ // uid is on DeviceIdleController's allowlist.
+ ret = FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST;
+ }
+ }
final String debugInfo =
"[callingPackage: " + callingPackage
@@ -5071,8 +5108,8 @@ public final class ActiveServices {
switch (code) {
case FGS_FEATURE_DENIED:
return "DENIED";
- case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
- return "ALLOWED_BY_PROC_STATE";
+ case FGS_FEATURE_ALLOWED_BY_UID_STATE:
+ return "ALLOWED_BY_UID_STATE";
case FGS_FEATURE_ALLOWED_BY_UID_VISIBLE:
return "ALLOWED_BY_UID_VISIBLE";
case FGS_FEATURE_ALLOWED_BY_FLAG:
@@ -5089,13 +5126,17 @@ public final class ActiveServices {
return "ALLOWED_BY_WHITELIST";
case FGS_FEATURE_ALLOWED_BY_DEVICE_OWNER:
return "ALLOWED_BY_DEVICE_OWNER";
+ case FGS_FEATURE_ALLOWED_BY_PROC_STATE:
+ return "ALLOWED_BY_PROC_STATE";
+ case FGS_FEATURE_ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST:
+ return "ALLOWED_BY_DEVICE_IDLE_ALLOW_LIST";
default:
return "";
}
}
private static boolean isFgsBgStart(@FgsFeatureRetCode int code) {
- return code != FGS_FEATURE_ALLOWED_BY_PROC_STATE
+ return code != FGS_FEATURE_ALLOWED_BY_UID_STATE
&& code != FGS_FEATURE_ALLOWED_BY_UID_VISIBLE;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index b54a917e7c1d..9c4a358e2592 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -91,6 +91,9 @@ final class ActivityManagerConstants extends ContentObserver {
static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration";
static final String KEY_PENDINGINTENT_WARNING_THRESHOLD = "pendingintent_warning_threshold";
static final String KEY_MIN_CRASH_INTERVAL = "min_crash_interval";
+ static final String KEY_PROCESS_CRASH_COUNT_RESET_INTERVAL =
+ "process_crash_count_reset_interval";
+ static final String KEY_PROCESS_CRASH_COUNT_LIMIT = "process_crash_count_limit";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
@@ -126,6 +129,8 @@ final class ActivityManagerConstants extends ContentObserver {
private static final int DEFAULT_PENDINGINTENT_WARNING_THRESHOLD = 2000;
private static final int DEFAULT_MIN_CRASH_INTERVAL = 2 * 60 * 1000;
private static final int DEFAULT_MAX_PHANTOM_PROCESSES = 32;
+ private static final int DEFAULT_PROCESS_CRASH_COUNT_RESET_INTERVAL = 12 * 60 * 60 * 1000;
+ private static final int DEFAULT_PROCESS_CRASH_COUNT_LIMIT = 12;
// Flag stored in the DeviceConfig API.
@@ -301,9 +306,27 @@ final class ActivityManagerConstants extends ContentObserver {
/**
* The minimum time we allow between crashes, for us to consider this
* application to be bad and stop its services and reject broadcasts.
+ * A reasonable interval here would be anything between 1-3 minutes.
*/
public static int MIN_CRASH_INTERVAL = DEFAULT_MIN_CRASH_INTERVAL;
+ /**
+ * We will allow for a maximum number of {@link PROCESS_CRASH_COUNT_LIMIT} crashes within this
+ * time period before we consider the application to be bad and stop services and reject
+ * broadcasts.
+ * A reasonable reset interval here would be anything between 10-20 hours along with a crash
+ * count limit of 10-20 crashes.
+ */
+ static long PROCESS_CRASH_COUNT_RESET_INTERVAL = DEFAULT_PROCESS_CRASH_COUNT_RESET_INTERVAL;
+
+ /**
+ * The maximum number of crashes allowed within {@link PROCESS_CRASH_COUNT_RESET_INTERVAL_MS}
+ * before we consider the application to be bad and stop services and reject broadcasts.
+ * A reasonable crash count limit here would be anything between 10-20 crashes along with a
+ * reset interval of 10-20 hours.
+ */
+ static int PROCESS_CRASH_COUNT_LIMIT = DEFAULT_PROCESS_CRASH_COUNT_LIMIT;
+
// Indicates whether the activity starts logging is enabled.
// Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED
volatile boolean mFlagActivityStartsLoggingEnabled;
@@ -694,6 +717,11 @@ final class ActivityManagerConstants extends ContentObserver {
DEFAULT_MIN_CRASH_INTERVAL);
PENDINGINTENT_WARNING_THRESHOLD = mParser.getInt(KEY_PENDINGINTENT_WARNING_THRESHOLD,
DEFAULT_PENDINGINTENT_WARNING_THRESHOLD);
+ PROCESS_CRASH_COUNT_RESET_INTERVAL = mParser.getInt(
+ KEY_PROCESS_CRASH_COUNT_RESET_INTERVAL,
+ DEFAULT_PROCESS_CRASH_COUNT_RESET_INTERVAL);
+ PROCESS_CRASH_COUNT_LIMIT = mParser.getInt(KEY_PROCESS_CRASH_COUNT_LIMIT,
+ DEFAULT_PROCESS_CRASH_COUNT_LIMIT);
if (POWER_CHECK_INTERVAL != currentPowerCheckInterval) {
mService.mHandler.removeMessages(
@@ -934,6 +962,10 @@ final class ActivityManagerConstants extends ContentObserver {
pw.println(TOP_TO_FGS_GRACE_DURATION);
pw.print(" "); pw.print(KEY_MIN_CRASH_INTERVAL); pw.print("=");
pw.println(MIN_CRASH_INTERVAL);
+ pw.print(" "); pw.print(KEY_PROCESS_CRASH_COUNT_RESET_INTERVAL); pw.print("=");
+ pw.println(PROCESS_CRASH_COUNT_RESET_INTERVAL);
+ pw.print(" "); pw.print(KEY_PROCESS_CRASH_COUNT_LIMIT); pw.print("=");
+ pw.println(PROCESS_CRASH_COUNT_LIMIT);
pw.print(" "); pw.print(KEY_IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES); pw.print("=");
pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES.toArray()));
pw.print(" "); pw.print(KEY_IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES); pw.print("=");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 112814c69d9b..4ca135808996 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -25,6 +25,7 @@ import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
+import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
@@ -194,6 +195,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageManager;
+import android.content.pm.IncrementalStatesInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -4890,6 +4892,15 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public boolean isIntentSenderImmutable(IIntentSender pendingResult) {
+ if (pendingResult instanceof PendingIntentRecord) {
+ final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
+ return (res.key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
+ }
+ return false;
+ }
+
+ @Override
public boolean isIntentSenderAnActivity(IIntentSender pendingResult) {
if (!(pendingResult instanceof PendingIntentRecord)) {
return false;
@@ -7565,6 +7576,20 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
+ boolean isPackageLoading = false;
+ // Notify package manager service to possibly update package state
+ if (r != null && r.info != null && r.info.packageName != null) {
+ mPackageManagerInt.notifyPackageCrashOrAnr(r.info.packageName);
+ IncrementalStatesInfo incrementalStatesInfo =
+ mPackageManagerInt.getIncrementalStatesInfo(r.info.packageName, r.uid,
+ r.userId);
+ isPackageLoading = incrementalStatesInfo.isLoading();
+ if (isPackageLoading) {
+ // Report in the main log that the package is still loading
+ Slog.e(TAG, "App crashed when package " + r.info.packageName + " is "
+ + ((int) (incrementalStatesInfo.getProgress() * 100)) + "% loaded.");
+ }
+ }
EventLogTags.writeAmCrash(Binder.getCallingPid(),
UserHandle.getUserId(Binder.getCallingUid()), processName,
@@ -7590,7 +7615,8 @@ public class ActivityManagerService extends IActivityManager.Stub
: FrameworkStatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__UNKNOWN,
processName.equals("system_server") ? ServerProtoEnums.SYSTEM_SERVER
: (r != null) ? r.getProcessClassEnum()
- : ServerProtoEnums.ERROR_SOURCE_UNKNOWN
+ : ServerProtoEnums.ERROR_SOURCE_UNKNOWN,
+ isPackageLoading
);
final int relaunchReason = r == null ? RELAUNCH_REASON_NONE
@@ -7606,10 +7632,6 @@ public class ActivityManagerService extends IActivityManager.Stub
eventType, r, processName, null, null, null, null, null, null, crashInfo);
mAppErrors.crashApplication(r, crashInfo);
- // Notify package manager service to possibly update package state
- if (r != null && r.info != null && r.info.packageName != null) {
- mPackageManagerInt.notifyPackageCrashOrAnr(r.info.packageName);
- }
}
public void handleApplicationStrictModeViolation(
@@ -7736,11 +7758,15 @@ public class ActivityManagerService extends IActivityManager.Stub
* @return true if the process should exit immediately (WTF is fatal)
*/
@Override
- public boolean handleApplicationWtf(final IBinder app, final String tag, boolean system,
- final ApplicationErrorReport.ParcelableCrashInfo crashInfo, int immediateCallerPid) {
+ public boolean handleApplicationWtf(@Nullable final IBinder app, @Nullable final String tag,
+ boolean system, @NonNull final ApplicationErrorReport.ParcelableCrashInfo crashInfo,
+ int immediateCallerPid) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ // Internal callers in RuntimeInit should always generate a crashInfo.
+ Preconditions.checkNotNull(crashInfo);
+
// If this is coming from the system, we could very well have low-level
// system locks held, so we want to do this all asynchronously. And we
// never want this to become fatal, so there is that too.
@@ -7773,14 +7799,15 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- ProcessRecord handleApplicationWtfInner(int callingUid, int callingPid, IBinder app, String tag,
- final ApplicationErrorReport.CrashInfo crashInfo) {
+ ProcessRecord handleApplicationWtfInner(int callingUid, int callingPid, @Nullable IBinder app,
+ @Nullable String tag, @Nullable final ApplicationErrorReport.CrashInfo crashInfo) {
final ProcessRecord r = findAppProcess(app, "WTF");
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
EventLogTags.writeAmWtf(UserHandle.getUserId(callingUid), callingPid,
- processName, r == null ? -1 : r.info.flags, tag, crashInfo.exceptionMessage);
+ processName, r == null ? -1 : r.info.flags, tag,
+ crashInfo == null ? "unknown" : crashInfo.exceptionMessage);
FrameworkStatsLog.write(FrameworkStatsLog.WTF_OCCURRED, callingUid, tag, processName,
callingPid, (r != null) ? r.getProcessClassEnum() : 0);
@@ -14192,9 +14219,12 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized(this) {
InstrumentationInfo ii = null;
ApplicationInfo ai = null;
+
+ boolean noRestart = (flags & INSTR_FLAG_NO_RESTART) != 0;
+
try {
ii = mContext.getPackageManager().getInstrumentationInfo(
- className, STOCK_PM_FLAGS);
+ className, STOCK_PM_FLAGS);
ai = AppGlobals.getPackageManager().getApplicationInfo(
ii.targetPackage, STOCK_PM_FLAGS, userId);
} catch (PackageManager.NameNotFoundException e) {
@@ -14210,24 +14240,33 @@ public class ActivityManagerService extends IActivityManager.Stub
"Unable to find instrumentation target package: " + ii.targetPackage);
return false;
}
- if (!ai.hasCode()) {
+
+ if (ii.targetPackage.equals("android")) {
+ if (!noRestart) {
+ reportStartInstrumentationFailureLocked(watcher, className,
+ "Cannot instrument system server without 'no-restart'");
+ return false;
+ }
+ } else if (!ai.hasCode()) {
reportStartInstrumentationFailureLocked(watcher, className,
"Instrumentation target has no code: " + ii.targetPackage);
return false;
}
- int match = mContext.getPackageManager().checkSignatures(
- ii.targetPackage, ii.packageName);
- if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
- String msg = "Permission Denial: starting instrumentation "
- + className + " from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingPid()
- + " not allowed because package " + ii.packageName
- + " does not have a signature matching the target "
- + ii.targetPackage;
- reportStartInstrumentationFailureLocked(watcher, className, msg);
- throw new SecurityException(msg);
+ if (!Build.IS_DEBUGGABLE) {
+ int match = mContext.getPackageManager().checkSignatures(
+ ii.targetPackage, ii.packageName);
+ if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
+ String msg = "Permission Denial: starting instrumentation "
+ + className + " from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingPid()
+ + " not allowed because package " + ii.packageName
+ + " does not have a signature matching the target "
+ + ii.targetPackage;
+ reportStartInstrumentationFailureLocked(watcher, className, msg);
+ throw new SecurityException(msg);
+ }
}
ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
@@ -14250,6 +14289,7 @@ public class ActivityManagerService extends IActivityManager.Stub
activeInstr.mHasBackgroundActivityStartsPermission = checkPermission(
START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED;
+ activeInstr.mNoRestart = noRestart;
boolean disableHiddenApiChecks = ai.usesNonSdkApi()
|| (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
@@ -14265,18 +14305,25 @@ public class ActivityManagerService extends IActivityManager.Stub
&& (flags & INSTR_FLAG_DISABLE_ISOLATED_STORAGE) != 0;
final long origId = Binder.clearCallingIdentity();
- // Instrumentation can kill and relaunch even persistent processes
- forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId,
- "start instr");
- // Inform usage stats to make the target package active
- if (mUsageStatsService != null) {
- mUsageStatsService.reportEvent(ii.targetPackage, userId,
- UsageEvents.Event.SYSTEM_INTERACTION);
+
+ ProcessRecord app;
+ if (noRestart) {
+ app = getProcessRecordLocked(ai.processName, ai.uid, true);
+ } else {
+ // Instrumentation can kill and relaunch even persistent processes
+ forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId,
+ "start instr");
+ // Inform usage stats to make the target package active
+ if (mUsageStatsService != null) {
+ mUsageStatsService.reportEvent(ii.targetPackage, userId,
+ UsageEvents.Event.SYSTEM_INTERACTION);
+ }
+ app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
+ disableTestApiChecks, mountExtStorageFull, abiOverride,
+ ZYGOTE_POLICY_FLAG_EMPTY);
}
- ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks,
- disableTestApiChecks, mountExtStorageFull, abiOverride,
- ZYGOTE_POLICY_FLAG_EMPTY);
+
app.setActiveInstrumentation(activeInstr);
activeInstr.mFinished = false;
activeInstr.mSourceUid = callingUid;
@@ -14292,11 +14339,34 @@ public class ActivityManagerService extends IActivityManager.Stub
ii.packageName, AppOpsManager.MODE_ALLOWED);
}
Binder.restoreCallingIdentity(origId);
+
+ if (noRestart) {
+ instrumentWithoutRestart(activeInstr, ai);
+ }
}
return true;
}
+ private void instrumentWithoutRestart(ActiveInstrumentation activeInstr,
+ ApplicationInfo targetInfo) {
+ ProcessRecord pr;
+ synchronized (this) {
+ pr = getProcessRecordLocked(targetInfo.processName, targetInfo.uid, true);
+ }
+
+ try {
+ pr.thread.instrumentWithoutRestart(
+ activeInstr.mClass,
+ activeInstr.mArguments,
+ activeInstr.mWatcher,
+ activeInstr.mUiAutomationConnection,
+ targetInfo);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "RemoteException from instrumentWithoutRestart", e);
+ }
+ }
+
private boolean isCallerShell() {
final int callingUid = Binder.getCallingUid();
return callingUid == SHELL_UID || callingUid == ROOT_UID;
@@ -14395,8 +14465,11 @@ public class ActivityManagerService extends IActivityManager.Stub
instr.removeProcess(app);
app.setActiveInstrumentation(null);
- forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId,
- "finished inst");
+ if (!instr.mNoRestart) {
+ forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false,
+ app.userId,
+ "finished inst");
+ }
}
public void finishInstrumentation(IApplicationThread target,
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index cf900ab9b0e6..0b4d27f4990b 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -19,6 +19,8 @@ package com.android.server.am;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
+import static com.android.server.am.ActivityManagerConstants.PROCESS_CRASH_COUNT_LIMIT;
+import static com.android.server.am.ActivityManagerConstants.PROCESS_CRASH_COUNT_RESET_INTERVAL;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -44,6 +46,7 @@ import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -90,6 +93,12 @@ class AppErrors {
private final ProcessMap<Long> mProcessCrashShowDialogTimes = new ProcessMap<>();
/**
+ * A pairing between how many times various processes have crashed since a given time.
+ * Entry and exit conditions for this map are similar to mProcessCrashTimes.
+ */
+ private final ProcessMap<Pair<Long, Integer>> mProcessCrashCounts = new ProcessMap<>();
+
+ /**
* Set of applications that we consider to be bad, and will reject
* incoming broadcasts from (which the user has no control over).
* Processes are added to this set when they have crashed twice within
@@ -118,6 +127,7 @@ class AppErrors {
mProcessCrashTimes.clear();
mProcessCrashTimesPersistent.clear();
mProcessCrashShowDialogTimes.clear();
+ mProcessCrashCounts.clear();
synchronized (mBadProcesses) {
mBadProcesses.clear();
}
@@ -196,9 +206,9 @@ class AppErrors {
}
boolean dumpLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage) {
+ final long now = SystemClock.uptimeMillis();
if (!mProcessCrashTimes.getMap().isEmpty()) {
boolean printed = false;
- final long now = SystemClock.uptimeMillis();
final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
final int processCount = pmap.size();
for (int ip = 0; ip < processCount; ip++) {
@@ -227,6 +237,36 @@ class AppErrors {
}
}
+ if (!mProcessCrashCounts.getMap().isEmpty()) {
+ boolean printed = false;
+ final ArrayMap<String, SparseArray<Pair<Long, Integer>>> pmap =
+ mProcessCrashCounts.getMap();
+ final int processCount = pmap.size();
+ for (int ip = 0; ip < processCount; ip++) {
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<Pair<Long, Integer>> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null && (r == null || !r.pkgList.containsKey(dumpPackage))) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) pw.println();
+ needSep = true;
+ pw.println(" First time processes crashed and counts:");
+ printed = true;
+ }
+ pw.print(" Process "); pw.print(pname);
+ pw.print(" uid "); pw.print(puid);
+ pw.print(": first crashed ");
+ TimeUtils.formatDuration(now - uids.valueAt(i).first, pw);
+ pw.print(" ago; crashes since then: "); pw.println(uids.valueAt(i).second);
+ }
+ }
+ }
+
if (!mBadProcesses.getMap().isEmpty()) {
boolean printed = false;
final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
@@ -295,34 +335,50 @@ class AppErrors {
void resetProcessCrashTimeLocked(final String processName, final int uid) {
mProcessCrashTimes.remove(processName, uid);
+ mProcessCrashCounts.remove(processName, uid);
}
void resetProcessCrashTimeLocked(boolean resetEntireUser, int appId, int userId) {
- final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
- for (int ip = pmap.size() - 1; ip >= 0; ip--) {
- SparseArray<Long> ba = pmap.valueAt(ip);
- for (int i = ba.size() - 1; i >= 0; i--) {
- boolean remove = false;
- final int entUid = ba.keyAt(i);
- if (!resetEntireUser) {
- if (userId == UserHandle.USER_ALL) {
- if (UserHandle.getAppId(entUid) == appId) {
- remove = true;
- }
- } else {
- if (entUid == UserHandle.getUid(userId, appId)) {
- remove = true;
- }
+ final ArrayMap<String, SparseArray<Long>> pTimeMap = mProcessCrashTimes.getMap();
+ for (int ip = pTimeMap.size() - 1; ip >= 0; ip--) {
+ SparseArray<Long> ba = pTimeMap.valueAt(ip);
+ resetProcessCrashMapLocked(ba, resetEntireUser, appId, userId);
+ if (ba.size() == 0) {
+ pTimeMap.removeAt(ip);
+ }
+ }
+
+ final ArrayMap<String, SparseArray<Pair<Long, Integer>>> pCountMap =
+ mProcessCrashCounts.getMap();
+ for (int ip = pCountMap.size() - 1; ip >= 0; ip--) {
+ SparseArray<Pair<Long, Integer>> ba = pCountMap.valueAt(ip);
+ resetProcessCrashMapLocked(ba, resetEntireUser, appId, userId);
+ if (ba.size() == 0) {
+ pCountMap.removeAt(ip);
+ }
+ }
+ }
+
+ private void resetProcessCrashMapLocked(SparseArray<?> ba, boolean resetEntireUser,
+ int appId, int userId) {
+ for (int i = ba.size() - 1; i >= 0; i--) {
+ boolean remove = false;
+ final int entUid = ba.keyAt(i);
+ if (!resetEntireUser) {
+ if (userId == UserHandle.USER_ALL) {
+ if (UserHandle.getAppId(entUid) == appId) {
+ remove = true;
+ }
+ } else {
+ if (entUid == UserHandle.getUid(userId, appId)) {
+ remove = true;
}
- } else if (UserHandle.getUserId(entUid) == userId) {
- remove = true;
- }
- if (remove) {
- ba.removeAt(i);
}
+ } else if (UserHandle.getUserId(entUid) == userId) {
+ remove = true;
}
- if (ba.size() == 0) {
- pmap.removeAt(ip);
+ if (remove) {
+ ba.removeAt(i);
}
}
}
@@ -567,12 +623,6 @@ class AppErrors {
if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
}
- if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
- // XXX Can't keep track of crash time for isolated processes,
- // since they don't have a persistent identity.
- mProcessCrashTimes.put(r.processName, r.uid,
- SystemClock.uptimeMillis());
- }
}
if (appErrorIntent != null) {
@@ -742,11 +792,14 @@ class AppErrors {
}
}
- if (crashTime != null && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL) {
- // The process crashed again very quickly. If it was a bound foreground service, let's
- // try to restart again in a while, otherwise the process loses!
- Slog.w(TAG, "Process " + app.processName
- + " has crashed too many times: killing!");
+ final boolean quickCrash = crashTime != null
+ && now < crashTime + ActivityManagerConstants.MIN_CRASH_INTERVAL;
+ if (quickCrash || isProcOverCrashLimit(app, now)) {
+ // The process either crashed again very quickly or has been crashing periodically in
+ // the last few hours. If it was a bound foreground service, let's try to restart again
+ // in a while, otherwise the process loses!
+ Slog.w(TAG, "Process " + app.processName + " has crashed too many times, killing!"
+ + " Reason: " + (quickCrash ? "crashed quickly" : "over process crash limit"));
EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
app.userId, app.processName, app.uid);
mService.mAtmInternal.onHandleAppCrash(app.getWindowProcessController());
@@ -765,6 +818,7 @@ class AppErrors {
new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
}
mProcessCrashTimes.remove(app.processName, app.uid);
+ mProcessCrashCounts.remove(app.processName, app.uid);
}
app.bad = true;
app.removed = true;
@@ -809,12 +863,30 @@ class AppErrors {
// because they don't have a persistent identity.
mProcessCrashTimes.put(app.processName, app.uid, now);
mProcessCrashTimesPersistent.put(app.processName, app.uid, now);
+ updateProcessCrashCount(app.processName, app.uid, now);
}
if (app.crashHandler != null) mService.mHandler.post(app.crashHandler);
return true;
}
+ private void updateProcessCrashCount(String processName, int uid, long now) {
+ Pair<Long, Integer> count = mProcessCrashCounts.get(processName, uid);
+ if (count == null || (count.first + PROCESS_CRASH_COUNT_RESET_INTERVAL) < now) {
+ count = new Pair<>(now, 1);
+ } else {
+ count = new Pair<>(count.first, count.second + 1);
+ }
+ mProcessCrashCounts.put(processName, uid, count);
+ }
+
+ private boolean isProcOverCrashLimit(ProcessRecord app, long now) {
+ final Pair<Long, Integer> crashCount = mProcessCrashCounts.get(app.processName, app.uid);
+ return !app.isolated && crashCount != null
+ && now < (crashCount.first + PROCESS_CRASH_COUNT_RESET_INTERVAL)
+ && crashCount.second >= PROCESS_CRASH_COUNT_LIMIT;
+ }
+
void handleShowAppErrorUi(Message msg) {
AppErrorDialog.Data data = (AppErrorDialog.Data) msg.obj;
boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 29431b1f8485..6765132ffd81 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -585,10 +585,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteSyncStartLocked(name, uid, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
- name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__ON);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
+ name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__ON);
}
public void noteSyncFinish(final String name, final int uid) {
@@ -600,10 +600,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteSyncFinishLocked(name, uid, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
- name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__OFF);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SYNC_STATE_CHANGED, uid, null,
+ name, FrameworkStatsLog.SYNC_STATE_CHANGED__STATE__OFF);
}
/** A scheduled job was started. */
@@ -849,10 +849,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteStartSensorLocked(uid, sensor, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid,
- null, sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__ON);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid,
+ null, sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__ON);
}
public void noteStopSensor(final int uid, final int sensor) {
@@ -864,10 +864,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteStopSensorLocked(uid, sensor, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid,
- null, sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__OFF);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SENSOR_STATE_CHANGED, uid,
+ null, sensor, FrameworkStatsLog.SENSOR_STATE_CHANGED__STATE__OFF);
}
public void noteVibratorOn(final int uid, final long durationMillis) {
@@ -935,10 +935,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteScreenStateLocked(state, elapsedRealtime, uptime, currentTime);
}
- FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_STATE_CHANGED, state);
if (DBG) Slog.d(TAG, "end noteScreenState");
});
}
+ FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_STATE_CHANGED, state);
}
public void noteScreenBrightness(final int brightness) {
@@ -950,9 +950,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteScreenBrightnessLocked(brightness, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED, brightness);
});
}
+ FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_BRIGHTNESS_CHANGED, brightness);
}
public void noteUserActivity(final int uid, final int event) {
@@ -1103,10 +1103,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteWifiOnLocked(elapsedRealtime, uptime);
}
- FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
- FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__ON);
});
}
+ FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
+ FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__ON);
}
public void noteWifiOff() {
@@ -1118,10 +1118,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteWifiOffLocked(elapsedRealtime, uptime);
}
- FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
- FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__OFF);
});
}
+ FrameworkStatsLog.write(FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED,
+ FrameworkStatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__OFF);
}
public void noteStartAudio(final int uid) {
@@ -1133,10 +1133,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteAudioOnLocked(uid, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid,
- null, FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__ON);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid,
+ null, FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__ON);
}
public void noteStopAudio(final int uid) {
@@ -1148,10 +1148,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteAudioOffLocked(uid, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid,
- null, FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__OFF);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, uid,
+ null, FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__OFF);
}
public void noteStartVideo(final int uid) {
@@ -1163,10 +1163,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteVideoOnLocked(uid, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED,
- uid, null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__ON);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED,
+ uid, null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__ON);
}
public void noteStopVideo(final int uid) {
@@ -1178,10 +1178,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteVideoOffLocked(uid, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED,
- uid, null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__OFF);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED,
+ uid, null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__OFF);
}
public void noteResetAudio() {
@@ -1193,10 +1193,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteResetAudioLocked(elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, -1, null,
- FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__RESET);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.AUDIO_STATE_CHANGED, -1, null,
+ FrameworkStatsLog.AUDIO_STATE_CHANGED__STATE__RESET);
}
public void noteResetVideo() {
@@ -1208,10 +1208,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteResetVideoLocked(elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED, -1,
- null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__RESET);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED, -1,
+ null, FrameworkStatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__RESET);
}
public void noteFlashlightOn(final int uid) {
@@ -1223,10 +1223,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteFlashlightOnLocked(uid, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
- null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__ON);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
+ null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__ON);
}
public void noteFlashlightOff(final int uid) {
@@ -1238,10 +1238,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteFlashlightOffLocked(uid, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
- null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__OFF);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, uid,
+ null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__OFF);
}
public void noteStartCamera(final int uid) {
@@ -1254,11 +1254,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteCameraOnLocked(uid, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid,
- null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__ON);
});
}
if (DBG) Slog.d(TAG, "end noteStartCamera");
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid,
+ null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__ON);
}
public void noteStopCamera(final int uid) {
@@ -1270,10 +1270,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteCameraOffLocked(uid, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid,
- null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__OFF);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, uid,
+ null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__OFF);
}
public void noteResetCamera() {
@@ -1285,10 +1285,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteResetCameraLocked(elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, -1,
- null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__RESET);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.CAMERA_STATE_CHANGED, -1,
+ null, FrameworkStatsLog.CAMERA_STATE_CHANGED__STATE__RESET);
}
public void noteResetFlashlight() {
@@ -1300,10 +1300,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteResetFlashlightLocked(elapsedRealtime, uptime);
}
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, -1,
- null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__RESET);
});
}
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED, -1,
+ null, FrameworkStatsLog.FLASHLIGHT_STATE_CHANGED__STATE__RESET);
}
@Override
@@ -1341,11 +1341,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteWifiRunningLocked(localWs, elapsedRealtime, uptime);
}
- // TODO: Log WIFI_RUNNING_STATE_CHANGED in a better spot to include Hotspot too.
- FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
- ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
});
}
+ // TODO: Log WIFI_RUNNING_STATE_CHANGED in a better spot to include Hotspot too.
+ FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+ ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
}
public void noteWifiRunningChanged(final WorkSource oldWs, final WorkSource newWs) {
@@ -1360,12 +1360,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mStats.noteWifiRunningChangedLocked(
localOldWs, localNewWs, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
- newWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
- FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
- oldWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
});
}
+ FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+ newWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
+ FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+ oldWs, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
}
public void noteWifiStopped(final WorkSource ws) {
@@ -1378,10 +1378,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteWifiStoppedLocked(localWs, elapsedRealtime, uptime);
}
- FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
- ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
});
}
+ FrameworkStatsLog.write(FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED,
+ ws, FrameworkStatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
}
public void noteWifiState(final int wifiState, final String accessPoint) {
@@ -2421,11 +2421,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
mHandler.post(() -> {
- FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
- uid, packageName, className,
- resumed
- ? FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND
- : FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
synchronized (mStats) {
if (resumed) {
mStats.noteActivityResumedLocked(uid, elapsedRealtime, uptime);
@@ -2435,6 +2430,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
});
}
+ FrameworkStatsLog.write(FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
+ uid, packageName, className,
+ resumed
+ ? FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND
+ : FrameworkStatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
}
void noteProcessDied(final int uid, final int pid) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index f1c591522e51..0877dd96c19f 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -798,7 +798,10 @@ public final class BroadcastQueue {
mService.updateOomAdjPendingTargetsLocked(
OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
}
+ } else if (filter.receiverList.app != null) {
+ mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(filter.receiverList.app);
}
+
try {
if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
"Delivering to " + filter + " : " + r);
@@ -1132,6 +1135,10 @@ public final class BroadcastQueue {
}
}
if (sendResult) {
+ if (r.callerApp != null) {
+ mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(
+ r.callerApp);
+ }
try {
if (DEBUG_BROADCAST) {
Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] "
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index cd0d5b47c238..36d4a38c1624 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -720,6 +720,16 @@ public final class CachedAppOptimizer {
}
}
+ // This will ensure app will be out of the freezer for at least FREEZE_TIMEOUT_MS
+ void unfreezeTemporarily(ProcessRecord app) {
+ synchronized (mAm) {
+ if (app.frozen) {
+ unfreezeAppLocked(app);
+ freezeAppAsync(app);
+ }
+ }
+ }
+
@GuardedBy("mAm")
void freezeAppAsync(ProcessRecord app) {
mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 01d0a6dec81a..771f273781fa 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1329,6 +1329,8 @@ public final class OomAdjuster {
app.setCached(false);
app.shouldNotFreeze = false;
+ app.mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
+
final int appUid = app.info.uid;
final int logUid = mService.mCurOomAdjUid;
@@ -1349,6 +1351,7 @@ public final class OomAdjuster {
app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
app.curCapability = PROCESS_CAPABILITY_ALL;
app.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT);
+ app.bumpAllowStartFgsState(PROCESS_STATE_PERSISTENT);
// System processes can do UI, and when they do we want to have
// them trim their memory after the user leaves the UI. To
// facilitate this, here we need to determine whether or not it
@@ -1403,6 +1406,7 @@ public final class OomAdjuster {
app.adjType = "top-activity";
foregroundActivities = true;
procState = PROCESS_STATE_CUR_TOP;
+ app.bumpAllowStartFgsState(PROCESS_STATE_TOP);
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making top: " + app);
}
@@ -1500,6 +1504,7 @@ public final class OomAdjuster {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
procState = PROCESS_STATE_FOREGROUND_SERVICE;
+ app.bumpAllowStartFgsState(PROCESS_STATE_FOREGROUND_SERVICE);
app.adjType = "fg-service";
app.setCached(false);
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
@@ -1887,7 +1892,9 @@ public final class OomAdjuster {
// into the top state, since they are not on top. Instead
// give them the best bound state after that.
if (cr.hasFlag(Context.BIND_FOREGROUND_SERVICE)) {
- clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; ;
+ clientProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ app.bumpAllowStartFgsState(
+ PROCESS_STATE_BOUND_FOREGROUND_SERVICE);
} else if (mService.mWakefulness
== PowerManagerInternal.WAKEFULNESS_AWAKE
&& (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
@@ -1901,6 +1908,7 @@ public final class OomAdjuster {
// Go at most to BOUND_TOP, unless requested to elevate
// to client's state.
clientProcState = PROCESS_STATE_BOUND_TOP;
+ app.bumpAllowStartFgsState(PROCESS_STATE_BOUND_TOP);
boolean enabled = false;
try {
enabled = mPlatformCompatCache.isChangeEnabled(
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 463ba6d3d5ee..1b06dd90df83 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -36,6 +36,8 @@ import android.app.IApplicationThread;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IncrementalStatesInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ProcessInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.VersionedPackage;
@@ -353,6 +355,10 @@ class ProcessRecord implements WindowProcessListener {
long mKillTime; // The timestamp in uptime when this process was killed.
+ // If the proc state is PROCESS_STATE_BOUND_FOREGROUND_SERVICE or above, it can start FGS.
+ // It must obtain the proc state from a persistent/top process or FGS, not transitive.
+ int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
+
void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo,
long startTime) {
this.startUid = startUid;
@@ -466,6 +472,8 @@ class ProcessRecord implements WindowProcessListener {
pw.print(" setCapability=");
ActivityManager.printCapabilitiesFull(pw, setCapability);
pw.println();
+ pw.print(prefix); pw.print("allowStartFgsState=");
+ pw.println(mAllowStartFgsState);
if (hasShownUi || mPendingUiClean || hasAboveClient || treatLikeActivity) {
pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
pw.print(" pendingUiClean="); pw.print(mPendingUiClean);
@@ -1252,7 +1260,6 @@ class ProcessRecord implements WindowProcessListener {
void setHasForegroundActivities(boolean hasForegroundActivities) {
mHasForegroundActivities = hasForegroundActivities;
- mWindowProcessController.setHasForegroundActivities(hasForegroundActivities);
}
boolean hasForegroundActivities() {
@@ -1647,6 +1654,19 @@ class ProcessRecord implements WindowProcessListener {
}
}
+ // Check if package is still being loaded
+ boolean isPackageLoading = false;
+ final PackageManagerInternal packageManagerInternal =
+ mService.getPackageManagerInternalLocked();
+ if (aInfo != null && aInfo.packageName != null) {
+ IncrementalStatesInfo incrementalStatesInfo =
+ packageManagerInternal.getIncrementalStatesInfo(
+ aInfo.packageName, uid, userId);
+ if (incrementalStatesInfo != null) {
+ isPackageLoading = incrementalStatesInfo.isLoading();
+ }
+ }
+
// Log the ANR to the main log.
StringBuilder info = new StringBuilder();
info.setLength(0);
@@ -1664,6 +1684,13 @@ class ProcessRecord implements WindowProcessListener {
info.append("Parent: ").append(parentShortComponentName).append("\n");
}
+ if (isPackageLoading) {
+ // Report in the main log that the package is still loading
+ final float loadingProgress = packageManagerInternal.getIncrementalStatesInfo(
+ aInfo.packageName, uid, userId).getProgress();
+ info.append("Package is ").append((int) (loadingProgress * 100)).append("% loaded.\n");
+ }
+
StringBuilder report = new StringBuilder();
report.append(MemoryPressureUtil.currentPsiState());
ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
@@ -1731,7 +1758,7 @@ class ProcessRecord implements WindowProcessListener {
? FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
: FrameworkStatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND,
getProcessClassEnum(),
- (this.info != null) ? this.info.packageName : "");
+ (this.info != null) ? this.info.packageName : "", isPackageLoading);
final ProcessRecord parentPr = parentProcess != null
? (ProcessRecord) parentProcess.mOwner : null;
mService.addErrorToDropBox("anr", this, processName, activityShortComponentName,
@@ -1766,8 +1793,7 @@ class ProcessRecord implements WindowProcessListener {
// Notify package manager service to possibly update package state
if (aInfo != null && aInfo.packageName != null) {
- mService.getPackageManagerInternalLocked().notifyPackageCrashOrAnr(
- aInfo.packageName);
+ packageManagerInternal.notifyPackageCrashOrAnr(aInfo.packageName);
}
// mUiHandler can be null if the AMS is constructed with injector only. This will only
@@ -1943,6 +1969,12 @@ class ProcessRecord implements WindowProcessListener {
return mDialogController;
}
+ void bumpAllowStartFgsState(int newProcState) {
+ if (newProcState < mAllowStartFgsState) {
+ mAllowStartFgsState = newProcState;
+ }
+ }
+
/** A controller to generate error dialogs in {@link ProcessRecord} */
class ErrorDialogController {
/** dialogs being displayed due to crash */
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 2b2d9b55c46e..0b2628d0f80b 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3026,15 +3026,18 @@ public class AppOpsService extends IAppOpsService.Stub {
mContext.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE);
final String voiceRecognitionServicePackageName =
- voiceRecognitionComponent != null ? ComponentName.unflattenFromString(
- voiceRecognitionComponent).getPackageName() : "";
+ getComponentPackageNameFromString(voiceRecognitionComponent);
final String voiceInteractionServicePackageName =
- voiceInteractionComponent != null ? ComponentName.unflattenFromString(
- voiceInteractionComponent).getPackageName() : "";
+ getComponentPackageNameFromString(voiceInteractionComponent);
return Objects.equals(packageName, voiceRecognitionServicePackageName) && Objects.equals(
voiceRecognitionServicePackageName, voiceInteractionServicePackageName);
}
+ private String getComponentPackageNameFromString(String from) {
+ ComponentName componentName = from != null ? ComponentName.unflattenFromString(from) : null;
+ return componentName != null ? componentName.getPackageName() : "";
+ }
+
@Override
public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
String proxiedAttributionTag, int proxyUid, String proxyPackageName,
@@ -3062,7 +3065,7 @@ public class AppOpsService extends IAppOpsService.Stub {
final int proxyMode = noteOperationUnchecked(code, proxyUid, resolveProxyPackageName,
proxyAttributionTag, Process.INVALID_UID, null, null, proxyFlags,
!isProxyTrusted, "proxy " + message, shouldCollectMessage);
- if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
+ if (proxyMode != AppOpsManager.MODE_ALLOWED) {
return proxyMode;
}
@@ -3547,8 +3550,7 @@ public class AppOpsService extends IAppOpsService.Stub {
resolvedProxyPackageName, proxyAttributionTag, Process.INVALID_UID, null, null,
proxyFlags, startIfModeDefault, !isProxyTrusted, "proxy " + message,
shouldCollectMessage, false);
- if (!shouldStartForMode(proxyMode, startIfModeDefault)
- || Binder.getCallingUid() == proxiedUid) {
+ if (!shouldStartForMode(proxyMode, startIfModeDefault)) {
return proxyMode;
}
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 54c179030929..eeec1bbf8d75 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -329,7 +329,11 @@ public class AuthService extends SystemService {
return;
}
- authenticator = new FingerprintAuthenticator(fingerprintService, config);
+ // Initialize this outside of FingerprintAuthenticator. Only HIDL HALs require
+ // initialization from here. AIDL HALs are initialized by FingerprintService since
+ // the HAL interface provides ID, strength, and other configuration information.
+ fingerprintService.initializeConfiguration(config.id, config.strength);
+ authenticator = new FingerprintAuthenticator(fingerprintService, config.id);
break;
case TYPE_FACE:
@@ -340,7 +344,11 @@ public class AuthService extends SystemService {
return;
}
- authenticator = new FaceAuthenticator(faceService, config);
+ // Initialize this outside of FingerprintAuthenticator. Only HIDL HALs require
+ // initialization from here. AIDL HALs are initialized by FaceService since
+ // the HAL interface provides ID, strength, and other configuration information.
+ faceService.initializeConfiguration(config.id, config.strength);
+ authenticator = new FaceAuthenticator(faceService, config.id);
break;
case TYPE_IRIS:
@@ -351,7 +359,8 @@ public class AuthService extends SystemService {
return;
}
- authenticator = new IrisAuthenticator(irisService, config);
+ irisService.initializeConfiguration(config.id, config.strength);
+ authenticator = new IrisAuthenticator(irisService, config.id);
break;
default:
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index 3c18cd4ed231..637a8963402e 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -17,9 +17,11 @@
package com.android.server.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -33,6 +35,8 @@ import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.IBinder;
import android.os.RemoteException;
import android.security.KeyStore;
@@ -68,47 +72,54 @@ public final class AuthSession implements IBinder.DeathRecipient {
*/
static final int STATE_AUTH_CALLED = 1;
/**
- * Authentication started, BiometricPrompt is showing and the hardware is authenticating.
+ * Authentication started, BiometricPrompt is showing and the hardware is authenticating. At
+ * this point, the BiometricPrompt UI has been requested, but is not necessarily done animating
+ * in yet.
*/
static final int STATE_AUTH_STARTED = 2;
/**
+ * Same as {@link #STATE_AUTH_STARTED}, except the BiometricPrompt UI is done animating in.
+ */
+ static final int STATE_AUTH_STARTED_UI_SHOWING = 3;
+ /**
* Authentication is paused, waiting for the user to press "try again" button. Only
* passive modalities such as Face or Iris should have this state. Note that for passive
* modalities, the HAL enters the idle state after onAuthenticated(false) which differs from
* fingerprint.
*/
- static final int STATE_AUTH_PAUSED = 3;
+ static final int STATE_AUTH_PAUSED = 4;
/**
* Paused, but "try again" was pressed. Sensors have new cookies and we're now waiting for all
* cookies to be returned.
*/
- static final int STATE_AUTH_PAUSED_RESUMING = 4;
+ static final int STATE_AUTH_PAUSED_RESUMING = 5;
/**
* Authentication is successful, but we're waiting for the user to press "confirm" button.
*/
- static final int STATE_AUTH_PENDING_CONFIRM = 5;
+ static final int STATE_AUTH_PENDING_CONFIRM = 6;
/**
* Biometric authenticated, waiting for SysUI to finish animation
*/
- static final int STATE_AUTHENTICATED_PENDING_SYSUI = 6;
+ static final int STATE_AUTHENTICATED_PENDING_SYSUI = 7;
/**
* Biometric error, waiting for SysUI to finish animation
*/
- static final int STATE_ERROR_PENDING_SYSUI = 7;
+ static final int STATE_ERROR_PENDING_SYSUI = 8;
/**
* Device credential in AuthController is showing
*/
- static final int STATE_SHOWING_DEVICE_CREDENTIAL = 8;
+ static final int STATE_SHOWING_DEVICE_CREDENTIAL = 9;
/**
* The client binder died, and sensors were authenticating at the time. Cancel has been
* requested and we're waiting for the HAL(s) to send ERROR_CANCELED.
*/
- static final int STATE_CLIENT_DIED_CANCELLING = 9;
+ static final int STATE_CLIENT_DIED_CANCELLING = 10;
@IntDef({
STATE_AUTH_IDLE,
STATE_AUTH_CALLED,
STATE_AUTH_STARTED,
+ STATE_AUTH_STARTED_UI_SHOWING,
STATE_AUTH_PAUSED,
STATE_AUTH_PAUSED_RESUMING,
STATE_AUTH_PENDING_CONFIRM,
@@ -150,6 +161,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
private final int mCallingPid;
private final int mCallingUserId;
private final boolean mDebugEnabled;
+ private final List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties;
// The current state, which can be either idle, called, or started
private @SessionState int mState = STATE_AUTH_IDLE;
@@ -165,12 +177,25 @@ public final class AuthSession implements IBinder.DeathRecipient {
// Timestamp when hardware authentication occurred
private long mAuthenticatedTimeMs;
- AuthSession(Context context, IStatusBarService statusBarService,
- IBiometricSysuiReceiver sysuiReceiver, KeyStore keystore, Random random,
- ClientDeathReceiver clientDeathReceiver, PreAuthInfo preAuthInfo, IBinder token,
- long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
- IBiometricServiceReceiver clientReceiver, String opPackageName, PromptInfo promptInfo,
- int callingUid, int callingPid, int callingUserId, boolean debugEnabled) {
+ AuthSession(@NonNull Context context,
+ @NonNull IStatusBarService statusBarService,
+ @NonNull IBiometricSysuiReceiver sysuiReceiver,
+ @NonNull KeyStore keystore,
+ @NonNull Random random,
+ @NonNull ClientDeathReceiver clientDeathReceiver,
+ @NonNull PreAuthInfo preAuthInfo,
+ @NonNull IBinder token,
+ long operationId,
+ int userId,
+ @NonNull IBiometricSensorReceiver sensorReceiver,
+ @NonNull IBiometricServiceReceiver clientReceiver,
+ @NonNull String opPackageName,
+ @NonNull PromptInfo promptInfo,
+ int callingUid,
+ int callingPid,
+ int callingUserId,
+ boolean debugEnabled,
+ @NonNull List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties) {
mContext = context;
mStatusBarService = statusBarService;
mSysuiReceiver = sysuiReceiver;
@@ -189,6 +214,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
mCallingPid = callingPid;
mCallingUserId = callingUserId;
mDebugEnabled = debugEnabled;
+ mFingerprintSensorProperties = fingerprintSensorProperties;
try {
mClientReceiver.asBinder().linkToDeath(this, 0 /* flags */);
@@ -267,7 +293,10 @@ public final class AuthSession implements IBinder.DeathRecipient {
if (allCookiesReceived()) {
mStartTimeMs = System.currentTimeMillis();
- startAllPreparedSensors();
+
+ // For UDFPS, do not start until BiometricPrompt UI is shown. Otherwise, the UDFPS
+ // affordance will be shown before the BP UI is finished animating in.
+ startAllPreparedSensorsExceptUdfps();
// No need to request the UI if we're coming from the paused state.
if (mState != STATE_AUTH_PAUSED_RESUMING) {
@@ -311,13 +340,41 @@ public final class AuthSession implements IBinder.DeathRecipient {
return false;
}
- private void startAllPreparedSensors() {
+ private boolean isUdfpsSensor(@NonNull BiometricSensor sensor) {
+ if (sensor.modality != TYPE_FINGERPRINT) {
+ return false;
+ }
+
+ for (FingerprintSensorPropertiesInternal prop : mFingerprintSensorProperties) {
+ if (sensor.id == prop.sensorId && prop.isAnyUdfpsType()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void startAllPreparedSensorsExceptUdfps() {
for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
+ if (isUdfpsSensor(sensor)) {
+ Slog.d(TAG, "Skipping UDFPS, sensorId: " + sensor.id);
+ continue;
+ }
try {
sensor.startSensor();
} catch (RemoteException e) {
- Slog.e(TAG, "Unable to start prepared client, sensor ID: "
- + sensor.id, e);
+ Slog.e(TAG, "Unable to start prepared client, sensor: " + sensor, e);
+ }
+ }
+ }
+
+ private void startPreparedUdfpsSensors() {
+ for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
+ if (isUdfpsSensor(sensor)) {
+ try {
+ sensor.startSensor();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to start UDFPS sensor: " + sensor, e);
+ }
}
}
}
@@ -390,7 +447,8 @@ public final class AuthSession implements IBinder.DeathRecipient {
break;
}
- case STATE_AUTH_STARTED: {
+ case STATE_AUTH_STARTED:
+ case STATE_AUTH_STARTED_UI_SHOWING: {
final boolean errorLockout = error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
|| error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
if (isAllowDeviceCredential() && errorLockout) {
@@ -463,6 +521,17 @@ public final class AuthSession implements IBinder.DeathRecipient {
}
}
+ void onDialogAnimatedIn() {
+ if (mState != STATE_AUTH_STARTED) {
+ Slog.w(TAG, "onDialogAnimatedIn, unexpected state: " + mState);
+ }
+
+ mState = STATE_AUTH_STARTED_UI_SHOWING;
+
+ // For UDFPS devices, we can now start the sensor.
+ startPreparedUdfpsSensors();
+ }
+
void onTryAgainPressed() {
if (mState != STATE_AUTH_PAUSED) {
Slog.w(TAG, "onTryAgainPressed, state: " + mState);
@@ -543,13 +612,15 @@ public final class AuthSession implements IBinder.DeathRecipient {
*/
boolean onClientDied() {
try {
- if (mState == STATE_AUTH_STARTED) {
- mState = STATE_CLIENT_DIED_CANCELLING;
- cancelAllSensors();
- return false;
- } else {
- mStatusBarService.hideAuthenticationDialog();
- return true;
+ switch (mState) {
+ case STATE_AUTH_STARTED:
+ case STATE_AUTH_STARTED_UI_SHOWING:
+ mState = STATE_CLIENT_DIED_CANCELLING;
+ cancelAllSensors();
+ return false;
+ default:
+ mStatusBarService.hideAuthenticationDialog();
+ return true;
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote Exception: " + e);
@@ -676,7 +747,10 @@ public final class AuthSession implements IBinder.DeathRecipient {
* @return true if this AuthSession is finished, e.g. should be set to null
*/
boolean onCancelAuthSession(boolean force) {
- if (mState == STATE_AUTH_STARTED && !force) {
+ final boolean authStarted = mState == STATE_AUTH_STARTED
+ || mState == STATE_AUTH_STARTED_UI_SHOWING;
+
+ if (authStarted && !force) {
cancelAllSensors();
// Wait for ERROR_CANCELED to be returned from the sensors
return false;
@@ -705,7 +779,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
* {@link #STATE_SHOWING_DEVICE_CREDENTIAL} or dismissed.
*/
private void cancelBiometricOnly() {
- if (mState == STATE_AUTH_STARTED) {
+ if (mState == STATE_AUTH_STARTED || mState == STATE_AUTH_STARTED_UI_SHOWING) {
cancelAllSensors();
}
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 3e0a40f9c288..196582a6c0d6 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -39,6 +39,8 @@ import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.net.Uri;
import android.os.Binder;
import android.os.DeadObjectException;
@@ -90,6 +92,7 @@ public class BiometricService extends SystemService {
private static final int MSG_ON_DEVICE_CREDENTIAL_PRESSED = 12;
private static final int MSG_ON_SYSTEM_EVENT = 13;
private static final int MSG_CLIENT_DIED = 14;
+ private static final int MSG_ON_DIALOG_ANIMATED_IN = 15;
private final Injector mInjector;
private final DevicePolicyManager mDevicePolicyManager;
@@ -221,6 +224,11 @@ public class BiometricService extends SystemService {
break;
}
+ case MSG_ON_DIALOG_ANIMATED_IN: {
+ handleOnDialogAnimatedIn();
+ break;
+ }
+
default:
Slog.e(TAG, "Unknown message: " + msg);
break;
@@ -451,6 +459,11 @@ public class BiometricService extends SystemService {
public void onSystemEvent(int event) {
mHandler.obtainMessage(MSG_ON_SYSTEM_EVENT, event).sendToTarget();
}
+
+ @Override
+ public void onDialogAnimatedIn() {
+ mHandler.obtainMessage(MSG_ON_DIALOG_ANIMATED_IN).sendToTarget();
+ }
};
private final AuthSession.ClientDeathReceiver mClientDeathReceiver = () -> {
@@ -594,20 +607,6 @@ public class BiometricService extends SystemService {
}
}
- // This happens infrequently enough, not worth caching.
- final String[] configs = mInjector.getConfiguration(getContext());
- boolean idFound = false;
- for (int i = 0; i < configs.length; i++) {
- SensorConfig config = new SensorConfig(configs[i]);
- if (config.id == id) {
- idFound = true;
- break;
- }
- }
- if (!idFound) {
- throw new IllegalStateException("Cannot register unknown id");
- }
-
mSensors.add(new BiometricSensor(id, modality, strength, authenticator) {
@Override
boolean confirmationAlwaysRequired(int userId) {
@@ -763,6 +762,16 @@ public class BiometricService extends SystemService {
public DevicePolicyManager getDevicePolicyManager(Context context) {
return context.getSystemService(DevicePolicyManager.class);
}
+
+ public List<FingerprintSensorPropertiesInternal> getFingerprintSensorProperties(
+ Context context) {
+ final FingerprintManager fpm = context.getSystemService(FingerprintManager.class);
+ if (fpm != null) {
+ return fpm.getSensorPropertiesInternal();
+ } else {
+ return new ArrayList<>();
+ }
+ }
}
/**
@@ -946,7 +955,7 @@ public class BiometricService extends SystemService {
private void handleClientDied() {
if (mCurrentAuthSession == null) {
- Slog.e(TAG, "Auth session null");
+ Slog.e(TAG, "handleClientDied: AuthSession is null");
return;
}
@@ -957,6 +966,15 @@ public class BiometricService extends SystemService {
}
}
+ private void handleOnDialogAnimatedIn() {
+ if (mCurrentAuthSession == null) {
+ Slog.e(TAG, "handleOnDialogAnimatedIn: AuthSession is null");
+ return;
+ }
+
+ mCurrentAuthSession.onDialogAnimatedIn();
+ }
+
/**
* Invoked when each service has notified that its client is ready to be started. When
* all biometrics are ready, this invokes the SystemUI dialog through StatusBar.
@@ -1040,7 +1058,8 @@ public class BiometricService extends SystemService {
mCurrentAuthSession = new AuthSession(getContext(), mStatusBarService, mSysuiReceiver,
mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, operationId, userId,
mBiometricSensorReceiver, receiver, opPackageName, promptInfo, callingUid,
- callingPid, callingUserId, debugEnabled);
+ callingPid, callingUserId, debugEnabled,
+ mInjector.getFingerprintSensorProperties(getContext()));
try {
mCurrentAuthSession.goToInitialState();
} catch (RemoteException e) {
@@ -1067,5 +1086,12 @@ public class BiometricService extends SystemService {
pw.println(" " + sensor);
}
pw.println("CurrentSession: " + mCurrentAuthSession);
+
+ final List<FingerprintSensorPropertiesInternal> fpProps =
+ mInjector.getFingerprintSensorProperties(getContext());
+ pw.println("FingerprintSensorProperties: " + fpProps.size());
+ for (FingerprintSensorPropertiesInternal prop : fpProps) {
+ pw.println(" " + prop);
+ }
}
}
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index 88804e28480b..67419428e4d7 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -453,7 +453,7 @@ public class Utils {
* {@link SensorPropertiesInternal} strength.
*/
public static @SensorProperties.Strength int authenticatorStrengthToPropertyStrength(
- @BiometricManager.Authenticators.Types int strength) {
+ @Authenticators.Types int strength) {
switch (strength) {
case BiometricManager.Authenticators.BIOMETRIC_CONVENIENCE:
return SensorProperties.STRENGTH_CONVENIENCE;
@@ -465,4 +465,18 @@ public class Utils {
throw new IllegalArgumentException("Unknown strength: " + strength);
}
}
+
+ public static @Authenticators.Types int propertyStrengthToAuthenticatorStrength(
+ @SensorProperties.Strength int strength) {
+ switch (strength) {
+ case SensorProperties.STRENGTH_CONVENIENCE:
+ return Authenticators.BIOMETRIC_CONVENIENCE;
+ case SensorProperties.STRENGTH_WEAK:
+ return Authenticators.BIOMETRIC_WEAK;
+ case SensorProperties.STRENGTH_STRONG:
+ return Authenticators.BIOMETRIC_STRONG;
+ default:
+ throw new IllegalArgumentException("Unknown strength: " + strength);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index ce2d3405ddc6..2784f46a96c2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.IBiometricService;
import android.os.Handler;
import android.os.IBinder;
@@ -378,9 +379,20 @@ public class BiometricScheduler {
return;
}
if (mCurrentOperation.state != Operation.STATE_WAITING_FOR_COOKIE) {
- Slog.e(getTag(), "Operation is in the wrong state: " + mCurrentOperation
- + ", expected STATE_WAITING_FOR_COOKIE");
- return;
+ if (mCurrentOperation.state == Operation.STATE_WAITING_IN_QUEUE_CANCELING) {
+ Slog.d(getTag(), "Operation was marked for cancellation, cancelling now: "
+ + mCurrentOperation);
+ // This should trigger the internal onClientFinished callback, which clears the
+ // operation and starts the next one.
+ final Interruptable interruptable = (Interruptable) mCurrentOperation.clientMonitor;
+ interruptable.onError(BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+ 0 /* vendorCode */);
+ return;
+ } else {
+ Slog.e(getTag(), "Operation is in the wrong state: " + mCurrentOperation
+ + ", expected STATE_WAITING_FOR_COOKIE");
+ return;
+ }
}
if (mCurrentOperation.clientMonitor.getCookie() != cookie) {
Slog.e(getTag(), "Mismatched cookie for operation: " + mCurrentOperation
@@ -461,6 +473,13 @@ public class BiometricScheduler {
Slog.w(getTag(), "Cancel already invoked for operation: " + operation);
return;
}
+ if (operation.state == Operation.STATE_WAITING_FOR_COOKIE) {
+ Slog.w(getTag(), "Skipping cancellation for non-started operation: " + operation);
+ // We can set it to null immediately, since the HAL was never notified to start.
+ mCurrentOperation = null;
+ startNextOperationIfIdle();
+ return;
+ }
Slog.d(getTag(), "[Cancelling] Current client: " + operation.clientMonitor);
final Interruptable interruptable = (Interruptable) operation.clientMonitor;
interruptable.cancel();
@@ -505,8 +524,9 @@ public class BiometricScheduler {
mCurrentOperation.clientMonitor instanceof AuthenticationConsumer;
final boolean tokenMatches = mCurrentOperation.clientMonitor.getToken() == token;
if (!isAuthenticating || !tokenMatches) {
- Slog.w(getTag(), "Not cancelling authentication, isEnrolling: " + isAuthenticating
- + " tokenMatches: " + tokenMatches);
+ Slog.w(getTag(), "Not cancelling authentication"
+ + ", current operation : " + mCurrentOperation
+ + ", tokenMatches: " + tokenMatches);
return;
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java
index 5f593b06c511..2ae6ccd73e3d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceCallback.java
@@ -14,19 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.car;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+package com.android.server.biometrics.sensors;
/**
- * Annotates that a test class should be run as part of CarSystemUI presubmit
+ * System_server services that require BiometricService to load before finishing initialization
+ * should implement this interface.
*/
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-@Documented
-public @interface CarSystemUiTest {
+public interface BiometricServiceCallback {
+ /**
+ * Notifies the service that BiometricService is initialized.
+ */
+ void onBiometricServiceReady();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
index c87f62f94499..61e7c8922f39 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
@@ -37,7 +37,7 @@ import android.os.RemoteException;
* It may be possible at some point in the future to combine I<Sensor>ServiceReceivers to share
* a common interface.
*/
-public final class ClientMonitorCallbackConverter {
+public class ClientMonitorCallbackConverter {
private IBiometricSensorReceiver mSensorReceiver; // BiometricService
private IFaceServiceReceiver mFaceServiceReceiver; // FaceManager
private IFingerprintServiceReceiver mFingerprintServiceReceiver; // FingerprintManager
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java b/services/core/java/com/android/server/biometrics/sensors/LockoutCache.java
index 2fae1f3d9d43..0aba29557b20 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/LockoutCache.java
+++ b/services/core/java/com/android/server/biometrics/sensors/LockoutCache.java
@@ -14,21 +14,19 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.fingerprint.aidl;
+package com.android.server.biometrics.sensors;
import android.util.SparseIntArray;
-import com.android.server.biometrics.sensors.LockoutTracker;
-
/**
* For a single sensor, caches lockout states for all users.
*/
-class LockoutCache implements LockoutTracker {
+public class LockoutCache implements LockoutTracker {
// Map of userId to LockoutMode
private final SparseIntArray mUserLockoutStates;
- LockoutCache() {
+ public LockoutCache() {
mUserLockoutStates = new SparseIntArray();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index 3318bcb8d593..b3e6cad0e666 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -30,11 +30,12 @@ import com.android.server.biometrics.sensors.LockoutTracker;
*/
public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {
private final IFaceService mFaceService;
+ private final int mSensorId;
- public FaceAuthenticator(IFaceService faceService, SensorConfig config)
+ public FaceAuthenticator(IFaceService faceService, int sensorId)
throws RemoteException {
mFaceService = faceService;
- mFaceService.initializeConfiguration(config.id, config.strength);
+ mSensorId = sensorId;
}
@Override
@@ -42,40 +43,41 @@ public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {
long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)
throws RemoteException {
- mFaceService.prepareForAuthentication(requireConfirmation, token, operationId, userId,
- sensorReceiver, opPackageName, cookie, callingUid, callingPid, callingUserId);
+ mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId,
+ userId, sensorReceiver, opPackageName, cookie, callingUid, callingPid,
+ callingUserId);
}
@Override
public void startPreparedClient(int cookie) throws RemoteException {
- mFaceService.startPreparedClient(cookie);
+ mFaceService.startPreparedClient(mSensorId, cookie);
}
@Override
public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid,
int callingPid, int callingUserId) throws RemoteException {
- mFaceService.cancelAuthenticationFromService(token, opPackageName, callingUid, callingPid,
- callingUserId);
+ mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName, callingUid,
+ callingPid, callingUserId);
}
@Override
public boolean isHardwareDetected(String opPackageName) throws RemoteException {
- return mFaceService.isHardwareDetected(opPackageName);
+ return mFaceService.isHardwareDetected(mSensorId, opPackageName);
}
@Override
public boolean hasEnrolledTemplates(int userId, String opPackageName) throws RemoteException {
- return mFaceService.hasEnrolledFaces(userId, opPackageName);
+ return mFaceService.hasEnrolledFaces(mSensorId, userId, opPackageName);
}
@Override
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId)
throws RemoteException {
- return mFaceService.getLockoutModeForUser(userId);
+ return mFaceService.getLockoutModeForUser(mSensorId, userId);
}
@Override
public long getAuthenticatorId(int callingUserId) throws RemoteException {
- return mFaceService.getAuthenticatorId(callingUserId);
+ return mFaceService.getAuthenticatorId(mSensorId, callingUserId);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index a298e19e4b02..1e0764a275c5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.face;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,14 +27,21 @@ import android.content.Context;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
+import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.SensorProps;
import android.hardware.face.Face;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.face.IFaceService;
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Process;
import android.os.NativeHandle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.Pair;
import android.util.Slog;
@@ -42,11 +50,15 @@ import android.view.Surface;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
+import com.android.server.biometrics.sensors.BiometricServiceCallback;
+import com.android.server.biometrics.sensors.face.aidl.FaceProvider;
+import com.android.server.biometrics.sensors.face.hidl.Face10;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -59,14 +71,15 @@ import java.util.List;
* The service is responsible for maintaining a list of clients and dispatching all
* face-related events.
*/
-public class FaceService extends SystemService {
+public class FaceService extends SystemService implements BiometricServiceCallback {
protected static final String TAG = "FaceService";
+ private final FaceServiceWrapper mServiceWrapper;
private final LockoutResetDispatcher mLockoutResetDispatcher;
private final LockPatternUtils mLockPatternUtils;
@NonNull
- private List<ServiceProvider> mServiceProviders;
+ private final List<ServiceProvider> mServiceProviders;
@Nullable
private ServiceProvider getProviderForSensor(int sensorId) {
@@ -255,35 +268,35 @@ public class FaceService extends SystemService {
}
@Override // Binder call
- public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
- long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
- String opPackageName, int cookie, int callingUid, int callingPid,
- int callingUserId) {
+ public void prepareForAuthentication(int sensorId, boolean requireConfirmation,
+ IBinder token, long operationId, int userId,
+ IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
+ int callingUid, int callingPid, int callingUserId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for prepareForAuthentication");
return;
}
final boolean restricted = true; // BiometricPrompt is always restricted
- provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, cookie,
+ provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, false /* isKeyguard */);
}
@Override // Binder call
- public void startPreparedClient(int cookie) {
+ public void startPreparedClient(int sensorId, int cookie) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for startPreparedClient");
return;
}
- provider.second.startPreparedClient(provider.first, cookie);
+ provider.startPreparedClient(sensorId, cookie);
}
@Override // Binder call
@@ -312,17 +325,17 @@ public class FaceService extends SystemService {
}
@Override // Binder call
- public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
- int callingUid, int callingPid, int callingUserId) {
+ public void cancelAuthenticationFromService(int sensorId, final IBinder token,
+ final String opPackageName, int callingUid, int callingPid, int callingUserId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthenticationFromService");
return;
}
- provider.second.cancelAuthentication(provider.first, token);
+ provider.cancelAuthentication(sensorId, token);
}
@Override // Binder call
@@ -384,24 +397,24 @@ public class FaceService extends SystemService {
}
@Override // Binder call
- public boolean isHardwareDetected(String opPackageName) {
+ public boolean isHardwareDetected(int sensorId, String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final long token = Binder.clearCallingIdentity();
try {
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
return false;
}
- return provider.second.isHardwareDetected(provider.first);
+ return provider.isHardwareDetected(sensorId);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override // Binder call
- public List<Face> getEnrolledFaces(int userId, String opPackageName) {
+ public List<Face> getEnrolledFaces(int sensorId, int userId, String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (userId != UserHandle.getCallingUserId()) {
@@ -412,7 +425,7 @@ public class FaceService extends SystemService {
}
@Override // Binder call
- public boolean hasEnrolledFaces(int userId, String opPackageName) {
+ public boolean hasEnrolledFaces(int sensorId, int userId, String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (userId != UserHandle.getCallingUserId()) {
@@ -423,30 +436,29 @@ public class FaceService extends SystemService {
}
@Override // Binder call
- @LockoutTracker.LockoutMode
- public int getLockoutModeForUser(int userId) {
+ public @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getLockoutModeForUser");
return LockoutTracker.LOCKOUT_NONE;
}
- return provider.second.getLockoutModeForUser(provider.first, userId);
+ return provider.getLockoutModeForUser(sensorId, userId);
}
@Override // Binder call
- public long getAuthenticatorId(int userId) {
+ public long getAuthenticatorId(int sensorId, int userId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getAuthenticatorId");
return 0;
}
- return provider.second.getAuthenticatorId(provider.first, userId);
+ return provider.getAuthenticatorId(sensorId, userId);
}
@Override // Binder call
@@ -454,13 +466,13 @@ public class FaceService extends SystemService {
String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName);
return;
}
- provider.second.scheduleResetLockout(provider.first, userId, hardwareAuthToken);
+ provider.scheduleResetLockout(sensorId, userId, hardwareAuthToken);
}
@Override
@@ -505,14 +517,66 @@ public class FaceService extends SystemService {
public FaceService(Context context) {
super(context);
+ mServiceWrapper = new FaceServiceWrapper();
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
mServiceProviders = new ArrayList<>();
}
@Override
+ public void onBiometricServiceReady() {
+ final IBiometricService biometricService = IBiometricService.Stub.asInterface(
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE));
+
+ final String[] instances = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR);
+ if (instances == null || instances.length == 0) {
+ return;
+ }
+
+ // If for some reason the HAL is not started before the system service, do not block
+ // the rest of system server. Put this on a background thread.
+ final ServiceThread thread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
+ true /* allowIo */);
+ thread.start();
+ final Handler handler = new Handler(thread.getLooper());
+
+ handler.post(() -> {
+ for (String instance : instances) {
+ final String fqName = IFace.DESCRIPTOR + "/" + instance;
+ final IFace face = IFace.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(fqName));
+ try {
+ final SensorProps[] props = face.getSensorProps();
+ final FaceProvider provider = new FaceProvider(getContext(), props, instance,
+ mLockoutResetDispatcher);
+ mServiceProviders.add(provider);
+
+ // Register each sensor individually with BiometricService
+ for (SensorProps prop : props) {
+ final int sensorId = prop.commonProps.sensorId;
+ @BiometricManager.Authenticators.Types int strength =
+ Utils.propertyStrengthToAuthenticatorStrength(
+ prop.commonProps.sensorStrength);
+ final FaceAuthenticator authenticator =
+ new FaceAuthenticator(mServiceWrapper, sensorId);
+ try {
+ biometricService.registerAuthenticator(sensorId, TYPE_FACE, strength,
+ authenticator);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when registering sensorId: "
+ + sensorId);
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when initializing instance: " + fqName);
+ }
+ }
+ });
+ }
+
+ @Override
public void onStart() {
- publishBinderService(Context.FACE_SERVICE, new FaceServiceWrapper());
+ publishBinderService(Context.FACE_SERVICE, mServiceWrapper);
}
private native NativeHandle convertSurfaceToNativeHandle(Surface surface);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/UsageStats.java b/services/core/java/com/android/server/biometrics/sensors/face/UsageStats.java
index 4841bf437cdc..d99abcd4b3d2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/UsageStats.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/UsageStats.java
@@ -28,7 +28,7 @@ import java.util.ArrayDeque;
* Keep a short historical buffer of stats, with an aggregated usage time.
*/
-class UsageStats {
+public class UsageStats {
private static final int EVENT_LOG_SIZE = 100;
/**
@@ -44,7 +44,7 @@ class UsageStats {
private int mVendorError;
private int mUser;
- AuthenticationEvent(long startTime, long latency, boolean authenticated, int error,
+ public AuthenticationEvent(long startTime, long latency, boolean authenticated, int error,
int vendorError, int user) {
mStartTime = startTime;
mLatency = latency;
@@ -76,14 +76,14 @@ class UsageStats {
private long mRejectLatency;
private SparseLongArray mErrorLatency;
- UsageStats(Context context) {
+ public UsageStats(Context context) {
mAuthenticationEvents = new ArrayDeque<>();
mErrorCount = new SparseIntArray();
mErrorLatency = new SparseLongArray();
mContext = context;
}
- void addEvent(AuthenticationEvent event) {
+ public void addEvent(AuthenticationEvent event) {
if (mAuthenticationEvents.size() >= EVENT_LOG_SIZE) {
mAuthenticationEvents.removeFirst();
}
@@ -101,7 +101,7 @@ class UsageStats {
}
}
- void print(PrintWriter pw) {
+ public void print(PrintWriter pw) {
pw.println("Events since last reboot: " + mAuthenticationEvents.size());
for (AuthenticationEvent event : mAuthenticationEvents) {
pw.println(event.toString(mContext));
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
new file mode 100644
index 000000000000..80f337f0f600
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -0,0 +1,221 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.face.FaceManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutCache;
+import com.android.server.biometrics.sensors.LockoutConsumer;
+import com.android.server.biometrics.sensors.LockoutTracker;
+import com.android.server.biometrics.sensors.face.UsageStats;
+
+import java.util.ArrayList;
+
+/**
+ * Face-specific authentication client for the {@link IFace} AIDL HAL interface.
+ */
+class FaceAuthenticationClient extends AuthenticationClient<ISession> implements LockoutConsumer {
+ private static final String TAG = "FaceAuthenticationClient";
+
+ @NonNull private final UsageStats mUsageStats;
+ @NonNull private final LockoutCache mLockoutCache;
+ @Nullable private final NotificationManager mNotificationManager;
+ @Nullable private ICancellationSignal mCancellationSignal;
+
+ private final int[] mBiometricPromptIgnoreList;
+ private final int[] mBiometricPromptIgnoreListVendor;
+ private final int[] mKeyguardIgnoreList;
+ private final int[] mKeyguardIgnoreListVendor;
+
+ private int mLastAcquire;
+
+ FaceAuthenticationClient(@NonNull Context context,
+ @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+ @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
+ boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
+ boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats,
+ @NonNull LockoutCache lockoutCache) {
+ super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
+ owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
+ BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
+ lockoutCache);
+ mUsageStats = usageStats;
+ mLockoutCache = lockoutCache;
+ mNotificationManager = context.getSystemService(NotificationManager.class);
+
+ final Resources resources = getContext().getResources();
+ mBiometricPromptIgnoreList = resources.getIntArray(
+ R.array.config_face_acquire_biometricprompt_ignorelist);
+ mBiometricPromptIgnoreListVendor = resources.getIntArray(
+ R.array.config_face_acquire_vendor_biometricprompt_ignorelist);
+ mKeyguardIgnoreList = resources.getIntArray(
+ R.array.config_face_acquire_keyguard_ignorelist);
+ mKeyguardIgnoreListVendor = resources.getIntArray(
+ R.array.config_face_acquire_vendor_keyguard_ignorelist);
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ mCancellationSignal = getFreshDaemon().authenticate(mSequentialId, mOperationId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when requesting auth", e);
+ onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ protected void stopHalOperation() {
+ if (mCancellationSignal != null) {
+ try {
+ mCancellationSignal.cancel();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when requesting cancel", e);
+ onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+ }
+
+ private boolean wasUserDetected() {
+ // Do not provide haptic feedback if the user was not detected, and an error (usually
+ // ERROR_TIMEOUT) is received.
+ return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED
+ && mLastAcquire != FaceManager.FACE_ACQUIRED_SENSOR_DIRTY;
+ }
+
+ @Override
+ public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
+ boolean authenticated, ArrayList<Byte> token) {
+ super.onAuthenticated(identifier, authenticated, token);
+
+ mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
+ getStartTimeMs(),
+ System.currentTimeMillis() - getStartTimeMs() /* latency */,
+ authenticated,
+ 0 /* error */,
+ 0 /* vendorError */,
+ getTargetUserId()));
+
+ // For face, the authentication lifecycle ends either when
+ // 1) Authenticated == true
+ // 2) Error occurred
+ // 3) Authenticated == false
+ mCallback.onClientFinished(this, true /* success */);
+ }
+
+ @Override
+ public void onError(int error, int vendorCode) {
+ mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
+ getStartTimeMs(),
+ System.currentTimeMillis() - getStartTimeMs() /* latency */,
+ false /* authenticated */,
+ error,
+ vendorCode,
+ getTargetUserId()));
+
+ switch (error) {
+ case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
+ if (!wasUserDetected() && !isBiometricPrompt()) {
+ // No vibration if user was not detected on keyguard
+ break;
+ }
+ case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
+ case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
+ if (mAuthAttempted) {
+ // Only vibrate if auth was attempted. If the user was already locked out prior
+ // to starting authentication, do not vibrate.
+ vibrateError();
+ }
+ break;
+ default:
+ break;
+ }
+
+ super.onError(error, vendorCode);
+ }
+
+ private int[] getAcquireIgnorelist() {
+ return isBiometricPrompt() ? mBiometricPromptIgnoreList : mKeyguardIgnoreList;
+ }
+
+ private int[] getAcquireVendorIgnorelist() {
+ return isBiometricPrompt() ? mBiometricPromptIgnoreListVendor : mKeyguardIgnoreListVendor;
+ }
+
+ private boolean shouldSend(int acquireInfo, int vendorCode) {
+ if (acquireInfo == FaceManager.FACE_ACQUIRED_VENDOR) {
+ return !Utils.listContains(getAcquireVendorIgnorelist(), vendorCode);
+ } else {
+ return !Utils.listContains(getAcquireIgnorelist(), acquireInfo);
+ }
+ }
+
+ @Override
+ public void onAcquired(int acquireInfo, int vendorCode) {
+ mLastAcquire = acquireInfo;
+
+ final boolean shouldSend = shouldSend(acquireInfo, vendorCode);
+ onAcquiredInternal(acquireInfo, vendorCode, shouldSend);
+ }
+
+ @Override public void onLockoutTimed(long durationMillis) {
+ mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED);
+ // Lockout metrics are logged as an error code.
+ final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT;
+ logOnError(getContext(), error, 0 /* vendorCode */, getTargetUserId());
+
+ try {
+ getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ @Override public void onLockoutPermanent() {
+ mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT);
+ // Lockout metrics are logged as an error code.
+ final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT;
+ logOnError(getContext(), error, 0 /* vendorCode */, getTargetUserId());
+
+ try {
+ getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
new file mode 100644
index 000000000000..f950862bacd9
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -0,0 +1,120 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.biometrics.BiometricFaceConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.face.Face;
+import android.hardware.face.FaceManager;
+import android.os.IBinder;
+import android.os.NativeHandle;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.EnrollClient;
+import com.android.server.biometrics.sensors.face.FaceUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Face-specific enroll client for the {@link IFace} AIDL HAL interface.
+ */
+public class FaceEnrollClient extends EnrollClient<ISession> {
+
+ private static final String TAG = "FaceEnrollClient";
+
+ @NonNull private final int[] mEnrollIgnoreList;
+ @NonNull private final int[] mEnrollIgnoreListVendor;
+ @Nullable private ICancellationSignal mCancellationSignal;
+ private final int mMaxTemplatesPerUser;
+
+ FaceEnrollClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
+ @NonNull byte[] hardwareAuthToken, @NonNull String opPackageName,
+ @NonNull BiometricUtils<Face> utils, @NonNull int[] disabledFeatures, int timeoutSec,
+ @Nullable NativeHandle previewSurface, int sensorId, int maxTemplatesPerUser) {
+ super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, opPackageName, utils,
+ timeoutSec, BiometricsProtoEnums.MODALITY_FACE, sensorId,
+ false /* shouldVibrate */);
+ mEnrollIgnoreList = getContext().getResources()
+ .getIntArray(R.array.config_face_acquire_enroll_ignorelist);
+ mEnrollIgnoreListVendor = getContext().getResources()
+ .getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist);
+ mMaxTemplatesPerUser = maxTemplatesPerUser;
+ }
+
+ @Override
+ protected boolean hasReachedEnrollmentLimit() {
+ return FaceUtils.getInstance(getSensorId()).getBiometricsForUser(getContext(),
+ getTargetUserId()).size() >= mMaxTemplatesPerUser;
+ }
+
+ @Override
+ public void onAcquired(int acquireInfo, int vendorCode) {
+ final boolean shouldSend;
+ if (acquireInfo == FaceManager.FACE_ACQUIRED_VENDOR) {
+ shouldSend = !Utils.listContains(mEnrollIgnoreListVendor, vendorCode);
+ } else {
+ shouldSend = !Utils.listContains(mEnrollIgnoreList, acquireInfo);
+ }
+ onAcquiredInternal(acquireInfo, vendorCode, shouldSend);
+ }
+
+ @Override
+ protected void startHalOperation() {
+ final ArrayList<Byte> token = new ArrayList<>();
+ for (byte b : mHardwareAuthToken) {
+ token.add(b);
+ }
+
+ try {
+ // TODO(b/172593978): Pass features.
+ // TODO(b/172593521): Pass mPreviewSurface as android.hardware.common.NativeHandle.
+ mCancellationSignal = getFreshDaemon().enroll(mSequentialId,
+ HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken),
+ null /* mPreviewSurface */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when requesting enroll", e);
+ onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ protected void stopHalOperation() {
+ if (mCancellationSignal != null) {
+ try {
+ mCancellationSignal.cancel();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when requesting cancel", e);
+ onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.java
new file mode 100644
index 000000000000..d7e08e462777
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGenerateChallengeClient.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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.GenerateChallengeClient;
+
+/**
+ * Face-specific generateChallenge client for the {@link IFace} AIDL HAL interface.
+ */
+public class FaceGenerateChallengeClient extends GenerateChallengeClient<ISession> {
+ private static final String TAG = "FaceGenerateChallengeClient";
+ private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes
+
+ FaceGenerateChallengeClient(@NonNull Context context,
+ @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+ @NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId) {
+ super(context, lazyDaemon, token, listener, owner, sensorId);
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ getFreshDaemon().generateChallenge(mSequentialId, CHALLENGE_TIMEOUT_SEC);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to generateChallenge", e);
+ }
+ }
+
+ void onChallengeGenerated(int sensorId, int userId, long challenge) {
+ try {
+ getListener().onChallengeGenerated(sensorId, challenge);
+ mCallback.onClientFinished(this, true /* success */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to send challenge", e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
new file mode 100644
index 000000000000..3280e9815660
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
@@ -0,0 +1,63 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.ISession;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.ClientMonitor;
+
+import java.util.Map;
+
+class FaceGetAuthenticatorIdClient extends ClientMonitor<ISession> {
+
+ private static final String TAG = "FaceGetAuthenticatorIdClient";
+
+ private final Map<Integer, Long> mAuthenticatorIds;
+
+ FaceGetAuthenticatorIdClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
+ int userId, @NonNull String opPackageName, int sensorId,
+ Map<Integer, Long> authenticatorIds) {
+ super(context, lazyDaemon, null /* token */, null /* listener */, userId, opPackageName,
+ 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_FACE,
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ mAuthenticatorIds = authenticatorIds;
+ }
+
+ @Override
+ public void unableToStart() {
+ // Nothing to do here
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ getFreshDaemon().getAuthenticatorId(mSequentialId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ void onAuthenticatorIdRetrieved(long authenticatorId) {
+ mAuthenticatorIds.put(getTargetUserId(), authenticatorId);
+ mCallback.onClientFinished(this, true /* success */);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java
new file mode 100644
index 000000000000..9680e4e1841e
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalCleanupClient.java
@@ -0,0 +1,67 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.face.Face;
+import android.os.IBinder;
+
+import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.InternalCleanupClient;
+import com.android.server.biometrics.sensors.InternalEnumerateClient;
+import com.android.server.biometrics.sensors.RemovalClient;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Face-specific internal cleanup client for the {@link IFace} AIDL HAL interface.
+ */
+class FaceInternalCleanupClient extends InternalCleanupClient<Face, ISession> {
+
+ FaceInternalCleanupClient(@NonNull Context context,
+ @NonNull LazyDaemon<ISession> lazyDaemon, int userId, @NonNull String owner,
+ int sensorId, @NonNull List<Face> enrolledList, @NonNull BiometricUtils<Face> utils,
+ @NonNull Map<Integer, Long> authenticatorIds) {
+ super(context, lazyDaemon, userId, owner, sensorId, BiometricsProtoEnums.MODALITY_FACE,
+ enrolledList, utils, authenticatorIds);
+ }
+
+ @Override
+ protected InternalEnumerateClient<ISession> getEnumerateClient(Context context,
+ LazyDaemon<ISession> lazyDaemon, IBinder token, int userId, String owner,
+ List<Face> enrolledList, BiometricUtils<Face> utils, int sensorId) {
+ return new FaceInternalEnumerateClient(context, lazyDaemon, token, userId, owner,
+ enrolledList, utils, sensorId);
+ }
+
+ @Override
+ protected RemovalClient<Face, ISession> getRemovalClient(Context context,
+ LazyDaemon<ISession> lazyDaemon, IBinder token,
+ int biometricId, int userId, String owner, BiometricUtils<Face> utils, int sensorId,
+ Map<Integer, Long> authenticatorIds) {
+ // Internal remove does not need to send results to anyone. Cleanup (enumerate + remove)
+ // is all done internally.
+ return new FaceRemovalClient(context, lazyDaemon, token,
+ null /* ClientMonitorCallbackConverter */, biometricId, userId, owner, utils,
+ sensorId, authenticatorIds);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java
new file mode 100644
index 000000000000..75888a5f28c9
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceInternalEnumerateClient.java
@@ -0,0 +1,57 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.face.Face;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.InternalEnumerateClient;
+
+import java.util.List;
+
+/**
+ * Face-specific internal enumerate client for the {@link IFace} AIDL HAL interface.
+ */
+class FaceInternalEnumerateClient extends InternalEnumerateClient<ISession> {
+ private static final String TAG = "FaceInternalEnumerateClient";
+
+ FaceInternalEnumerateClient(@NonNull Context context,
+ @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token, int userId,
+ @NonNull String owner, @NonNull List<Face> enrolledList,
+ @NonNull BiometricUtils<Face> utils, int sensorId) {
+ super(context, lazyDaemon, token, userId, owner, enrolledList, utils, sensorId,
+ BiometricsProtoEnums.MODALITY_FACE);
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ getFreshDaemon().enumerateEnrollments(mSequentialId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when requesting enumerate", e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
new file mode 100644
index 000000000000..590579adbe1a
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -0,0 +1,580 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.SensorProps;
+import android.hardware.face.Face;
+import android.hardware.face.FaceSensorPropertiesInternal;
+import android.hardware.face.IFaceServiceReceiver;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.NativeHandle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserManager;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.ClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutResetDispatcher;
+import com.android.server.biometrics.sensors.PerformanceTracker;
+import com.android.server.biometrics.sensors.face.FaceUtils;
+import com.android.server.biometrics.sensors.face.ServiceProvider;
+import com.android.server.biometrics.sensors.face.UsageStats;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Provider for a single instance of the {@link IFace} HAL.
+ */
+public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
+ private static final String TAG = "FaceProvider";
+ private static final int ENROLL_TIMEOUT_SEC = 75;
+
+ @NonNull private final Context mContext;
+ @NonNull private final String mHalInstanceName;
+ @NonNull private final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
+ @NonNull private final ClientMonitor.LazyDaemon<IFace> mLazyDaemon;
+ @NonNull private final Handler mHandler;
+ @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
+ @NonNull private final UsageStats mUsageStats;
+ @NonNull private final IActivityTaskManager mActivityTaskManager;
+ @NonNull private final BiometricTaskStackListener mTaskStackListener;
+
+ @Nullable private IFace mDaemon;
+
+ private final class BiometricTaskStackListener extends TaskStackListener {
+ @Override
+ public void onTaskStackChanged() {
+ mHandler.post(() -> {
+ for (int i = 0; i < mSensors.size(); i++) {
+ final ClientMonitor<?> client = mSensors.get(i).getScheduler()
+ .getCurrentClient();
+ if (!(client instanceof AuthenticationClient)) {
+ Slog.e(getTag(), "Task stack changed for client: " + client);
+ continue;
+ }
+ if (Utils.isKeyguard(mContext, client.getOwnerString())) {
+ continue; // Keyguard is always allowed
+ }
+
+ try {
+ final List<ActivityManager.RunningTaskInfo> runningTasks =
+ mActivityTaskManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ final String topPackage =
+ runningTasks.get(0).topActivity.getPackageName();
+ if (!topPackage.contentEquals(client.getOwnerString())
+ && !client.isAlreadyDone()) {
+ Slog.e(getTag(), "Stopping background authentication, top: "
+ + topPackage + " currentClient: " + client);
+ mSensors.get(i).getScheduler()
+ .cancelAuthentication(client.getToken());
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to get running tasks", e);
+ }
+ }
+ });
+ }
+ }
+
+ public FaceProvider(@NonNull Context context, @NonNull SensorProps[] props,
+ @NonNull String halInstanceName,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ mContext = context;
+ mHalInstanceName = halInstanceName;
+ mSensors = new SparseArray<>();
+ mLazyDaemon = this::getHalInstance;
+ mHandler = new Handler(Looper.getMainLooper());
+ mUsageStats = new UsageStats(context);
+ mLockoutResetDispatcher = lockoutResetDispatcher;
+ mActivityTaskManager = ActivityTaskManager.getService();
+ mTaskStackListener = new BiometricTaskStackListener();
+
+ for (SensorProps prop : props) {
+ final int sensorId = prop.commonProps.sensorId;
+
+ final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
+ prop.commonProps.sensorId, prop.commonProps.sensorStrength,
+ prop.commonProps.maxEnrollmentsPerUser, false /* supportsFaceDetection */,
+ prop.halControlsPreview);
+ final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
+ internalProp);
+
+ mSensors.put(sensorId, sensor);
+ Slog.d(getTag(), "Added: " + internalProp);
+ }
+ }
+
+ private String getTag() {
+ return "FaceProvider/" + mHalInstanceName;
+ }
+
+ @Nullable
+ private synchronized IFace getHalInstance() {
+ if (mDaemon != null) {
+ return mDaemon;
+ }
+
+ Slog.d(getTag(), "Daemon was null, reconnecting");
+
+ mDaemon = IFace.Stub.asInterface(
+ ServiceManager.waitForDeclaredService(IFace.DESCRIPTOR + "/" + mHalInstanceName));
+ if (mDaemon == null) {
+ Slog.e(getTag(), "Unable to get daemon");
+ return null;
+ }
+
+ try {
+ mDaemon.asBinder().linkToDeath(this, 0 /* flags */);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to linkToDeath", e);
+ }
+
+ for (int i = 0; i < mSensors.size(); i++) {
+ final int sensorId = mSensors.keyAt(i);
+ scheduleLoadAuthenticatorIds(sensorId);
+ scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser());
+ }
+
+ return mDaemon;
+ }
+
+ private void scheduleForSensor(int sensorId, @NonNull ClientMonitor<?> client) {
+ if (!mSensors.contains(sensorId)) {
+ throw new IllegalStateException("Unable to schedule client: " + client
+ + " for sensor: " + sensorId);
+ }
+ mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ }
+
+ private void scheduleForSensor(int sensorId, @NonNull ClientMonitor<?> client,
+ ClientMonitor.Callback callback) {
+ if (!mSensors.contains(sensorId)) {
+ throw new IllegalStateException("Unable to schedule client: " + client
+ + " for sensor: " + sensorId);
+ }
+ mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
+ }
+
+ private void createNewSessionWithoutHandler(@NonNull IFace daemon, int sensorId,
+ int userId) throws RemoteException {
+ // Note that per IFingerprint createSession contract, this method will block until all
+ // existing operations are canceled/finished. However, also note that this is fine, since
+ // this method "withoutHandler" means it should only ever be invoked from the worker thread,
+ // so callers will never be blocked.
+ mSensors.get(sensorId).createNewSession(daemon, sensorId, userId);
+ }
+
+
+ private void scheduleLoadAuthenticatorIds(int sensorId) {
+ for (UserInfo user : UserManager.get(mContext).getAliveUsers()) {
+ scheduleLoadAuthenticatorIdsForUser(sensorId, user.id);
+ }
+ }
+
+ private void scheduleLoadAuthenticatorIdsForUser(int sensorId, int userId) {
+ mHandler.post(() -> {
+ final IFace daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during loadAuthenticatorIds, sensorId: " + sensorId);
+ return;
+ }
+
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final FaceGetAuthenticatorIdClient client = new FaceGetAuthenticatorIdClient(
+ mContext, mSensors.get(sensorId).getLazySession(), userId,
+ mContext.getOpPackageName(), sensorId,
+ mSensors.get(sensorId).getAuthenticatorIds());
+
+ mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling loadAuthenticatorId"
+ + ", sensorId: " + sensorId
+ + ", userId: " + userId, e);
+ }
+ });
+ }
+
+ @Override
+ public boolean containsSensor(int sensorId) {
+ return mSensors.contains(sensorId);
+ }
+
+ @NonNull
+ @Override
+ public List<FaceSensorPropertiesInternal> getSensorProperties() {
+ final List<FaceSensorPropertiesInternal> props = new ArrayList<>();
+ for (int i = 0; i < mSensors.size(); ++i) {
+ props.add(mSensors.valueAt(i).getSensorProperties());
+ }
+ return props;
+ }
+
+ @NonNull
+ @Override
+ public List<Face> getEnrolledFaces(int sensorId, int userId) {
+ return FaceUtils.getInstance(sensorId).getBiometricsForUser(mContext, userId);
+ }
+
+ @Override
+ public int getLockoutModeForUser(int sensorId, int userId) {
+ return mSensors.get(sensorId).getLockoutCache().getLockoutModeForUser(userId);
+ }
+
+ @Override
+ public long getAuthenticatorId(int sensorId, int userId) {
+ return mSensors.get(sensorId).getAuthenticatorIds().getOrDefault(userId, 0L);
+ }
+
+ @Override
+ public boolean isHardwareDetected(int sensorId) {
+ return getHalInstance() != null;
+ }
+
+ @Override
+ public void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token,
+ @NonNull IFaceServiceReceiver receiver, String opPackageName) {
+ mHandler.post(() -> {
+ final IFace daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during generateChallenge, sensorId: " + sensorId);
+ return;
+ }
+
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(mContext,
+ mSensors.get(sensorId).getLazySession(), token,
+ new ClientMonitorCallbackConverter(receiver), opPackageName, sensorId);
+
+ scheduleForSensor(sensorId, client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling generateChallenge", e);
+ }
+ });
+ }
+
+ @Override
+ public void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token,
+ @NonNull String opPackageName, long challenge) {
+ mHandler.post(() -> {
+ final IFace daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during revokeChallenge, sensorId: " + sensorId);
+ return;
+ }
+
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
+ mSensors.get(sensorId).getLazySession(), token, opPackageName, sensorId,
+ challenge);
+
+ scheduleForSensor(sensorId, client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling revokeChallenge", e);
+ }
+ });
+ }
+
+ @Override
+ public void scheduleEnroll(int sensorId, @NonNull IBinder token,
+ @NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver,
+ @NonNull String opPackageName, @NonNull int[] disabledFeatures,
+ @Nullable NativeHandle previewSurface) {
+ mHandler.post(() -> {
+ final IFace daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during enroll, sensorId: " + sensorId);
+ // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+ // this operation. We should not send the callback yet, since the scheduler may
+ // be processing something else.
+ return;
+ }
+
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final int maxTemplatesPerUser = mSensors.get(
+ sensorId).getSensorProperties().maxEnrollmentsPerUser;
+ final FaceEnrollClient client = new FaceEnrollClient(mContext,
+ mSensors.get(sensorId).getLazySession(), token,
+ new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
+ opPackageName, FaceUtils.getInstance(sensorId), disabledFeatures,
+ ENROLL_TIMEOUT_SEC, previewSurface, sensorId, maxTemplatesPerUser);
+ scheduleForSensor(sensorId, client, new ClientMonitor.Callback() {
+ @Override
+ public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor,
+ boolean success) {
+ if (success) {
+ scheduleLoadAuthenticatorIdsForUser(sensorId, userId);
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling enroll", e);
+ }
+ });
+ }
+
+ @Override
+ public void cancelEnrollment(int sensorId, @NonNull IBinder token) {
+ mHandler.post(() -> mSensors.get(sensorId).getScheduler().cancelEnrollment(token));
+ }
+
+ @Override
+ public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+ int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
+ @NonNull String opPackageName, boolean restricted, int statsClient,
+ boolean isKeyguard) {
+ mHandler.post(() -> {
+ final IFace daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during authenticate, sensorId: " + sensorId);
+ // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+ // this operation. We should not send the callback yet, since the scheduler may
+ // be processing something else.
+ return;
+ }
+
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
+ final FaceAuthenticationClient client = new FaceAuthenticationClient(
+ mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
+ operationId, restricted, opPackageName, cookie,
+ false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
+ mUsageStats, mSensors.get(sensorId).getLockoutCache());
+ mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling authenticate", e);
+ }
+ });
+ }
+
+ @Override
+ public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
+ mHandler.post(() -> mSensors.get(sensorId).getScheduler().cancelAuthentication(token));
+ }
+
+ @Override
+ public void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId,
+ @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
+ mHandler.post(() -> {
+ final IFace daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during remove, sensorId: " + sensorId);
+ // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+ // this operation. We should not send the callback yet, since the scheduler may
+ // be processing something else.
+ return;
+ }
+
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final FaceRemovalClient client = new FaceRemovalClient(mContext,
+ mSensors.get(sensorId).getLazySession(), token,
+ new ClientMonitorCallbackConverter(receiver), faceId, userId,
+ opPackageName, FaceUtils.getInstance(sensorId), sensorId,
+ mSensors.get(sensorId).getAuthenticatorIds());
+
+ mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling remove", e);
+ }
+ });
+ }
+
+ @Override
+ public void scheduleResetLockout(int sensorId, int userId, @NonNull byte[] hardwareAuthToken) {
+ mHandler.post(() -> {
+ final IFace daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during resetLockout, sensorId: " + sensorId);
+ return;
+ }
+
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final FaceResetLockoutClient client = new FaceResetLockoutClient(
+ mContext, mSensors.get(sensorId).getLazySession(), userId,
+ mContext.getOpPackageName(), sensorId, hardwareAuthToken,
+ mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher);
+
+ scheduleForSensor(sensorId, client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling resetLockout", e);
+ }
+ });
+ }
+
+ @Override
+ public void scheduleSetFeature(int sensorId, @NonNull IBinder token, int userId, int feature,
+ boolean enabled, @NonNull byte[] hardwareAuthToken,
+ @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
+ // TODO(b/171335732): implement this.
+ }
+
+ @Override
+ public void scheduleGetFeature(int sensorId, @NonNull IBinder token, int userId, int feature,
+ @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName) {
+ // TODO(b/171335732): implement this.
+ }
+
+ @Override
+ public void startPreparedClient(int sensorId, int cookie) {
+ mHandler.post(() -> {
+ mSensors.get(sensorId).getScheduler().startPreparedClient(cookie);
+ });
+ }
+
+ @Override
+ public void scheduleInternalCleanup(int sensorId, int userId) {
+ mHandler.post(() -> {
+ final IFace daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during internal cleanup, sensorId: " + sensorId);
+ return;
+ }
+
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final List<Face> enrolledList = getEnrolledFaces(sensorId, userId);
+ final FaceInternalCleanupClient client =
+ new FaceInternalCleanupClient(mContext,
+ mSensors.get(sensorId).getLazySession(), userId,
+ mContext.getOpPackageName(), sensorId, enrolledList,
+ FaceUtils.getInstance(sensorId),
+ mSensors.get(sensorId).getAuthenticatorIds());
+
+ mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling internal cleanup", e);
+ }
+ });
+ }
+
+ @Override
+ public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) {
+
+ }
+
+ @Override
+ public void dumpProtoMetrics(int sensorId, @NonNull FileDescriptor fd) {
+
+ }
+
+ @Override
+ public void dumpInternal(int sensorId, @NonNull PrintWriter pw) {
+ PerformanceTracker performanceTracker =
+ PerformanceTracker.getInstanceForSensorId(sensorId);
+
+ JSONObject dump = new JSONObject();
+ try {
+ dump.put("service", "Face Manager");
+
+ JSONArray sets = new JSONArray();
+ for (UserInfo user : UserManager.get(mContext).getUsers()) {
+ final int userId = user.getUserHandle().getIdentifier();
+ final int c = FaceUtils.getInstance().getBiometricsForUser(mContext, userId).size();
+ JSONObject set = new JSONObject();
+ set.put("id", userId);
+ set.put("count", c);
+ set.put("accept", performanceTracker.getAcceptForUser(userId));
+ set.put("reject", performanceTracker.getRejectForUser(userId));
+ set.put("acquire", performanceTracker.getAcquireForUser(userId));
+ set.put("lockout", performanceTracker.getTimedLockoutForUser(userId));
+ set.put("permanentLockout", performanceTracker.getPermanentLockoutForUser(userId));
+ // cryptoStats measures statistics about secure face transactions
+ // (e.g. to unlock password storage, make secure purchases, etc.)
+ set.put("acceptCrypto", performanceTracker.getAcceptCryptoForUser(userId));
+ set.put("rejectCrypto", performanceTracker.getRejectCryptoForUser(userId));
+ set.put("acquireCrypto", performanceTracker.getAcquireCryptoForUser(userId));
+ sets.put(set);
+ }
+
+ dump.put("prints", sets);
+ } catch (JSONException e) {
+ Slog.e(TAG, "dump formatting failure", e);
+ }
+ pw.println(dump);
+ pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount());
+
+ mSensors.get(sensorId).getScheduler().dump(pw);
+ mUsageStats.print(pw);
+ }
+
+ @Override
+ public void binderDied() {
+ Slog.e(getTag(), "HAL died");
+ mHandler.post(() -> {
+ mDaemon = null;
+ for (int i = 0; i < mSensors.size(); i++) {
+ final int sensorId = mSensors.keyAt(i);
+ PerformanceTracker.getInstanceForSensorId(sensorId).incrementHALDeathCount();
+ }
+ });
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java
new file mode 100644
index 000000000000..1cb5031374ec
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRemovalClient.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.face.Face;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.BiometricUtils;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.RemovalClient;
+
+import java.util.Map;
+
+/**
+ * Face-specific removal client for the {@link IFace} AIDL HAL interface.
+ */
+class FaceRemovalClient extends RemovalClient<Face, ISession> {
+ private static final String TAG = "FaceRemovalClient";
+
+ FaceRemovalClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
+ int biometricId, int userId, @NonNull String owner, @NonNull BiometricUtils<Face> utils,
+ int sensorId, @NonNull Map<Integer, Long> authenticatorIds) {
+ super(context, lazyDaemon, token, listener, biometricId, userId, owner, utils, sensorId,
+ authenticatorIds, BiometricsProtoEnums.MODALITY_FACE);
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ final int[] ids = new int[]{mBiometricId};
+ getFreshDaemon().removeEnrollments(mSequentialId, ids);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when requesting remove", e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
new file mode 100644
index 000000000000..5d100ec5e6dd
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
@@ -0,0 +1,79 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.keymaster.HardwareAuthToken;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.sensors.ClientMonitor;
+import com.android.server.biometrics.sensors.LockoutCache;
+import com.android.server.biometrics.sensors.LockoutResetDispatcher;
+import com.android.server.biometrics.sensors.LockoutTracker;
+
+/**
+ * Face-specific resetLockout client for the {@link IFace} AIDL HAL interface.
+ * Updates the framework's lockout cache and notifies clients such as Keyguard when lockout is
+ * cleared.
+ */
+public class FaceResetLockoutClient extends ClientMonitor<ISession> {
+
+ private static final String TAG = "FaceResetLockoutClient";
+
+ private final HardwareAuthToken mHardwareAuthToken;
+ private final LockoutCache mLockoutCache;
+ private final LockoutResetDispatcher mLockoutResetDispatcher;
+
+ FaceResetLockoutClient(@NonNull Context context,
+ @NonNull LazyDaemon<ISession> lazyDaemon, int userId, String owner, int sensorId,
+ @NonNull byte[] hardwareAuthToken, @NonNull LockoutCache lockoutTracker,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
+ 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
+ mLockoutCache = lockoutTracker;
+ mLockoutResetDispatcher = lockoutResetDispatcher;
+ }
+
+ @Override
+ public void unableToStart() {
+ // Nothing to do here
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ getFreshDaemon().resetLockout(mSequentialId, mHardwareAuthToken);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to reset lockout", e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ void onLockoutCleared() {
+ mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_NONE);
+ mLockoutResetDispatcher.notifyLockoutResetCallbacks(getSensorId());
+ mCallback.onClientFinished(this, true /* success */);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClient.java
new file mode 100644
index 000000000000..2863f9fc2959
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceRevokeChallengeClient.java
@@ -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.server.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.RevokeChallengeClient;
+
+/**
+ * Face-specific revokeChallenge client for the {@link IFace} AIDL HAL interface.
+ */
+public class FaceRevokeChallengeClient extends RevokeChallengeClient<ISession> {
+
+ private static final String TAG = "FaceRevokeChallengeClient";
+
+ private final long mChallenge;
+
+ FaceRevokeChallengeClient(@NonNull Context context,
+ @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+ @NonNull String owner, int sensorId, long challenge) {
+ super(context, lazyDaemon, token, owner, sensorId);
+ mChallenge = challenge;
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ getFreshDaemon().revokeChallenge(mSequentialId, mChallenge);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to revokeChallenge", e);
+ }
+ }
+
+ void onChallengeRevoked(int sensorId, int userId, long challenge) {
+ final boolean success = challenge == mChallenge;
+ mCallback.onClientFinished(this, success);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
new file mode 100644
index 000000000000..ca1f17be9179
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -0,0 +1,456 @@
+/*
+ * 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.biometrics.sensors.face.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.Error;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.ISession;
+import android.hardware.biometrics.face.ISessionCallback;
+import android.hardware.face.Face;
+import android.hardware.face.FaceManager;
+import android.hardware.face.FaceSensorPropertiesInternal;
+import android.hardware.keymaster.HardwareAuthToken;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.biometrics.HardwareAuthTokenUtils;
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.AcquisitionClient;
+import com.android.server.biometrics.sensors.AuthenticationConsumer;
+import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.ClientMonitor;
+import com.android.server.biometrics.sensors.EnumerateConsumer;
+import com.android.server.biometrics.sensors.Interruptable;
+import com.android.server.biometrics.sensors.LockoutCache;
+import com.android.server.biometrics.sensors.LockoutConsumer;
+import com.android.server.biometrics.sensors.RemovalConsumer;
+import com.android.server.biometrics.sensors.face.FaceUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Maintains the state of a single sensor within an instance of the {@link IFace} HAL.
+ */
+public class Sensor implements IBinder.DeathRecipient {
+
+ @NonNull private final String mTag;
+ @NonNull private final FaceProvider mProvider;
+ @NonNull private final Context mContext;
+ @NonNull private final Handler mHandler;
+ @NonNull private final FaceSensorPropertiesInternal mSensorProperties;
+ @NonNull private final BiometricScheduler mScheduler;
+ @NonNull private final LockoutCache mLockoutCache;
+ @NonNull private final Map<Integer, Long> mAuthenticatorIds;
+ @NonNull private final ClientMonitor.LazyDaemon<ISession> mLazySession;
+ @Nullable private Session mCurrentSession;
+
+ @Override
+ public void binderDied() {
+ Slog.e(mTag, "Binder died");
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (client instanceof Interruptable) {
+ Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
+ final Interruptable interruptable = (Interruptable) client;
+ interruptable.onError(FaceManager.FACE_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+
+ mScheduler.recordCrashState();
+
+ FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
+ BiometricsProtoEnums.MODALITY_FACE,
+ BiometricsProtoEnums.ISSUE_HAL_DEATH);
+ mCurrentSession = null;
+ }
+ });
+ }
+
+ static class Session {
+ @NonNull final HalSessionCallback mHalSessionCallback;
+ @NonNull private final String mTag;
+ @NonNull private final ISession mSession;
+ private final int mUserId;
+
+ Session(@NonNull String tag, @NonNull ISession session, int userId,
+ @NonNull HalSessionCallback halSessionCallback) {
+ mTag = tag;
+ mSession = session;
+ mUserId = userId;
+ mHalSessionCallback = halSessionCallback;
+ Slog.d(mTag, "New session created for user: " + userId);
+ }
+ }
+
+ Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
+ @NonNull Handler handler, @NonNull FaceSensorPropertiesInternal sensorProperties) {
+ mTag = tag;
+ mProvider = provider;
+ mContext = context;
+ mHandler = handler;
+ mSensorProperties = sensorProperties;
+ mScheduler = new BiometricScheduler(tag, null /* gestureAvailabilityDispatcher */);
+ mLockoutCache = new LockoutCache();
+ mAuthenticatorIds = new HashMap<>();
+ mLazySession = () -> (mCurrentSession != null) ? mCurrentSession.mSession : null;
+ }
+
+ @NonNull ClientMonitor.LazyDaemon<ISession> getLazySession() {
+ return mLazySession;
+ }
+
+ @NonNull FaceSensorPropertiesInternal getSensorProperties() {
+ return mSensorProperties;
+ }
+
+ @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+ boolean hasSessionForUser(int userId) {
+ return mCurrentSession != null && mCurrentSession.mUserId == userId;
+ }
+
+ @Nullable Session getSessionForUser(int userId) {
+ if (mCurrentSession != null && mCurrentSession.mUserId == userId) {
+ return mCurrentSession;
+ } else {
+ return null;
+ }
+ }
+
+ void createNewSession(@NonNull IFace daemon, int sensorId, int userId)
+ throws RemoteException {
+
+ final HalSessionCallback.Callback callback = () -> {
+ Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
+ mCurrentSession = null;
+ };
+ final HalSessionCallback resultController = new HalSessionCallback(mContext, mHandler,
+ mTag, mScheduler, sensorId, userId, callback);
+
+ final ISession newSession = daemon.createSession(sensorId, userId, resultController);
+ newSession.asBinder().linkToDeath(this, 0 /* flags */);
+ mCurrentSession = new Session(mTag, newSession, userId, resultController);
+ }
+
+ @NonNull BiometricScheduler getScheduler() {
+ return mScheduler;
+ }
+
+ @NonNull LockoutCache getLockoutCache() {
+ return mLockoutCache;
+ }
+
+ @NonNull Map<Integer, Long> getAuthenticatorIds() {
+ return mAuthenticatorIds;
+ }
+
+ static class HalSessionCallback extends ISessionCallback.Stub {
+ /**
+ * Interface to sends results to the HalSessionCallback's owner.
+ */
+ public interface Callback {
+ /**
+ * Invoked when the HAL sends ERROR_HW_UNAVAILABLE.
+ */
+ void onHardwareUnavailable();
+ }
+
+ @NonNull
+ private final Context mContext;
+ @NonNull
+ private final Handler mHandler;
+ @NonNull
+ private final String mTag;
+ @NonNull
+ private final BiometricScheduler mScheduler;
+ private final int mSensorId;
+ private final int mUserId;
+ @NonNull
+ private final Callback mCallback;
+
+ HalSessionCallback(@NonNull Context context, @NonNull Handler handler, @NonNull String tag,
+ @NonNull BiometricScheduler scheduler, int sensorId, int userId,
+ @NonNull Callback callback) {
+ mContext = context;
+ mHandler = handler;
+ mTag = tag;
+ mScheduler = scheduler;
+ mSensorId = sensorId;
+ mUserId = userId;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onStateChanged(int cookie, byte state) {
+ // TODO(b/162973174)
+ }
+
+ @Override
+ public void onChallengeGenerated(int sensorId, int userId, long challenge) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof FaceGenerateChallengeClient)) {
+ Slog.e(mTag, "onChallengeGenerated for wrong client: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final FaceGenerateChallengeClient generateChallengeClient =
+ (FaceGenerateChallengeClient) client;
+ generateChallengeClient.onChallengeGenerated(mSensorId, mUserId, challenge);
+ });
+ }
+
+ @Override
+ public void onChallengeRevoked(int sensorId, int userId, long challenge) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof FaceRevokeChallengeClient)) {
+ Slog.e(mTag, "onChallengeRevoked for wrong client: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final FaceRevokeChallengeClient revokeChallengeClient =
+ (FaceRevokeChallengeClient) client;
+ revokeChallengeClient.onChallengeRevoked(mSensorId, mUserId, challenge);
+ });
+ }
+
+ @Override
+ public void onAcquired(byte info, int vendorCode) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof AcquisitionClient)) {
+ Slog.e(mTag, "onAcquired for non-acquisition client: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final AcquisitionClient<?> acquisitionClient = (AcquisitionClient<?>) client;
+ acquisitionClient.onAcquired(info, vendorCode);
+ });
+ }
+
+ @Override
+ public void onError(byte error, int vendorCode) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ Slog.d(mTag, "onError"
+ + ", client: " + Utils.getClientName(client)
+ + ", error: " + error
+ + ", vendorCode: " + vendorCode);
+ if (!(client instanceof Interruptable)) {
+ Slog.e(mTag, "onError for non-error consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final Interruptable interruptable = (Interruptable) client;
+ interruptable.onError(error, vendorCode);
+
+ if (error == Error.HW_UNAVAILABLE) {
+ mCallback.onHardwareUnavailable();
+ }
+ });
+ }
+
+ @Override
+ public void onEnrollmentProgress(int enrollmentId, int remaining) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof FaceEnrollClient)) {
+ Slog.e(mTag, "onEnrollmentProgress for non-enroll client: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final int currentUserId = client.getTargetUserId();
+ final CharSequence name = FaceUtils.getInstance(mSensorId)
+ .getUniqueName(mContext, currentUserId);
+ final Face face = new Face(name, enrollmentId, mSensorId);
+
+ final FaceEnrollClient enrollClient = (FaceEnrollClient) client;
+ enrollClient.onEnrollResult(face, remaining);
+ });
+ }
+
+ @Override
+ public void onAuthenticationSucceeded(int enrollmentId, HardwareAuthToken hat) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof AuthenticationConsumer)) {
+ Slog.e(mTag, "onAuthenticationSucceeded for non-authentication consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final AuthenticationConsumer authenticationConsumer =
+ (AuthenticationConsumer) client;
+ final Face face = new Face("" /* name */, enrollmentId, mSensorId);
+ final byte[] byteArray = HardwareAuthTokenUtils.toByteArray(hat);
+ final ArrayList<Byte> byteList = new ArrayList<>();
+ for (byte b : byteArray) {
+ byteList.add(b);
+ }
+ authenticationConsumer.onAuthenticated(face, true /* authenticated */, byteList);
+ });
+ }
+
+ @Override
+ public void onAuthenticationFailed() {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof AuthenticationConsumer)) {
+ Slog.e(mTag, "onAuthenticationFailed for non-authentication consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final AuthenticationConsumer authenticationConsumer =
+ (AuthenticationConsumer) client;
+ final Face face = new Face("" /* name */, 0 /* faceId */, mSensorId);
+ authenticationConsumer.onAuthenticated(face, false /* authenticated */,
+ null /* hat */);
+ });
+ }
+
+ @Override
+ public void onLockoutTimed(long durationMillis) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof LockoutConsumer)) {
+ Slog.e(mTag, "onLockoutTimed for non-lockout consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final LockoutConsumer lockoutConsumer = (LockoutConsumer) client;
+ lockoutConsumer.onLockoutTimed(durationMillis);
+ });
+ }
+
+ @Override
+ public void onLockoutPermanent() {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof LockoutConsumer)) {
+ Slog.e(mTag, "onLockoutPermanent for non-lockout consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final LockoutConsumer lockoutConsumer = (LockoutConsumer) client;
+ lockoutConsumer.onLockoutPermanent();
+ });
+ }
+
+ @Override
+ public void onLockoutCleared() {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof FaceResetLockoutClient)) {
+ Slog.e(mTag, "onLockoutCleared for non-resetLockout client: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final FaceResetLockoutClient resetLockoutClient = (FaceResetLockoutClient) client;
+ resetLockoutClient.onLockoutCleared();
+ });
+ }
+
+ @Override
+ public void onInteractionDetected() {
+ // no-op
+ }
+
+ @Override
+ public void onEnrollmentsEnumerated(int[] enrollmentIds) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof EnumerateConsumer)) {
+ Slog.e(mTag, "onEnrollmentsEnumerated for non-enumerate consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final EnumerateConsumer enumerateConsumer =
+ (EnumerateConsumer) client;
+ if (enrollmentIds.length > 0) {
+ for (int i = 0; i < enrollmentIds.length; ++i) {
+ final Face face = new Face("" /* name */, enrollmentIds[i], mSensorId);
+ enumerateConsumer.onEnumerationResult(face, enrollmentIds.length - i - 1);
+ }
+ } else {
+ enumerateConsumer.onEnumerationResult(null /* identifier */, 0 /* remaining */);
+ }
+ });
+ }
+
+ @Override
+ public void onEnrollmentsRemoved(int[] enrollmentIds) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof RemovalConsumer)) {
+ Slog.e(mTag, "onRemoved for non-removal consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final RemovalConsumer removalConsumer = (RemovalConsumer) client;
+ if (enrollmentIds.length > 0) {
+ for (int i = 0; i < enrollmentIds.length; i++) {
+ final Face face = new Face("" /* name */, enrollmentIds[i], mSensorId);
+ removalConsumer.onRemoved(face, enrollmentIds.length - i - 1);
+ }
+ } else {
+ removalConsumer.onRemoved(null /* identifier */, 0 /* remaining */);
+ }
+ });
+ }
+
+ @Override
+ public void onAuthenticatorIdRetrieved(long authenticatorId) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof FaceGetAuthenticatorIdClient)) {
+ Slog.e(mTag, "onAuthenticatorIdRetrieved for wrong consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final FaceGetAuthenticatorIdClient getAuthenticatorIdClient =
+ (FaceGetAuthenticatorIdClient) client;
+ getAuthenticatorIdClient.onAuthenticatorIdRetrieved(authenticatorId);
+ });
+ }
+
+ @Override
+ public void onAuthenticatorIdInvalidated() {
+ // TODO(b/159667191)
+ }
+
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index 15f8c5373672..7b70bd8a8730 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -63,6 +63,10 @@ import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.RemovalConsumer;
+import com.android.server.biometrics.sensors.face.FaceUtils;
+import com.android.server.biometrics.sensors.face.LockoutHalImpl;
+import com.android.server.biometrics.sensors.face.ServiceProvider;
+import com.android.server.biometrics.sensors.face.UsageStats;
import org.json.JSONArray;
import org.json.JSONException;
@@ -82,7 +86,7 @@ import java.util.Map;
* Supports a single instance of the {@link android.hardware.biometrics.face.V1_0} or
* its extended minor versions.
*/
-class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
+public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
private static final String TAG = "Face10";
private static final int ENROLL_TIMEOUT_SEC = 75;
@@ -120,166 +124,175 @@ class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
private final IBiometricsFaceClientCallback mDaemonCallback =
new IBiometricsFaceClientCallback.Stub() {
- @Override
- public void onEnrollResult(long deviceId, int faceId, int userId, int remaining) {
- mHandler.post(() -> {
- final CharSequence name = FaceUtils.getInstance()
- .getUniqueName(mContext, userId);
- final Face face = new Face(name, faceId, deviceId);
-
- final ClientMonitor<?> client = mScheduler.getCurrentClient();
- if (!(client instanceof FaceEnrollClient)) {
- Slog.e(TAG, "onEnrollResult for non-enroll client: "
- + Utils.getClientName(client));
- return;
- }
-
- final FaceEnrollClient enrollClient = (FaceEnrollClient) client;
- enrollClient.onEnrollResult(face, remaining);
- });
- }
+ @Override
+ public void onEnrollResult(long deviceId, int faceId, int userId, int remaining) {
+ mHandler.post(() -> {
+ final CharSequence name = FaceUtils.getInstance()
+ .getUniqueName(mContext, userId);
+ final Face face = new Face(name, faceId, deviceId);
+
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof FaceEnrollClient)) {
+ Slog.e(TAG, "onEnrollResult for non-enroll client: "
+ + Utils.getClientName(client));
+ return;
+ }
- @Override
- public void onAuthenticated(long deviceId, int faceId, int userId, ArrayList<Byte> token) {
- mHandler.post(() -> {
- final ClientMonitor<?> client = mScheduler.getCurrentClient();
- if (!(client instanceof AuthenticationConsumer)) {
- Slog.e(TAG, "onAuthenticated for non-authentication consumer: "
- + Utils.getClientName(client));
- return;
+ final FaceEnrollClient enrollClient = (FaceEnrollClient) client;
+ enrollClient.onEnrollResult(face, remaining);
+ });
}
- final AuthenticationConsumer authenticationConsumer =
- (AuthenticationConsumer) client;
- final boolean authenticated = faceId != 0;
- final Face face = new Face("", faceId, deviceId);
- authenticationConsumer.onAuthenticated(face, authenticated, token);
- });
- }
+ @Override
+ public void onAuthenticated(long deviceId, int faceId, int userId,
+ ArrayList<Byte> token) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof AuthenticationConsumer)) {
+ Slog.e(TAG, "onAuthenticated for non-authentication consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
- @Override
- public void onAcquired(long deviceId, int userId, int acquiredInfo, int vendorCode) {
- mHandler.post(() -> {
- final ClientMonitor<?> client = mScheduler.getCurrentClient();
- if (!(client instanceof AcquisitionClient)) {
- Slog.e(TAG, "onAcquired for non-acquire client: "
- + Utils.getClientName(client));
- return;
+ final AuthenticationConsumer authenticationConsumer =
+ (AuthenticationConsumer) client;
+ final boolean authenticated = faceId != 0;
+ final Face face = new Face("", faceId, deviceId);
+ authenticationConsumer.onAuthenticated(face, authenticated, token);
+ });
}
- final AcquisitionClient<?> acquisitionClient = (AcquisitionClient<?>) client;
- acquisitionClient.onAcquired(acquiredInfo, vendorCode);
- });
- }
+ @Override
+ public void onAcquired(long deviceId, int userId, int acquiredInfo,
+ int vendorCode) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof AcquisitionClient)) {
+ Slog.e(TAG, "onAcquired for non-acquire client: "
+ + Utils.getClientName(client));
+ return;
+ }
- @Override
- public void onError(long deviceId, int userId, int error, int vendorCode) {
- mHandler.post(() -> {
- final ClientMonitor<?> client = mScheduler.getCurrentClient();
- Slog.d(TAG, "handleError"
- + ", client: " + (client != null ? client.getOwnerString() : null)
- + ", error: " + error
- + ", vendorCode: " + vendorCode);
- if (!(client instanceof Interruptable)) {
- Slog.e(TAG, "onError for non-error consumer: " + Utils.getClientName(client));
- return;
+ final AcquisitionClient<?> acquisitionClient =
+ (AcquisitionClient<?>) client;
+ acquisitionClient.onAcquired(acquiredInfo, vendorCode);
+ });
}
- final Interruptable interruptable = (Interruptable) client;
- interruptable.onError(error, vendorCode);
+ @Override
+ public void onError(long deviceId, int userId, int error, int vendorCode) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ Slog.d(TAG, "handleError"
+ + ", client: " + (client != null ? client.getOwnerString() : null)
+ + ", error: " + error
+ + ", vendorCode: " + vendorCode);
+ if (!(client instanceof Interruptable)) {
+ Slog.e(TAG, "onError for non-error consumer: " + Utils.getClientName(
+ client));
+ return;
+ }
- if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
- Slog.e(TAG, "Got ERROR_HW_UNAVAILABLE");
- mDaemon = null;
- mCurrentUserId = UserHandle.USER_NULL;
- }
- });
- }
+ final Interruptable interruptable = (Interruptable) client;
+ interruptable.onError(error, vendorCode);
- @Override
- public void onRemoved(long deviceId, ArrayList<Integer> removed, int userId) {
- mHandler.post(() -> {
- final ClientMonitor<?> client = mScheduler.getCurrentClient();
- if (!(client instanceof RemovalConsumer)) {
- Slog.e(TAG, "onRemoved for non-removal consumer: "
- + Utils.getClientName(client));
- return;
+ if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
+ Slog.e(TAG, "Got ERROR_HW_UNAVAILABLE");
+ mDaemon = null;
+ mCurrentUserId = UserHandle.USER_NULL;
+ }
+ });
}
- final RemovalConsumer removalConsumer = (RemovalConsumer) client;
-
- if (!removed.isEmpty()) {
- // Convert to old fingerprint-like behavior, where remove() receives one removal
- // at a time. This way, remove can share some more common code.
- for (int i = 0; i < removed.size(); i++) {
- final int id = removed.get(i);
- final Face face = new Face("", id, deviceId);
- final int remaining = removed.size() - i - 1;
- Slog.d(TAG, "Removed, faceId: " + id + ", remaining: " + remaining);
- removalConsumer.onRemoved(face, remaining);
- }
- } else {
- removalConsumer.onRemoved(null, 0 /* remaining */);
- }
+ @Override
+ public void onRemoved(long deviceId, ArrayList<Integer> removed, int userId) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof RemovalConsumer)) {
+ Slog.e(TAG, "onRemoved for non-removal consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT);
- });
- }
+ final RemovalConsumer removalConsumer = (RemovalConsumer) client;
+
+ if (!removed.isEmpty()) {
+ // Convert to old fingerprint-like behavior, where remove() receives
+ // one removal
+ // at a time. This way, remove can share some more common code.
+ for (int i = 0; i < removed.size(); i++) {
+ final int id = removed.get(i);
+ final Face face = new Face("", id, deviceId);
+ final int remaining = removed.size() - i - 1;
+ Slog.d(TAG, "Removed, faceId: " + id + ", remaining: " + remaining);
+ removalConsumer.onRemoved(face, remaining);
+ }
+ } else {
+ removalConsumer.onRemoved(null, 0 /* remaining */);
+ }
- @Override
- public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId) {
- mHandler.post(() -> {
- final ClientMonitor<?> client = mScheduler.getCurrentClient();
- if (!(client instanceof EnumerateConsumer)) {
- Slog.e(TAG, "onEnumerate for non-enumerate consumer: "
- + Utils.getClientName(client));
- return;
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT);
+ });
}
- final EnumerateConsumer enumerateConsumer = (EnumerateConsumer) client;
+ @Override
+ public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof EnumerateConsumer)) {
+ Slog.e(TAG, "onEnumerate for non-enumerate consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
- if (!faceIds.isEmpty()) {
- // Convert to old fingerprint-like behavior, where enumerate() receives one
- // template at a time. This way, enumerate can share some more common code.
- for (int i = 0; i < faceIds.size(); i++) {
- final Face face = new Face("", faceIds.get(i), deviceId);
- enumerateConsumer.onEnumerationResult(face, faceIds.size() - i - 1);
- }
- } else {
- // For face, the HIDL contract is to receive an empty list when there are no
- // templates enrolled. Send a null identifier since we don't consume them
- // anywhere, and send remaining == 0 so this code can be shared with
- // Fingerprint@2.1
- enumerateConsumer.onEnumerationResult(null /* identifier */, 0);
- }
- });
- }
+ final EnumerateConsumer enumerateConsumer = (EnumerateConsumer) client;
- @Override
- public void onLockoutChanged(long duration) {
- mHandler.post(() -> {
- Slog.d(TAG, "onLockoutChanged: " + duration);
- final @LockoutTracker.LockoutMode int lockoutMode;
- if (duration == 0) {
- lockoutMode = LockoutTracker.LOCKOUT_NONE;
- } else if (duration == -1 || duration == Long.MAX_VALUE) {
- lockoutMode = LockoutTracker.LOCKOUT_PERMANENT;
- } else {
- lockoutMode = LockoutTracker.LOCKOUT_TIMED;
+ if (!faceIds.isEmpty()) {
+ // Convert to old fingerprint-like behavior, where enumerate()
+ // receives one
+ // template at a time. This way, enumerate can share some more common
+ // code.
+ for (int i = 0; i < faceIds.size(); i++) {
+ final Face face = new Face("", faceIds.get(i), deviceId);
+ enumerateConsumer.onEnumerationResult(face, faceIds.size() - i - 1);
+ }
+ } else {
+ // For face, the HIDL contract is to receive an empty list when there
+ // are no
+ // templates enrolled. Send a null identifier since we don't consume
+ // them
+ // anywhere, and send remaining == 0 so this code can be shared with
+ // Fingerprint@2.1
+ enumerateConsumer.onEnumerationResult(null /* identifier */, 0);
+ }
+ });
}
- mLockoutTracker.setCurrentUserLockoutMode(lockoutMode);
+ @Override
+ public void onLockoutChanged(long duration) {
+ mHandler.post(() -> {
+ Slog.d(TAG, "onLockoutChanged: " + duration);
+ final @LockoutTracker.LockoutMode int lockoutMode;
+ if (duration == 0) {
+ lockoutMode = LockoutTracker.LOCKOUT_NONE;
+ } else if (duration == -1 || duration == Long.MAX_VALUE) {
+ lockoutMode = LockoutTracker.LOCKOUT_PERMANENT;
+ } else {
+ lockoutMode = LockoutTracker.LOCKOUT_TIMED;
+ }
+
+ mLockoutTracker.setCurrentUserLockoutMode(lockoutMode);
- if (duration == 0) {
- mLockoutResetDispatcher.notifyLockoutResetCallbacks(mSensorId);
+ if (duration == 0) {
+ mLockoutResetDispatcher.notifyLockoutResetCallbacks(mSensorId);
+ }
+ });
}
- });
- }
- };
+ };
@VisibleForTesting
- Face10(@NonNull Context context, int sensorId,
+ public Face10(@NonNull Context context, int sensorId,
@BiometricManager.Authenticators.Types int strength,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
boolean supportsSelfIllumination, int maxTemplatesAllowed) {
@@ -304,7 +317,7 @@ class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
}
}
- Face10(@NonNull Context context, int sensorId,
+ public Face10(@NonNull Context context, int sensorId,
@BiometricManager.Authenticators.Types int strength,
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
this(context, sensorId, strength, lockoutResetDispatcher,
@@ -479,8 +492,8 @@ class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
public void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token,
@NonNull String opPackageName, long challenge) {
mHandler.post(() -> {
- if (mCurrentChallengeOwner != null &&
- !mCurrentChallengeOwner.getOwnerString().contentEquals(opPackageName)) {
+ if (mCurrentChallengeOwner != null
+ && !mCurrentChallengeOwner.getOwnerString().contentEquals(opPackageName)) {
Slog.e(TAG, "scheduleRevokeChallenge, package: " + opPackageName
+ " attempting to revoke challenge owned by: "
+ mCurrentChallengeOwner.getOwnerString());
@@ -717,10 +730,10 @@ class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
JSONArray sets = new JSONArray();
for (UserInfo user : UserManager.get(mContext).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
- final int N = FaceUtils.getInstance().getBiometricsForUser(mContext, userId).size();
+ final int c = FaceUtils.getInstance().getBiometricsForUser(mContext, userId).size();
JSONObject set = new JSONObject();
set.put("id", userId);
- set.put("count", N);
+ set.put("count", c);
set.put("accept", performanceTracker.getAcceptForUser(userId));
set.put("reject", performanceTracker.getRejectForUser(userId));
set.put("acquire", performanceTracker.getAcquireForUser(userId));
@@ -816,7 +829,7 @@ class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
try {
devnull = new FileOutputStream("/dev/null");
final NativeHandle handle = new NativeHandle(
- new FileDescriptor[] { devnull.getFD(), fd },
+ new FileDescriptor[]{devnull.getFD(), fd},
new int[0], false);
daemon.debug(handle, new ArrayList<String>(Arrays.asList(args)));
} catch (IOException | RemoteException ex) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 892d6a48488d..ce880aa8aeed 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.app.Notification;
@@ -40,6 +40,7 @@ import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutTracker;
+import com.android.server.biometrics.sensors.face.UsageStats;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
index 989b5c938cbc..1a7544fc7f01 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClient.java
index 406a7ccedc33..c3d54c2b7fbb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGenerateChallengeClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -24,7 +24,6 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
-import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.GenerateChallengeClient;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
index 33b2b6ada24c..e25bb812caa6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceInternalCleanupClient.java
index 7626587f5519..abfda499cf0f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceInternalCleanupClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.content.Context;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceInternalEnumerateClient.java
index 4166dff85332..9a0974b472cb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceInternalEnumerateClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.content.Context;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceRemovalClient.java
index 31ae3a387f90..acae89928460 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceRemovalClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.content.Context;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
index f4324bedb4c6..8df9b9f305de 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.content.Context;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceRevokeChallengeClient.java
index a10c573f34fc..e5edfafcef61 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceRevokeChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceRevokeChallengeClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.content.Context;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
index 94abb7f378df..0e2072823684 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.content.Context;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
index 05b176d28e28..22275e5f9d32 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.biometrics.sensors.face;
+package com.android.server.biometrics.sensors.face.hidl;
import android.annotation.NonNull;
import android.content.Context;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index 4b59112b3524..9f9d9cca2158 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -30,11 +30,12 @@ import com.android.server.biometrics.sensors.LockoutTracker;
*/
public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub {
private final IFingerprintService mFingerprintService;
+ private final int mSensorId;
- public FingerprintAuthenticator(IFingerprintService fingerprintService, SensorConfig config)
+ public FingerprintAuthenticator(IFingerprintService fingerprintService, int sensorId)
throws RemoteException {
mFingerprintService = fingerprintService;
- mFingerprintService.initializeConfiguration(config.id, config.strength);
+ mSensorId = sensorId;
}
@Override
@@ -42,40 +43,40 @@ public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub
long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)
throws RemoteException {
- mFingerprintService.prepareForAuthentication(token, operationId, userId, sensorReceiver,
- opPackageName, cookie, callingUid, callingPid, callingUserId);
+ mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId,
+ sensorReceiver, opPackageName, cookie, callingUid, callingPid, callingUserId);
}
@Override
public void startPreparedClient(int cookie) throws RemoteException {
- mFingerprintService.startPreparedClient(cookie);
+ mFingerprintService.startPreparedClient(mSensorId, cookie);
}
@Override
public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid,
int callingPid, int callingUserId) throws RemoteException {
- mFingerprintService.cancelAuthenticationFromService(token, opPackageName, callingUid,
- callingPid, callingUserId);
+ mFingerprintService.cancelAuthenticationFromService(mSensorId, token, opPackageName,
+ callingUid, callingPid, callingUserId);
}
@Override
public boolean isHardwareDetected(String opPackageName) throws RemoteException {
- return mFingerprintService.isHardwareDetected(opPackageName);
+ return mFingerprintService.isHardwareDetected(mSensorId, opPackageName);
}
@Override
public boolean hasEnrolledTemplates(int userId, String opPackageName) throws RemoteException {
- return mFingerprintService.hasEnrolledFingerprints(userId, opPackageName);
+ return mFingerprintService.hasEnrolledFingerprints(mSensorId, userId, opPackageName);
}
@Override
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId)
throws RemoteException {
- return mFingerprintService.getLockoutModeForUser(userId);
+ return mFingerprintService.getLockoutModeForUser(mSensorId, userId);
}
@Override
public long getAuthenticatorId(int callingUserId) throws RemoteException {
- return mFingerprintService.getAuthenticatorId(callingUserId);
+ return mFingerprintService.getAuthenticatorId(mSensorId, callingUserId);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 265ba0545395..b84d0958e426 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -24,14 +24,17 @@ import static android.Manifest.permission.TEST_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.USE_FINGERPRINT;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
+import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.fingerprint.IFingerprint;
@@ -65,6 +68,7 @@ import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
+import com.android.server.biometrics.sensors.BiometricServiceCallback;
import com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintProvider;
import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21;
import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21UdfpsMock;
@@ -80,7 +84,7 @@ import java.util.List;
* The service is responsible for maintaining a list of clients and dispatching all
* fingerprint-related events.
*/
-public class FingerprintService extends SystemService {
+public class FingerprintService extends SystemService implements BiometricServiceCallback {
protected static final String TAG = "FingerprintService";
@@ -88,6 +92,7 @@ public class FingerprintService extends SystemService {
private final LockoutResetDispatcher mLockoutResetDispatcher;
private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
private final LockPatternUtils mLockPatternUtils;
+ private final FingerprintServiceWrapper mServiceWrapper;
@NonNull private List<ServiceProvider> mServiceProviders;
/**
@@ -255,34 +260,34 @@ public class FingerprintService extends SystemService {
}
@Override // Binder call
- public void prepareForAuthentication(IBinder token, long operationId, int userId,
- IBiometricSensorReceiver sensorReceiver, String opPackageName,
+ public void prepareForAuthentication(int sensorId, IBinder token, long operationId,
+ int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
int cookie, int callingUid, int callingPid, int callingUserId) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for prepareForAuthentication");
return;
}
final boolean restricted = true; // BiometricPrompt is always restricted
- provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, cookie,
+ provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, false /* isKeyguard */);
}
@Override // Binder call
- public void startPreparedClient(int cookie) {
+ public void startPreparedClient(int sensorId, int cookie) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for startPreparedClient");
return;
}
- provider.second.startPreparedClient(provider.first, cookie);
+ provider.startPreparedClient(sensorId, cookie);
}
@@ -328,17 +333,17 @@ public class FingerprintService extends SystemService {
}
@Override // Binder call
- public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
- int callingUid, int callingPid, int callingUserId) {
+ public void cancelAuthenticationFromService(final int sensorId, final IBinder token,
+ final String opPackageName, int callingUid, int callingPid, int callingUserId) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for cancelAuthenticationFromService");
return;
}
- provider.second.cancelAuthentication(provider.first, token);
+ provider.cancelAuthentication(sensorId, token);
}
@Override // Binder call
@@ -402,7 +407,7 @@ public class FingerprintService extends SystemService {
}
@Override // Binder call
- public boolean isHardwareDetected(String opPackageName) {
+ public boolean isHardwareDetectedDeprecated(String opPackageName) {
if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
Binder.getCallingUid(), Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
@@ -413,7 +418,8 @@ public class FingerprintService extends SystemService {
try {
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
- Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
+ Slog.w(TAG, "Null provider for isHardwareDetectedDeprecated, caller: "
+ + opPackageName);
return false;
}
return provider.second.isHardwareDetected(provider.first);
@@ -423,6 +429,19 @@ public class FingerprintService extends SystemService {
}
@Override // Binder call
+ public boolean isHardwareDetected(int sensorId, String opPackageName) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
+ return false;
+ }
+
+ return provider.isHardwareDetected(sensorId);
+ }
+
+ @Override // Binder call
public void rename(final int fingerId, final int userId, final String name) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
if (!Utils.isCurrentUserOrProfile(getContext(), userId)) {
@@ -450,11 +469,11 @@ public class FingerprintService extends SystemService {
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
- return FingerprintService.this.getEnrolledFingerprints(userId, opPackageName);
+ return FingerprintService.this.getEnrolledFingerprintsDeprecated(userId, opPackageName);
}
@Override // Binder call
- public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
+ public boolean hasEnrolledFingerprintsDeprecated(int userId, String opPackageName) {
if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
Binder.getCallingUid(), Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
@@ -464,7 +483,7 @@ public class FingerprintService extends SystemService {
if (userId != UserHandle.getCallingUserId()) {
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
- return !FingerprintService.this.getEnrolledFingerprints(userId, opPackageName)
+ return !FingerprintService.this.getEnrolledFingerprintsDeprecated(userId, opPackageName)
.isEmpty();
}
@@ -489,28 +508,40 @@ public class FingerprintService extends SystemService {
return false;
}
+ public boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for hasEnrolledFingerprints, caller: " + opPackageName);
+ return false;
+ }
+
+ return provider.getEnrolledFingerprints(sensorId, userId).size() > 0;
+ }
+
@Override // Binder call
- public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) {
+ public @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getLockoutModeForUser");
return LockoutTracker.LOCKOUT_NONE;
}
- return provider.second.getLockoutModeForUser(provider.first, userId);
+ return provider.getLockoutModeForUser(sensorId, userId);
}
@Override // Binder call
- public long getAuthenticatorId(int userId) {
+ public long getAuthenticatorId(int sensorId, int userId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ final ServiceProvider provider = getProviderForSensor(sensorId);
if (provider == null) {
Slog.w(TAG, "Null provider for getAuthenticatorId");
return 0;
}
- return provider.second.getAuthenticatorId(provider.first, userId);
+ return provider.getAuthenticatorId(sensorId, userId);
}
@Override // Binder call
@@ -546,7 +577,8 @@ public class FingerprintService extends SystemService {
}
@Override // Binder call
- public void initializeConfiguration(int sensorId, int strength) {
+ public void initializeConfiguration(int sensorId,
+ @BiometricManager.Authenticators.Types int strength) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final Fingerprint21 fingerprint21;
@@ -600,16 +632,19 @@ public class FingerprintService extends SystemService {
public FingerprintService(Context context) {
super(context);
+ mServiceWrapper = new FingerprintServiceWrapper();
mAppOps = context.getSystemService(AppOpsManager.class);
mGestureAvailabilityDispatcher = new GestureAvailabilityDispatcher();
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
mServiceProviders = new ArrayList<>();
-
- initializeAidlHals();
}
- private void initializeAidlHals() {
+ @Override
+ public void onBiometricServiceReady() {
+ final IBiometricService biometricService = IBiometricService.Stub.asInterface(
+ ServiceManager.getService(Context.BIOMETRIC_SERVICE));
+
final String[] instances = ServiceManager.getDeclaredInstances(IFingerprint.DESCRIPTOR);
if (instances == null || instances.length == 0) {
return;
@@ -633,6 +668,23 @@ public class FingerprintService extends SystemService {
new FingerprintProvider(getContext(), props, instance,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
mServiceProviders.add(provider);
+
+ // Register each sensor individually with BiometricService
+ for (SensorProps prop : props) {
+ final int sensorId = prop.commonProps.sensorId;
+ @BiometricManager.Authenticators.Types int strength =
+ Utils.propertyStrengthToAuthenticatorStrength(
+ prop.commonProps.sensorStrength);
+ final FingerprintAuthenticator authenticator =
+ new FingerprintAuthenticator(mServiceWrapper, sensorId);
+ try {
+ biometricService.registerAuthenticator(sensorId,
+ TYPE_FINGERPRINT, strength, authenticator);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when registering sensorId: "
+ + sensorId);
+ }
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when initializing instance: " + fqName);
}
@@ -642,7 +694,7 @@ public class FingerprintService extends SystemService {
@Override
public void onStart() {
- publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
+ publishBinderService(Context.FINGERPRINT_SERVICE, mServiceWrapper);
}
@Nullable
@@ -691,10 +743,11 @@ public class FingerprintService extends SystemService {
}
@NonNull
- private List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
+ private List<Fingerprint> getEnrolledFingerprintsDeprecated(int userId, String opPackageName) {
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
- Slog.w(TAG, "Null provider for getEnrolledFingerprints, caller: " + opPackageName);
+ Slog.w(TAG, "Null provider for getEnrolledFingerprintsDeprecated, caller: "
+ + opPackageName);
return Collections.emptyList();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 8acf4f5204a9..ce0c43937af1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -32,6 +32,7 @@ import android.util.Slog;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutConsumer;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.fingerprint.Udfps;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
index 17181264c620..1f1d19d07121 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
@@ -27,6 +27,7 @@ import android.util.Slog;
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.sensors.ClientMonitor;
+import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index 51c30b68e0c5..2e78912703f2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -49,6 +49,7 @@ import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.EnumerateConsumer;
import com.android.server.biometrics.sensors.Interruptable;
+import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutConsumer;
import com.android.server.biometrics.sensors.RemovalConsumer;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
index 0400ef522142..b756d8e87fd6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
@@ -31,10 +31,8 @@ import com.android.server.biometrics.sensors.LockoutTracker;
public final class IrisAuthenticator extends IBiometricAuthenticator.Stub {
private final IIrisService mIrisService;
- public IrisAuthenticator(IIrisService irisService, SensorConfig config) throws
- RemoteException {
+ public IrisAuthenticator(IIrisService irisService, int sensorId) throws RemoteException {
mIrisService = irisService;
- mIrisService.initializeConfiguration(config.id);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java
index bcf63dcdd67f..08b24897581f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java
@@ -42,7 +42,7 @@ public class IrisService extends SystemService {
*/
private final class IrisServiceWrapper extends IIrisService.Stub {
@Override // Binder call
- public void initializeConfiguration(int sensorId) {
+ public void initializeConfiguration(int sensorId, int strength) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
}
}
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index d5488712aa34..17828a0549b3 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -95,7 +95,11 @@ public class MultipathPolicyTracker {
private static final boolean DBG = false;
+ // This context is for the current user.
private final Context mContext;
+ // This context is for all users, so register a BroadcastReceiver which can receive intents from
+ // all users.
+ private final Context mUserAllContext;
private final Handler mHandler;
private final Clock mClock;
private final Dependencies mDeps;
@@ -132,6 +136,7 @@ public class MultipathPolicyTracker {
public MultipathPolicyTracker(Context ctx, Handler handler, Dependencies deps) {
mContext = ctx;
+ mUserAllContext = ctx.createContextAsUser(UserHandle.ALL, 0 /* flags */);
mHandler = handler;
mClock = deps.getClock();
mDeps = deps;
@@ -155,8 +160,8 @@ public class MultipathPolicyTracker {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- mContext.registerReceiverAsUser(
- mConfigChangeReceiver, UserHandle.ALL, intentFilter, null, mHandler);
+ mUserAllContext.registerReceiver(
+ mConfigChangeReceiver, intentFilter, null /* broadcastPermission */, mHandler);
}
public void shutdown() {
@@ -167,7 +172,7 @@ public class MultipathPolicyTracker {
}
mMultipathTrackers.clear();
mResolver.unregisterContentObserver(mSettingsObserver);
- mContext.unregisterReceiver(mConfigChangeReceiver);
+ mUserAllContext.unregisterReceiver(mConfigChangeReceiver);
}
// Called on an arbitrary binder thread.
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 338539312278..0563fcd1bf50 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -43,7 +43,6 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.notification.SystemNotificationChannels;
public class NetworkNotificationManager {
@@ -74,7 +73,12 @@ public class NetworkNotificationManager {
private static final String TAG = NetworkNotificationManager.class.getSimpleName();
private static final boolean DBG = true;
- private static final boolean VDBG = false;
+
+ // Notification channels used by ConnectivityService mainline module, it should be aligned with
+ // SystemNotificationChannels.
+ public static final String NOTIFICATION_NETWORK_STATUS = "NETWORK_STATUS";
+ public static final String NOTIFICATION_NETWORK_ALERTS = "NETWORK_ALERTS";
+ public static final String NOTIFICATION_VPN = "VPN";
// The context is for the current user (system server)
private final Context mContext;
@@ -259,8 +263,7 @@ public class NetworkNotificationManager {
// the tag.
final boolean hasPreviousNotification = previousNotifyType != null;
final String channelId = (highPriority && !hasPreviousNotification)
- ? SystemNotificationChannels.NETWORK_ALERTS
- : SystemNotificationChannels.NETWORK_STATUS;
+ ? NOTIFICATION_NETWORK_ALERTS : NOTIFICATION_NETWORK_STATUS;
Notification.Builder builder = new Notification.Builder(mContext, channelId)
.setWhen(System.currentTimeMillis())
.setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 4d3998956858..ba7ba7895d2a 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -25,13 +25,14 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.server.connectivity.NetworkNotificationManager.NOTIFICATION_VPN;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -110,7 +111,6 @@ import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
-import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.server.ConnectivityService;
import com.android.server.DeviceIdleInternal;
@@ -865,7 +865,7 @@ public class Vpn {
Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
serviceIntent.setPackage(alwaysOnPackage);
try {
- return mContext.startServiceAsUser(serviceIntent, UserHandle.of(mUserId)) != null;
+ return mUserIdContext.startService(serviceIntent) != null;
} catch (RuntimeException e) {
Log.e(TAG, "VpnService " + serviceIntent + " failed to start", e);
return false;
@@ -1036,20 +1036,21 @@ public class Vpn {
final long token = Binder.clearCallingIdentity();
try {
- final int[] toChange;
+ final String[] toChange;
// Clear all AppOps if the app is being unauthorized.
switch (vpnType) {
case VpnManager.TYPE_VPN_NONE:
- toChange = new int[] {
- AppOpsManager.OP_ACTIVATE_VPN, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN
+ toChange = new String[] {
+ AppOpsManager.OPSTR_ACTIVATE_VPN,
+ AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN
};
break;
case VpnManager.TYPE_VPN_PLATFORM:
- toChange = new int[] {AppOpsManager.OP_ACTIVATE_PLATFORM_VPN};
+ toChange = new String[] {AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN};
break;
case VpnManager.TYPE_VPN_SERVICE:
- toChange = new int[] {AppOpsManager.OP_ACTIVATE_VPN};
+ toChange = new String[] {AppOpsManager.OPSTR_ACTIVATE_VPN};
break;
default:
Log.wtf(TAG, "Unrecognized VPN type while granting authorization");
@@ -1058,9 +1059,9 @@ public class Vpn {
final AppOpsManager appOpMgr =
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
- for (final int appOp : toChange) {
+ for (final String appOpStr : toChange) {
appOpMgr.setMode(
- appOp,
+ appOpStr,
uid,
packageName,
vpnType == VpnManager.TYPE_VPN_NONE
@@ -1086,21 +1087,22 @@ public class Vpn {
}
}
- private static boolean doesPackageHaveAppop(Context context, String packageName, int appop) {
+ private static boolean doesPackageHaveAppop(Context context, String packageName,
+ String appOpStr) {
final AppOpsManager appOps =
(AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
// Verify that the caller matches the given package and has the required permission.
- return appOps.noteOpNoThrow(appop, Binder.getCallingUid(), packageName)
- == AppOpsManager.MODE_ALLOWED;
+ return appOps.noteOpNoThrow(appOpStr, Binder.getCallingUid(), packageName,
+ null /* attributionTag */, null /* message */) == AppOpsManager.MODE_ALLOWED;
}
private static boolean isVpnServicePreConsented(Context context, String packageName) {
- return doesPackageHaveAppop(context, packageName, AppOpsManager.OP_ACTIVATE_VPN);
+ return doesPackageHaveAppop(context, packageName, AppOpsManager.OPSTR_ACTIVATE_VPN);
}
private static boolean isVpnProfilePreConsented(Context context, String packageName) {
- return doesPackageHaveAppop(context, packageName, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN)
+ return doesPackageHaveAppop(context, packageName, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN)
|| isVpnServicePreConsented(context, packageName);
}
@@ -1330,16 +1332,17 @@ public class Vpn {
// Restricted users are not allowed to create VPNs, they are tied to Owner
enforceNotRestrictedUser();
- ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent,
- null, 0, mUserId);
+ final PackageManager packageManager = mUserIdContext.getPackageManager();
+ if (packageManager == null) {
+ throw new UnsupportedOperationException("Cannot get PackageManager.");
+ }
+ final ResolveInfo info = packageManager.resolveService(intent, 0 /* flags */);
if (info == null) {
throw new SecurityException("Cannot find " + config.user);
}
if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) {
throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE);
}
- } catch (RemoteException e) {
- throw new SecurityException("Cannot find " + config.user);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1942,7 +1945,7 @@ public class Vpn {
final PendingIntent configIntent = mSystemServices.pendingIntentGetActivityAsUser(
intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, user);
final Notification.Builder builder =
- new Notification.Builder(mContext, SystemNotificationChannels.VPN)
+ new Notification.Builder(mContext, NOTIFICATION_VPN)
.setSmallIcon(R.drawable.vpn_connected)
.setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
.setContentText(mContext.getString(R.string.vpn_lockdown_config))
@@ -2757,6 +2760,8 @@ public class Vpn {
LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd, VpnProfile profile) {
super(TAG);
+ checkArgument(racoon != null || mtpd != null, "Arguments to racoon and mtpd "
+ + "must not both be null");
mConfig = config;
mDaemons = new String[] {"racoon", "mtpd"};
// TODO: clear arguments from memory once launched
@@ -2913,15 +2918,6 @@ public class Vpn {
}
new File("/data/misc/vpn/abort").delete();
- // Check if we need to restart any of the daemons.
- boolean restart = false;
- for (String[] arguments : mArguments) {
- restart = restart || (arguments != null);
- }
- if (!restart) {
- agentDisconnect();
- return;
- }
updateState(DetailedState.CONNECTING, "execute");
// Start the daemon with arguments.
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 626303001ba0..fa03e59f2f2e 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -60,12 +60,12 @@ import android.net.ipsec.ike.IkeTrafficSelector;
import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.net.util.IpRange;
import android.system.OsConstants;
import android.util.Log;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.HexDump;
+import com.android.net.module.util.IpRange;
import java.net.Inet4Address;
import java.net.Inet6Address;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 6a4ca8da00d1..0b2d4d70ae1e 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -151,6 +151,8 @@ import java.util.function.Predicate;
* run at a later time. Similarly, when a sync succeeds, backoff is cleared and all associated syncs
* are rescheduled. A rescheduled sync will get a new jobId.
*
+ * See also {@code SyncManager.md} in the same directory for how app-standby affects sync adapters.
+ *
* @hide
*/
public class SyncManager {
diff --git a/services/core/java/com/android/server/content/SyncManager.md b/services/core/java/com/android/server/content/SyncManager.md
new file mode 100644
index 000000000000..8507abdcc40e
--- /dev/null
+++ b/services/core/java/com/android/server/content/SyncManager.md
@@ -0,0 +1,122 @@
+# Sync Manager notes
+
+## App-standby and Sync Manager
+
+Android 9 Pie introduced
+["App Standby Buckets"](https://developer.android.com/topic/performance/appstandby), which throttles various things
+including
+[JobScheduler](https://developer.android.com/reference/android/app/job/JobScheduler)
+and [AlarmManager](https://developer.android.com/reference/android/app/AlarmManager),
+[among other things](https://developer.android.com/topic/performance/power/power-details),
+for background applications.
+
+Because SyncManager executes sync operations as JobScheduler jobs, sync operations are subject
+to the same throttling.
+
+However, unlike JobScheduler jobs, any apps (with the proper permission) can schedule a sync
+operation in any other apps using
+[ContentResolver.requestSync()](https://developer.android.com/reference/android/content/ContentResolver#requestSync(android.content.SyncRequest)),
+whch means it's possible for a foreground app to request a sync in another app that is either in the
+background or is not even running.
+For example, when the user hits the refresh button on the Contacts app, it'll
+request sync to all the contacts sync adapters, which are implemented in other packages (and they're
+likely not in the foreground).
+
+Because of this, calls to
+[ContentResolver.requestSync()](https://developer.android.com/reference/android/content/ContentResolver#requestSync(android.content.SyncRequest))
+made by foreground apps are special cased such that the resulting sync operations will be
+exempted from app-standby throttling.
+
+### Two Levels of Exemption
+Specifically, there are two different levels of exemption, depending on the state of the caller:
+1. `ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET`
+2. `ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP`, which is more powerful than 1.
+
+The exemption level is calculated in
+[ContentService.getSyncExemptionAndCleanUpExtrasForCaller()](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/content/ContentService.java?q=%22int%20getSyncExemptionAndCleanUpExtrasForCaller%22&ss=android%2Fplatform%2Fsuperproject),
+which was [implemented slightly differently](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/content/ContentService.java?q=%22int%20getSyncExemptionAndCleanUpExtrasForCaller%22&ss=android%2Fplatform%2Fsuperproject)
+in Android 9, compared to Android 10 and later.
+
+The logic is as follows:
+- When the caller's procstate is `PROCESS_STATE_TOP` or above,
+ meaning if the caller has a foreground activity,
+ `SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP` will be set.
+
+- Otherwise, when the caller's procstate is `PROCESS_STATE_IMPORTANT_FOREGROUND` or above,
+ e.g. when the caller has a foreground service, a service bound by the system of a specific kind,
+ `SYNC_EXEMPTION_PROMOTE_BUCKET` will be set.
+
+- Additionally, on Android 10 and later, when the caller is
+ "UID-active" (but the procstate is below `PROCESS_STATE_TOP`),
+ `SYNC_EXEMPTION_PROMOTE_BUCKET` will be set.
+ This is what happens when the app has just received a high-priority FCM, for example.
+ Temp-allowlist is also used in various other situations.
+
+### Behavior of Each Exemption
+
+The exemptions are tracked in `SyncOperation.syncExemptionFlag`.
+
+- Behavior of `SYNC_EXEMPTION_PROMOTE_BUCKET`
+ - This will add `JobInfo.FLAG_EXEMPT_FROM_APP_STANDBY` to the sync job. This makes the job
+ subject to "ACTIVE" app quota, so minimum deferral will be applied to it.
+
+ - This also reports `AppStandbyController.reportExemptedSyncStart()`, so the package that owns
+ the sync adapter is temporarily put in the "ACTIVE" bucket for the
+ duration of `mExemptedSyncStartTimeoutMillis`, whose default is 10 minutes as of 2020-10-23.
+
+ This will allow the app to access network, even if it has been in the `RARE` bucket
+ (in which case, the system cuts its network access).
+
+ Note if the device is dozing or in battery saver, promoting to the "ACTIVE" bucket will still
+ _not_ give the app network access.
+
+- Behavior of `SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP`
+ - This gives all the perks given by `SYNC_EXEMPTION_PROMOTE_BUCKET`, plus puts the target app
+ in the temp-allowlist (by calling `DeviceIdleInternal.addPowerSaveTempWhitelistApp()`)
+ for the duration of `SyncManagerConstants.getKeyExemptionTempWhitelistDurationInSeconds()`,
+ whose default is 10 minutes.
+
+ Temp-allowlist will grant the app network access even if the device is in doze or in battery
+ saver.
+
+ (However, note that when the device is dozing, sync jobs will not run anyway.)
+
+### How Retries Are Handled
+
+- When a sync operation needs a retry, SyncManager creates a new operation (job) with a back-off
+ (in `SyncManager.maybeRescheduleSync()`). In this case, the new sync operation will inherit
+ `SyncOperation.syncExemptionFlag`, unless the number of retries (not counting the original sync
+ job) is equal to or greater than `SyncManagerConstants.getMaxRetriesWithAppStandbyExemption()`,
+ whose default is 5.
+
+### Special-handling of Pre-installed Packages
+
+- When a content provider is accessed, `AppStandbyController.reportContentProviderUsage()` is
+ triggered, which elevates the standby bucket of the associated sync adapters' packages to `ACTIVE`
+ for the duration of `mSyncAdapterTimeoutMillis`, whose default is 10 minutes, but _only for_
+ pre-installed packages. This is to help pre-installed sync adapters, which often don't have UI,
+ sync properly.
+
+- Also, since Android 11, all the pre-installed apps with no activities will be kept in
+ the `ACTIVE` bucket, which greatly relaxes app-standby throttling. But they're still subject
+ to doze and battery saver.
+
+### Summary
+
+- When the device is dozing, no sync operations will be executed.
+
+- Normally, sync operations are subject to App-Standby, which throttles jobs owned by background
+ apps. Jobs owned by foreground apps are not affected.
+
+- A sync operation requested by a foreground activity will be executed immediately even if the
+ app owning the sync adapter is in RARE bucket, and the device is in battery saver.
+
+- A sync operation requested by a foreground service (or a "bound foreground" service)
+ will be executed immediately even if the app owning the sync adapter is in RARE bucket,
+ *unless* the device is in battery saver.
+
+ Since Android 9 and later, the same thing will happen if the requester is temp-allowlisted (e.g.
+ when it has just received a "high-priority FCM").
+
+- There are certain exemptions for pre-installed apps, but doze and battery saver will still
+ block their sync adapters. \ No newline at end of file
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index fe6e60f6159c..3172a04e9a3d 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -16,18 +16,22 @@
package com.android.server.devicestate;
-import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import static android.Manifest.permission.CONTROL_DEVICE_STATE;
+import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.devicestate.IDeviceStateManager;
+import android.hardware.devicestate.IDeviceStateManagerCallback;
import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.util.IntArray;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -37,6 +41,7 @@ import com.android.server.policy.DeviceStatePolicyImpl;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
/**
@@ -66,6 +71,8 @@ public final class DeviceStateManagerService extends SystemService {
private final Object mLock = new Object();
@NonNull
private final DeviceStatePolicy mDeviceStatePolicy;
+ @NonNull
+ private final BinderService mBinderService;
@GuardedBy("mLock")
private IntArray mSupportedDeviceStates;
@@ -88,6 +95,10 @@ public final class DeviceStateManagerService extends SystemService {
@GuardedBy("mLock")
private int mRequestedOverrideState = INVALID_DEVICE_STATE;
+ // List of registered callbacks indexed by process id.
+ @GuardedBy("mLock")
+ private final SparseArray<CallbackRecord> mCallbacks = new SparseArray<>();
+
public DeviceStateManagerService(@NonNull Context context) {
this(context, new DeviceStatePolicyImpl());
}
@@ -96,12 +107,13 @@ public final class DeviceStateManagerService extends SystemService {
DeviceStateManagerService(@NonNull Context context, @NonNull DeviceStatePolicy policy) {
super(context);
mDeviceStatePolicy = policy;
+ mDeviceStatePolicy.getDeviceStateProvider().setListener(new DeviceStateProviderListener());
+ mBinderService = new BinderService();
}
@Override
public void onStart() {
- mDeviceStatePolicy.getDeviceStateProvider().setListener(new DeviceStateProviderListener());
- publishBinderService(Context.DEVICE_STATE_SERVICE, new BinderService());
+ publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService);
}
/**
@@ -186,6 +198,11 @@ public final class DeviceStateManagerService extends SystemService {
}
}
+ @VisibleForTesting
+ IDeviceStateManager getBinderService() {
+ return mBinderService;
+ }
+
private void updateSupportedStates(int[] supportedDeviceStates) {
// Must ensure sorted as isSupportedStateLocked() impl uses binary search.
Arrays.sort(supportedDeviceStates, 0, supportedDeviceStates.length);
@@ -310,18 +327,81 @@ public final class DeviceStateManagerService extends SystemService {
* </p>
*/
private void commitPendingState() {
+ // Update the current state.
+ int newState;
synchronized (mLock) {
if (DEBUG) {
Slog.d(TAG, "Committing state: " + mPendingState);
}
mCommittedState = mPendingState;
+ newState = mCommittedState;
mPendingState = INVALID_DEVICE_STATE;
updatePendingStateLocked();
}
+ // Notify callbacks of a change.
+ notifyDeviceStateChanged(newState);
+
+ // Try to configure the next state if needed.
notifyPolicyIfNeeded();
}
+ private void notifyDeviceStateChanged(int deviceState) {
+ if (Thread.holdsLock(mLock)) {
+ throw new IllegalStateException(
+ "Attempting to notify callbacks with service lock held.");
+ }
+
+ // Grab the lock and copy the callbacks.
+ ArrayList<CallbackRecord> callbacks;
+ synchronized (mLock) {
+ if (mCallbacks.size() == 0) {
+ return;
+ }
+
+ callbacks = new ArrayList<>();
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ callbacks.add(mCallbacks.valueAt(i));
+ }
+ }
+
+ // After releasing the lock, send the notifications out.
+ for (int i = 0; i < callbacks.size(); i++) {
+ callbacks.get(i).notifyDeviceStateAsync(deviceState);
+ }
+ }
+
+ private void registerCallbackInternal(IDeviceStateManagerCallback callback, int callingPid) {
+ int currentState;
+ CallbackRecord record;
+ // Grab the lock to register the callback and get the current state.
+ synchronized (mLock) {
+ if (mCallbacks.contains(callingPid)) {
+ throw new SecurityException("The calling process has already registered an"
+ + " IDeviceStateManagerCallback.");
+ }
+
+ record = new CallbackRecord(callback, callingPid);
+ try {
+ callback.asBinder().linkToDeath(record, 0);
+ } catch (RemoteException ex) {
+ throw new RuntimeException(ex);
+ }
+
+ mCallbacks.put(callingPid, record);
+ currentState = mCommittedState;
+ }
+
+ // Notify the callback of the state at registration.
+ record.notifyDeviceStateAsync(currentState);
+ }
+
+ private void unregisterCallbackInternal(CallbackRecord record) {
+ synchronized (mLock) {
+ mCallbacks.remove(record.mPid);
+ }
+ }
+
private void dumpInternal(PrintWriter pw) {
pw.println("DEVICE STATE MANAGER (dumpsys device_state)");
@@ -330,6 +410,14 @@ public final class DeviceStateManagerService extends SystemService {
pw.println(" mPendingState=" + toString(mPendingState));
pw.println(" mRequestedState=" + toString(mRequestedState));
pw.println(" mRequestedOverrideState=" + toString(mRequestedOverrideState));
+
+ final int callbackCount = mCallbacks.size();
+ pw.println();
+ pw.println("Callbacks: size=" + callbackCount);
+ for (int i = 0; i < callbackCount; i++) {
+ CallbackRecord callback = mCallbacks.valueAt(i);
+ pw.println(" " + i + ": mPid=" + callback.mPid);
+ }
}
}
@@ -360,9 +448,48 @@ public final class DeviceStateManagerService extends SystemService {
}
}
+ private final class CallbackRecord implements IBinder.DeathRecipient {
+ private final IDeviceStateManagerCallback mCallback;
+ private final int mPid;
+
+ CallbackRecord(IDeviceStateManagerCallback callback, int pid) {
+ mCallback = callback;
+ mPid = pid;
+ }
+
+ @Override
+ public void binderDied() {
+ unregisterCallbackInternal(this);
+ }
+
+ public void notifyDeviceStateAsync(int devicestate) {
+ try {
+ mCallback.onDeviceStateChanged(devicestate);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify process " + mPid + " that device state changed.",
+ ex);
+ }
+ }
+ }
+
/** Implementation of {@link IDeviceStateManager} published as a binder service. */
private final class BinderService extends IDeviceStateManager.Stub {
@Override // Binder call
+ public void registerCallback(IDeviceStateManagerCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("Device state callback must not be null.");
+ }
+
+ final int callingPid = Binder.getCallingPid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ registerCallbackInternal(callback, callingPid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver result) {
new DeviceStateManagerShellCommand(DeviceStateManagerService.this)
diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java
index 838dc84d4a0a..1fc151221b46 100644
--- a/services/core/java/com/android/server/display/DisplayAdapter.java
+++ b/services/core/java/com/android/server/display/DisplayAdapter.java
@@ -120,8 +120,13 @@ abstract class DisplayAdapter {
}
public static Display.Mode createMode(int width, int height, float refreshRate) {
- return new Display.Mode(
- NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate);
+ return createMode(width, height, refreshRate, new float[0]);
+ }
+
+ public static Display.Mode createMode(int width, int height, float refreshRate,
+ float[] alternativeRefreshRates) {
+ return new Display.Mode(NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate,
+ alternativeRefreshRates);
}
public interface Listener {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b10cd12cdba5..004e481354ec 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -89,6 +89,7 @@ import android.util.IntArray;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.util.Spline;
import android.view.Display;
import android.view.DisplayInfo;
@@ -96,6 +97,7 @@ import android.view.IDisplayFoldListener;
import android.view.Surface;
import android.view.SurfaceControl;
+import com.android.internal.BrightnessSynchronizer;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
@@ -112,7 +114,6 @@ import com.android.server.wm.WindowManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.List;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
@@ -235,15 +236,28 @@ public final class DisplayManagerService extends SystemService {
private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() {
@Override
public void requestDisplayState(int displayId, int state, float brightness) {
+ // TODO (b/168210494): Stop applying default display state to all displays.
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ return;
+ }
+ final int[] displayIds;
+ synchronized (mSyncRoot) {
+ displayIds = mLogicalDisplayMapper.getDisplayIdsLocked();
+ }
+
// The order of operations is important for legacy reasons.
if (state == Display.STATE_OFF) {
- requestGlobalDisplayStateInternal(state, brightness);
+ for (int id : displayIds) {
+ requestDisplayStateInternal(id, state, brightness);
+ }
}
mDisplayPowerCallbacks.onDisplayStateChange(state);
if (state != Display.STATE_OFF) {
- requestGlobalDisplayStateInternal(state, brightness);
+ for (int id : displayIds) {
+ requestDisplayStateInternal(id, state, brightness);
+ }
}
}
};
@@ -257,13 +271,16 @@ public final class DisplayManagerService extends SystemService {
/** The {@link Handler} used by all {@link DisplayPowerController}s. */
private Handler mPowerHandler;
- // The overall display state, independent of changes that might influence one
- // display or another in particular.
- private int mGlobalDisplayState = Display.STATE_ON;
+ // A map from LogicalDisplay ID to display power state.
+ @GuardedBy("mSyncRoot")
+ private final SparseIntArray mDisplayStates = new SparseIntArray();
+
+ // A map from LogicalDisplay ID to display brightness.
+ @GuardedBy("mSyncRoot")
+ private final SparseArray<Float> mDisplayBrightnesses = new SparseArray<>();
- // The overall display brightness.
- // For now, this only applies to the default display but we may split it up eventually.
- private float mGlobalDisplayBrightness;
+ // The default brightness.
+ private final float mDisplayDefaultBrightness;
// Set to true when there are pending display changes that have yet to be applied
// to the surface flinger state.
@@ -317,11 +334,6 @@ public final class DisplayManagerService extends SystemService {
// DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY flag set.
private final int mDefaultDisplayDefaultColorMode;
- // Temporary list of deferred work to perform when setting the display state.
- // Only used by requestDisplayState. The field is self-synchronized and only
- // intended for use inside of the requestGlobalDisplayStateInternal function.
- private final ArrayList<Runnable> mTempDisplayStateWorkQueue = new ArrayList<Runnable>();
-
// Lists of UIDs that are present on the displays. Maps displayId -> array of UIDs.
private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>();
@@ -372,7 +384,7 @@ public final class DisplayManagerService extends SystemService {
mMinimumBrightnessSpline = Spline.createSpline(lux, nits);
PowerManager pm = mContext.getSystemService(PowerManager.class);
- mGlobalDisplayBrightness = pm.getBrightnessConstraint(
+ mDisplayDefaultBrightness = pm.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT);
mCurrentUserId = UserHandle.USER_SYSTEM;
ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
@@ -589,7 +601,7 @@ public final class DisplayManagerService extends SystemService {
}
}
- private void requestGlobalDisplayStateInternal(int state, float brightnessState) {
+ private void requestDisplayStateInternal(int displayId, int state, float brightnessState) {
if (state == Display.STATE_UNKNOWN) {
state = Display.STATE_ON;
}
@@ -602,38 +614,40 @@ public final class DisplayManagerService extends SystemService {
brightnessState = PowerManager.BRIGHTNESS_MAX;
}
- synchronized (mTempDisplayStateWorkQueue) {
- try {
- // Update the display state within the lock.
- // Note that we do not need to schedule traversals here although it
- // may happen as a side-effect of displays changing state.
- synchronized (mSyncRoot) {
- if (mGlobalDisplayState == state
- && mGlobalDisplayBrightness == brightnessState) {
- return; // no change
- }
+ // Update the display state within the lock.
+ // Note that we do not need to schedule traversals here although it
+ // may happen as a side-effect of displays changing state.
+ final Runnable runnable;
+ final String traceMessage;
+ synchronized (mSyncRoot) {
+ final int index = mDisplayStates.indexOfKey(displayId);
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestGlobalDisplayState("
- + Display.stateToString(state)
- + ", brightness=" + brightnessState + ")");
+ if (index < 0 || (mDisplayStates.valueAt(index) == state
+ && BrightnessSynchronizer.floatEquals(mDisplayBrightnesses.valueAt(index),
+ brightnessState))) {
+ return; // Display no longer exists or no change.
+ }
- mGlobalDisplayState = state;
- mGlobalDisplayBrightness = brightnessState;
- applyGlobalDisplayStateLocked(mTempDisplayStateWorkQueue);
- }
+ traceMessage = "requestDisplayStateInternal("
+ + displayId + ", "
+ + Display.stateToString(state)
+ + ", brightness=" + brightnessState + ")";
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, traceMessage, displayId);
- // Setting the display power state can take hundreds of milliseconds
- // to complete so we defer the most expensive part of the work until
- // after we have exited the critical section to avoid blocking other
- // threads for a long time.
- for (int i = 0; i < mTempDisplayStateWorkQueue.size(); i++) {
- mTempDisplayStateWorkQueue.get(i).run();
- }
- Trace.traceEnd(Trace.TRACE_TAG_POWER);
- } finally {
- mTempDisplayStateWorkQueue.clear();
- }
+ mDisplayStates.setValueAt(index, state);
+ mDisplayBrightnesses.setValueAt(index, brightnessState);
+ runnable = updateDisplayStateLocked(
+ mLogicalDisplayMapper.getLocked(displayId).getPrimaryDisplayDeviceLocked());
+ }
+
+ // Setting the display power state can take hundreds of milliseconds
+ // to complete so we defer the most expensive part of the work until
+ // after we have exited the critical section to avoid blocking other
+ // threads for a long time.
+ if (runnable != null) {
+ runnable.run();
}
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, traceMessage, displayId);
}
private class SettingsObserver extends ContentObserver {
@@ -987,6 +1001,8 @@ public final class DisplayManagerService extends SystemService {
recordTopInsetLocked(display);
}
addDisplayPowerControllerLocked(displayId);
+ mDisplayStates.append(displayId, Display.STATE_OFF);
+ mDisplayBrightnesses.append(displayId, mDisplayDefaultBrightness);
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
@@ -1021,6 +1037,8 @@ public final class DisplayManagerService extends SystemService {
private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
final int displayId = display.getDisplayIdLocked();
mDisplayPowerControllers.delete(displayId);
+ mDisplayStates.delete(displayId);
+ mDisplayBrightnesses.delete(displayId);
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
scheduleTraversalLocked(false);
@@ -1035,15 +1053,6 @@ public final class DisplayManagerService extends SystemService {
handleLogicalDisplayChangedLocked(display);
}
- private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) {
- mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> {
- Runnable runnable = updateDisplayStateLocked(device);
- if (runnable != null) {
- workQueue.add(runnable);
- }
- });
- }
-
private Runnable updateDisplayStateLocked(DisplayDevice device) {
// Blank or unblank the display immediately to match the state requested
// by the display power controller (if known).
@@ -1052,12 +1061,16 @@ public final class DisplayManagerService extends SystemService {
// TODO - b/170498827 The rules regarding what display state to apply to each
// display will depend on the configuration/mapping of logical displays.
// Clean up LogicalDisplay.isEnabled() mechanism once this is fixed.
- int state = mGlobalDisplayState;
final LogicalDisplay display = mLogicalDisplayMapper.getLocked(device);
- if (display != null && !display.isEnabled()) {
+ final int state;
+ final int displayId = display.getDisplayIdLocked();
+ if (display.isEnabled()) {
+ state = mDisplayStates.get(displayId);
+ } else {
state = Display.STATE_OFF;
}
- return device.requestDisplayStateLocked(state, mGlobalDisplayBrightness);
+ final float brightness = mDisplayBrightnesses.get(displayId);
+ return device.requestDisplayStateLocked(state, brightness);
}
return null;
}
@@ -1423,17 +1436,18 @@ public final class DisplayManagerService extends SystemService {
private Optional<Integer> getViewportType(DisplayDeviceInfo info) {
// Get the corresponding viewport type.
- if ((info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
- return Optional.of(VIEWPORT_INTERNAL);
- } else if (info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
- return Optional.of(VIEWPORT_EXTERNAL);
- } else if (info.touch == DisplayDeviceInfo.TOUCH_VIRTUAL
- && !TextUtils.isEmpty(info.uniqueId)) {
- return Optional.of(VIEWPORT_VIRTUAL);
- } else {
- if (DEBUG) {
- Slog.i(TAG, "Display " + info + " does not support input device matching.");
- }
+ switch (info.touch) {
+ case DisplayDeviceInfo.TOUCH_INTERNAL:
+ return Optional.of(VIEWPORT_INTERNAL);
+ case DisplayDeviceInfo.TOUCH_EXTERNAL:
+ return Optional.of(VIEWPORT_EXTERNAL);
+ case DisplayDeviceInfo.TOUCH_VIRTUAL:
+ if (!TextUtils.isEmpty(info.uniqueId)) {
+ return Optional.of(VIEWPORT_VIRTUAL);
+ }
+ // fallthrough
+ default:
+ Slog.w(TAG, "Display " + info + " does not support input device matching.");
}
return Optional.empty();
}
@@ -1483,13 +1497,6 @@ public final class DisplayManagerService extends SystemService {
return null;
}
- // Only allow a single INTERNAL or EXTERNAL viewport by forcing their uniqueIds
- // to be identical (in particular, empty).
- // TODO (b/116824030) allow multiple EXTERNAL viewports and remove this function.
- if (viewportType != VIEWPORT_VIRTUAL) {
- uniqueId = "";
- }
-
DisplayViewport viewport;
final int count = mViewports.size();
for (int i = 0; i < count; i++) {
@@ -1593,13 +1600,24 @@ public final class DisplayManagerService extends SystemService {
pw.println(" mOnlyCode=" + mOnlyCore);
pw.println(" mSafeMode=" + mSafeMode);
pw.println(" mPendingTraversal=" + mPendingTraversal);
- pw.println(" mGlobalDisplayState=" + Display.stateToString(mGlobalDisplayState));
pw.println(" mViewports=" + mViewports);
pw.println(" mDefaultDisplayDefaultColorMode=" + mDefaultDisplayDefaultColorMode);
pw.println(" mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
pw.println(" mStableDisplaySize=" + mStableDisplaySize);
pw.println(" mMinimumBrightnessCurve=" + mMinimumBrightnessCurve);
+ pw.println();
+ final int displayStateCount = mDisplayStates.size();
+ pw.println("Display States: size=" + displayStateCount);
+ for (int i = 0; i < displayStateCount; i++) {
+ final int displayId = mDisplayStates.keyAt(i);
+ final int displayState = mDisplayStates.valueAt(i);
+ final float brightness = mDisplayBrightnesses.valueAt(i);
+ pw.println(" Display Id=" + displayId);
+ pw.println(" Display State=" + Display.stateToString(displayState));
+ pw.println(" Display Brightness=" + brightness);
+ }
+
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.increaseIndent();
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index c013145b5269..1aced07e0997 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -931,6 +931,8 @@ public class DisplayModeDirector {
Settings.System.getUriFor(Settings.System.MIN_REFRESH_RATE);
private final Uri mLowPowerModeSetting =
Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE);
+ private final Uri mMatchContentFrameRateSetting =
+ Settings.Secure.getUriFor(Settings.Secure.MATCH_CONTENT_FRAME_RATE);
private final Context mContext;
private float mDefaultPeakRefreshRate;
@@ -953,6 +955,8 @@ public class DisplayModeDirector {
UserHandle.USER_SYSTEM);
cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
UserHandle.USER_SYSTEM);
+ cr.registerContentObserver(mMatchContentFrameRateSetting, false /*notifyDescendants*/,
+ this);
Float deviceConfigDefaultPeakRefresh =
mDeviceConfigDisplaySettings.getDefaultPeakRefreshRate();
@@ -963,6 +967,7 @@ public class DisplayModeDirector {
synchronized (mLock) {
updateRefreshRateSettingLocked();
updateLowPowerModeSettingLocked();
+ updateModeSwitchingTypeSettingLocked();
}
}
@@ -988,6 +993,8 @@ public class DisplayModeDirector {
updateRefreshRateSettingLocked();
} else if (mLowPowerModeSetting.equals(uri)) {
updateLowPowerModeSettingLocked();
+ } else if (mMatchContentFrameRateSetting.equals(uri)) {
+ updateModeSwitchingTypeSettingLocked();
}
}
}
@@ -1050,6 +1057,17 @@ public class DisplayModeDirector {
mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, maxRefreshRate);
}
+ private void updateModeSwitchingTypeSettingLocked() {
+ final ContentResolver cr = mContext.getContentResolver();
+ int switchingType = Settings.Secure.getIntForUser(
+ cr, Settings.Secure.MATCH_CONTENT_FRAME_RATE, mModeSwitchingType /*default*/,
+ cr.getUserId());
+ if (switchingType != mModeSwitchingType) {
+ mModeSwitchingType = switchingType;
+ notifyDesiredDisplayModeSpecsChangedLocked();
+ }
+ }
+
public void dumpLocked(PrintWriter pw) {
pw.println(" SettingsObserver");
pw.println(" mDefaultRefreshRate: " + mDefaultRefreshRate);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 309271c6addc..f48826055028 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -328,8 +328,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private BrightnessReason mBrightnessReasonTemp = new BrightnessReason();
// Brightness animation ramp rates in brightness units per second
- private final float mBrightnessRampRateSlow = 0.2352941f;
- private final float mBrightnessRampRateFast = 0.7058823f;
+ private final float mBrightnessRampRateSlow;
+ private final float mBrightnessRampRateFast;
// Whether or not to skip the initial brightness ramps into STATE_ON.
@@ -417,6 +417,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mBlanker = blanker;
mContext = context;
mBrightnessSynchronizer = new BrightnessSynchronizer(context);
+ mBrightnessSynchronizer.startSynchronizing();
mDisplayId = displayId;
PowerManager pm = context.getSystemService(PowerManager.class);
@@ -454,6 +455,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);
+ mBrightnessRampRateFast = BrightnessSynchronizer.brightnessIntToFloat(resources.getInteger(
+ com.android.internal.R.integer.config_brightness_ramp_rate_fast));
+ mBrightnessRampRateSlow = BrightnessSynchronizer.brightnessIntToFloat(resources.getInteger(
+ com.android.internal.R.integer.config_brightness_ramp_rate_slow));
mSkipScreenOnBrightnessRamp = resources.getBoolean(
com.android.internal.R.bool.config_skipScreenOnBrightnessRamp);
@@ -680,8 +685,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
private void initialize() {
- // Initialize the power state object for the default display.
- // In the future, we might manage multiple displays independently.
mPowerState = new DisplayPowerState(mBlanker,
mColorFadeEnabled ? new ColorFade(mDisplayId) : null, mDisplayId);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 9245f55bd9fe..f6578584cb18 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -266,12 +266,27 @@ final class LocalDisplayAdapter extends DisplayAdapter {
boolean modesAdded = false;
for (int i = 0; i < configs.length; i++) {
SurfaceControl.DisplayConfig config = configs[i];
+ List<Float> alternativeRefreshRates = new ArrayList<>();
+ for (int j = 0; j < configs.length; j++) {
+ SurfaceControl.DisplayConfig other = configs[j];
+ boolean isAlternative = j != i && other.width == config.width
+ && other.height == config.height
+ && other.refreshRate != config.refreshRate
+ && other.configGroup == config.configGroup;
+ if (isAlternative) {
+ alternativeRefreshRates.add(configs[j].refreshRate);
+ }
+ }
+ Collections.sort(alternativeRefreshRates);
+
// First, check to see if we've already added a matching mode. Since not all
// configuration options are exposed via Display.Mode, it's possible that we have
// multiple DisplayConfigs that would generate the same Display.Mode.
boolean existingMode = false;
- for (int j = 0; j < records.size(); j++) {
- if (records.get(j).hasMatchingMode(config)) {
+ for (DisplayModeRecord record : records) {
+ if (record.hasMatchingMode(config)
+ && refreshRatesEquals(alternativeRefreshRates,
+ record.mMode.getAlternativeRefreshRates())) {
existingMode = true;
break;
}
@@ -282,9 +297,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// If we haven't already added a mode for this configuration to the new set of
// supported modes then check to see if we have one in the prior set of supported
// modes to reuse.
- DisplayModeRecord record = findDisplayModeRecord(config);
+ DisplayModeRecord record = findDisplayModeRecord(config, alternativeRefreshRates);
if (record == null) {
- record = new DisplayModeRecord(config);
+ float[] alternativeRates = new float[alternativeRefreshRates.size()];
+ for (int j = 0; j < alternativeRates.length; j++) {
+ alternativeRates[j] = alternativeRefreshRates.get(j);
+ }
+ record = new DisplayModeRecord(config, alternativeRates);
modesAdded = true;
}
records.add(record);
@@ -495,16 +514,31 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return true;
}
- private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayConfig config) {
+ private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayConfig config,
+ List<Float> alternativeRefreshRates) {
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
- if (record.hasMatchingMode(config)) {
+ if (record.hasMatchingMode(config)
+ && refreshRatesEquals(alternativeRefreshRates,
+ record.mMode.getAlternativeRefreshRates())) {
return record;
}
}
return null;
}
+ private boolean refreshRatesEquals(List<Float> list, float[] array) {
+ if (list.size() != array.length) {
+ return false;
+ }
+ for (int i = 0; i < list.size(); i++) {
+ if (Float.floatToIntBits(list.get(i)) != Float.floatToIntBits(array[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
@Override
public void applyPendingDisplayDeviceInfoChangesLocked() {
if (mHavePendingChanges) {
@@ -1032,8 +1066,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private static final class DisplayModeRecord {
public final Display.Mode mMode;
- DisplayModeRecord(SurfaceControl.DisplayConfig config) {
- mMode = createMode(config.width, config.height, config.refreshRate);
+ DisplayModeRecord(SurfaceControl.DisplayConfig config,
+ float[] alternativeRefreshRates) {
+ mMode = createMode(config.width, config.height, config.refreshRate,
+ alternativeRefreshRates);
}
/**
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index e35becc93be0..979c3b871284 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -588,7 +588,7 @@ final class LogicalDisplay {
}
/**
- * Swap the underlying {@link DisplayDevice} with the specificed LogicalDisplay.
+ * Swap the underlying {@link DisplayDevice} with the specified LogicalDisplay.
*
* @param targetDisplay The display with which to swap display-devices.
* @return {@code true} if the displays were swapped, {@code false} otherwise.
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index a843af5982b4..45c38b456b0a 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -17,6 +17,7 @@
package com.android.server.display;
import android.content.Context;
+import android.os.Process;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Slog;
@@ -149,6 +150,10 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
return null;
}
+ public int[] getDisplayIdsLocked() {
+ return getDisplayIdsLocked(Process.SYSTEM_UID);
+ }
+
public int[] getDisplayIdsLocked(int callingUid) {
final int count = mLogicalDisplays.size();
int[] displayIds = new int[count];
diff --git a/services/core/java/com/android/server/display/TEST_MAPPING b/services/core/java/com/android/server/display/TEST_MAPPING
new file mode 100644
index 000000000000..66ec5c4b1525
--- /dev/null
+++ b/services/core/java/com/android/server/display/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksMockingServicesTests",
+ "options": [
+ {"include-filter": "com.android.server.display"},
+ {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 5fddae53d632..d0cc8e71dbfa 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -88,79 +88,84 @@ final class Constants {
@Retention(RetentionPolicy.SOURCE)
@IntDef({
- MESSAGE_FEATURE_ABORT,
- MESSAGE_IMAGE_VIEW_ON,
- MESSAGE_TUNER_STEP_INCREMENT,
- MESSAGE_TUNER_STEP_DECREMENT,
- MESSAGE_TUNER_DEVICE_STATUS,
- MESSAGE_GIVE_TUNER_DEVICE_STATUS,
- MESSAGE_RECORD_ON,
- MESSAGE_RECORD_STATUS,
- MESSAGE_RECORD_OFF,
- MESSAGE_TEXT_VIEW_ON,
- MESSAGE_RECORD_TV_SCREEN,
- MESSAGE_GIVE_DECK_STATUS,
- MESSAGE_DECK_STATUS,
- MESSAGE_SET_MENU_LANGUAGE,
- MESSAGE_CLEAR_ANALOG_TIMER,
- MESSAGE_SET_ANALOG_TIMER,
- MESSAGE_TIMER_STATUS,
- MESSAGE_STANDBY,
- MESSAGE_PLAY,
- MESSAGE_DECK_CONTROL,
- MESSAGE_TIMER_CLEARED_STATUS,
- MESSAGE_USER_CONTROL_PRESSED,
- MESSAGE_USER_CONTROL_RELEASED,
- MESSAGE_GIVE_OSD_NAME,
- MESSAGE_SET_OSD_NAME,
- MESSAGE_SET_OSD_STRING,
- MESSAGE_SET_TIMER_PROGRAM_TITLE,
- MESSAGE_SYSTEM_AUDIO_MODE_REQUEST,
- MESSAGE_GIVE_AUDIO_STATUS,
- MESSAGE_SET_SYSTEM_AUDIO_MODE,
- MESSAGE_REPORT_AUDIO_STATUS,
- MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS,
- MESSAGE_SYSTEM_AUDIO_MODE_STATUS,
- MESSAGE_ROUTING_CHANGE,
- MESSAGE_ROUTING_INFORMATION,
- MESSAGE_ACTIVE_SOURCE,
- MESSAGE_GIVE_PHYSICAL_ADDRESS,
- MESSAGE_REPORT_PHYSICAL_ADDRESS,
- MESSAGE_REQUEST_ACTIVE_SOURCE,
- MESSAGE_SET_STREAM_PATH,
- MESSAGE_DEVICE_VENDOR_ID,
- MESSAGE_VENDOR_COMMAND,
- MESSAGE_VENDOR_REMOTE_BUTTON_DOWN,
- MESSAGE_VENDOR_REMOTE_BUTTON_UP,
- MESSAGE_GIVE_DEVICE_VENDOR_ID,
- MESSAGE_MENU_REQUEST,
- MESSAGE_MENU_STATUS,
- MESSAGE_GIVE_DEVICE_POWER_STATUS,
- MESSAGE_REPORT_POWER_STATUS,
- MESSAGE_GET_MENU_LANGUAGE,
- MESSAGE_SELECT_ANALOG_SERVICE,
- MESSAGE_SELECT_DIGITAL_SERVICE,
- MESSAGE_SET_DIGITAL_TIMER,
- MESSAGE_CLEAR_DIGITAL_TIMER,
- MESSAGE_SET_AUDIO_RATE,
- MESSAGE_INACTIVE_SOURCE,
- MESSAGE_CEC_VERSION,
- MESSAGE_GET_CEC_VERSION,
- MESSAGE_VENDOR_COMMAND_WITH_ID,
- MESSAGE_CLEAR_EXTERNAL_TIMER,
- MESSAGE_SET_EXTERNAL_TIMER,
- MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR,
- MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
- MESSAGE_INITIATE_ARC,
- MESSAGE_REPORT_ARC_INITIATED,
- MESSAGE_REPORT_ARC_TERMINATED,
- MESSAGE_REQUEST_ARC_INITIATION,
- MESSAGE_REQUEST_ARC_TERMINATION,
- MESSAGE_TERMINATE_ARC,
- MESSAGE_CDC_MESSAGE,
- MESSAGE_ABORT,
+ MESSAGE_FEATURE_ABORT,
+ MESSAGE_IMAGE_VIEW_ON,
+ MESSAGE_TUNER_STEP_INCREMENT,
+ MESSAGE_TUNER_STEP_DECREMENT,
+ MESSAGE_TUNER_DEVICE_STATUS,
+ MESSAGE_GIVE_TUNER_DEVICE_STATUS,
+ MESSAGE_RECORD_ON,
+ MESSAGE_RECORD_STATUS,
+ MESSAGE_RECORD_OFF,
+ MESSAGE_TEXT_VIEW_ON,
+ MESSAGE_RECORD_TV_SCREEN,
+ MESSAGE_GIVE_DECK_STATUS,
+ MESSAGE_DECK_STATUS,
+ MESSAGE_SET_MENU_LANGUAGE,
+ MESSAGE_CLEAR_ANALOG_TIMER,
+ MESSAGE_SET_ANALOG_TIMER,
+ MESSAGE_TIMER_STATUS,
+ MESSAGE_STANDBY,
+ MESSAGE_PLAY,
+ MESSAGE_DECK_CONTROL,
+ MESSAGE_TIMER_CLEARED_STATUS,
+ MESSAGE_USER_CONTROL_PRESSED,
+ MESSAGE_USER_CONTROL_RELEASED,
+ MESSAGE_GIVE_OSD_NAME,
+ MESSAGE_SET_OSD_NAME,
+ MESSAGE_SET_OSD_STRING,
+ MESSAGE_SET_TIMER_PROGRAM_TITLE,
+ MESSAGE_SYSTEM_AUDIO_MODE_REQUEST,
+ MESSAGE_GIVE_AUDIO_STATUS,
+ MESSAGE_SET_SYSTEM_AUDIO_MODE,
+ MESSAGE_REPORT_AUDIO_STATUS,
+ MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS,
+ MESSAGE_SYSTEM_AUDIO_MODE_STATUS,
+ MESSAGE_ROUTING_CHANGE,
+ MESSAGE_ROUTING_INFORMATION,
+ MESSAGE_ACTIVE_SOURCE,
+ MESSAGE_GIVE_PHYSICAL_ADDRESS,
+ MESSAGE_REPORT_PHYSICAL_ADDRESS,
+ MESSAGE_REQUEST_ACTIVE_SOURCE,
+ MESSAGE_SET_STREAM_PATH,
+ MESSAGE_DEVICE_VENDOR_ID,
+ MESSAGE_VENDOR_COMMAND,
+ MESSAGE_VENDOR_REMOTE_BUTTON_DOWN,
+ MESSAGE_VENDOR_REMOTE_BUTTON_UP,
+ MESSAGE_GIVE_DEVICE_VENDOR_ID,
+ MESSAGE_MENU_REQUEST,
+ MESSAGE_MENU_STATUS,
+ MESSAGE_GIVE_DEVICE_POWER_STATUS,
+ MESSAGE_REPORT_POWER_STATUS,
+ MESSAGE_GET_MENU_LANGUAGE,
+ MESSAGE_SELECT_ANALOG_SERVICE,
+ MESSAGE_SELECT_DIGITAL_SERVICE,
+ MESSAGE_SET_DIGITAL_TIMER,
+ MESSAGE_CLEAR_DIGITAL_TIMER,
+ MESSAGE_SET_AUDIO_RATE,
+ MESSAGE_INACTIVE_SOURCE,
+ MESSAGE_CEC_VERSION,
+ MESSAGE_GET_CEC_VERSION,
+ MESSAGE_VENDOR_COMMAND_WITH_ID,
+ MESSAGE_CLEAR_EXTERNAL_TIMER,
+ MESSAGE_SET_EXTERNAL_TIMER,
+ MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR,
+ MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR,
+ MESSAGE_GIVE_FEATURES,
+ MESSAGE_REPORT_FEATURES,
+ MESSAGE_REQUEST_CURRENT_LATENCY,
+ MESSAGE_REPORT_CURRENT_LATENCY,
+ MESSAGE_INITIATE_ARC,
+ MESSAGE_REPORT_ARC_INITIATED,
+ MESSAGE_REPORT_ARC_TERMINATED,
+ MESSAGE_REQUEST_ARC_INITIATION,
+ MESSAGE_REQUEST_ARC_TERMINATION,
+ MESSAGE_TERMINATE_ARC,
+ MESSAGE_CDC_MESSAGE,
+ MESSAGE_ABORT,
})
- public @interface FeatureOpcode {}
+ public @interface FeatureOpcode {
+ }
static final int MESSAGE_FEATURE_ABORT = 0x00;
static final int MESSAGE_IMAGE_VIEW_ON = 0x04;
@@ -225,6 +230,10 @@ final class Constants {
static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2;
static final int MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR = 0xA3;
static final int MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR = 0xA4;
+ static final int MESSAGE_GIVE_FEATURES = 0xA5;
+ static final int MESSAGE_REPORT_FEATURES = 0xA6;
+ static final int MESSAGE_REQUEST_CURRENT_LATENCY = 0xA7;
+ static final int MESSAGE_REPORT_CURRENT_LATENCY = 0xA8;
static final int MESSAGE_INITIATE_ARC = 0xC0;
static final int MESSAGE_REPORT_ARC_INITIATED = 0xC1;
static final int MESSAGE_REPORT_ARC_TERMINATED = 0xC2;
@@ -501,6 +510,35 @@ final class Constants {
static final int VERSION_1_4 = 0x05;
static final int VERSION_2_0 = 0x06;
+ static final int ALL_DEVICE_TYPES_TV = 7;
+ static final int ALL_DEVICE_TYPES_RECORDER = 6;
+ static final int ALL_DEVICE_TYPES_TUNER = 5;
+ static final int ALL_DEVICE_TYPES_PLAYBACK = 4;
+ static final int ALL_DEVICE_TYPES_AUDIO_SYSTEM = 3;
+ static final int ALL_DEVICE_TYPES_SWITCH = 2;
+
+ static final int DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN = 6;
+ static final int DEVICE_FEATURE_TV_SUPPORTS_SET_OSD_STRING = 5;
+ static final int DEVICE_FEATURE_SUPPORTS_DECK_CONTROL = 4;
+ static final int DEVICE_FEATURE_SUPPORTS_SET_AUDIO_RATE = 3;
+ static final int DEVICE_FEATURE_SINK_SUPPORTS_ARC_TX = 2;
+ static final int DEVICE_FEATURE_SOURCE_SUPPORTS_ARC_RX = 1;
+
+ static final int RC_PROFILE_TV = 0;
+ static final int RC_PROFILE_SOURCE = 1;
+
+ static final int RC_PROFILE_TV_NONE = 0x0;
+ static final int RC_PROFILE_TV_ONE = 0x2;
+ static final int RC_PROFILE_TV_TWO = 0x6;
+ static final int RC_PROFILE_TV_THREE = 0xA;
+ static final int RC_PROFILE_TV_FOUR = 0xE;
+
+ static final int RC_PROFILE_SOURCE_HANDLES_ROOT_MENU = 4;
+ static final int RC_PROFILE_SOURCE_HANDLES_SETUP_MENU = 3;
+ static final int RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU = 2;
+ static final int RC_PROFILE_SOURCE_HANDLES_TOP_MENU = 1;
+ static final int RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU = 0;
+
private Constants() {
/* cannot be instantiated */
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index e906a7c8132c..3794da398c01 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -21,6 +21,7 @@ import static android.hardware.hdmi.HdmiControlManager.CecSettingName;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringDef;
import android.content.Context;
import android.hardware.hdmi.HdmiControlManager;
import android.os.Environment;
@@ -68,6 +69,15 @@ public class HdmiCecConfig {
private static final int STORAGE_SYSPROPS = 0;
private static final int STORAGE_GLOBAL_SETTINGS = 1;
+ private static final String VALUE_TYPE_STRING = "string";
+ private static final String VALUE_TYPE_INT = "int";
+
+ @StringDef({
+ VALUE_TYPE_STRING,
+ VALUE_TYPE_INT,
+ })
+ private @interface ValueType {}
+
/**
* System property key for Power State Change on Active Source Lost.
*/
@@ -219,6 +229,8 @@ public class HdmiCecConfig {
switch (setting.getName()) {
case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED:
return STORAGE_GLOBAL_SETTINGS;
+ case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION:
+ return STORAGE_GLOBAL_SETTINGS;
case HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP:
return STORAGE_GLOBAL_SETTINGS;
case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST:
@@ -227,7 +239,7 @@ public class HdmiCecConfig {
return STORAGE_SYSPROPS;
default:
throw new RuntimeException("Invalid CEC setting '" + setting.getName()
- + "' storage.");
+ + "' storage.");
}
}
@@ -235,6 +247,8 @@ public class HdmiCecConfig {
switch (setting.getName()) {
case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED:
return Global.HDMI_CONTROL_ENABLED;
+ case HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION:
+ return Global.HDMI_CEC_VERSION;
case HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP:
return Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP;
case HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST:
@@ -247,17 +261,15 @@ public class HdmiCecConfig {
}
}
- private String retrieveValue(@NonNull Setting setting) {
+ private String retrieveValue(@NonNull Setting setting, @NonNull String defaultValue) {
@Storage int storage = getStorage(setting);
String storageKey = getStorageKey(setting);
if (storage == STORAGE_SYSPROPS) {
Slog.d(TAG, "Reading '" + storageKey + "' sysprop.");
- return mStorageAdapter.retrieveSystemProperty(storageKey,
- setting.getDefaultValue().getStringValue());
+ return mStorageAdapter.retrieveSystemProperty(storageKey, defaultValue);
} else if (storage == STORAGE_GLOBAL_SETTINGS) {
Slog.d(TAG, "Reading '" + storageKey + "' global setting.");
- return mStorageAdapter.retrieveGlobalSetting(mContext, storageKey,
- setting.getDefaultValue().getStringValue());
+ return mStorageAdapter.retrieveGlobalSetting(mContext, storageKey, defaultValue);
}
return null;
}
@@ -274,6 +286,10 @@ public class HdmiCecConfig {
}
}
+ private int getIntValue(@NonNull Value value) {
+ return Integer.decode(value.getIntValue());
+ }
+
/**
* Returns a list of all settings based on the XML metadata.
*/
@@ -316,13 +332,41 @@ public class HdmiCecConfig {
}
/**
- * For a given setting name returns values that are allowed for that setting.
+ * For a given setting name returns true if and only if the value type of that
+ * setting is a string.
*/
- public List<String> getAllowedValues(@NonNull @CecSettingName String name) {
+ public boolean isStringValueType(@NonNull @CecSettingName String name) {
Setting setting = getSetting(name);
if (setting == null) {
throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
}
+ return getSetting(name).getValueType().equals(VALUE_TYPE_STRING);
+ }
+
+ /**
+ * For a given setting name returns true if and only if the value type of that
+ * setting is an int.
+ */
+ public boolean isIntValueType(@NonNull @CecSettingName String name) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ return getSetting(name).getValueType().equals(VALUE_TYPE_INT);
+ }
+
+ /**
+ * For a given setting name returns values that are allowed for that setting (string).
+ */
+ public List<String> getAllowedStringValues(@NonNull @CecSettingName String name) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ if (!setting.getValueType().equals(VALUE_TYPE_STRING)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
List<String> allowedValues = new ArrayList<String>();
for (Value allowedValue : setting.getAllowedValues().getValue()) {
allowedValues.add(allowedValue.getStringValue());
@@ -331,32 +375,92 @@ public class HdmiCecConfig {
}
/**
- * For a given setting name returns the default value for that setting.
+ * For a given setting name returns values that are allowed for that setting (string).
+ */
+ public List<Integer> getAllowedIntValues(@NonNull @CecSettingName String name) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ if (!setting.getValueType().equals(VALUE_TYPE_INT)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
+ List<Integer> allowedValues = new ArrayList<Integer>();
+ for (Value allowedValue : setting.getAllowedValues().getValue()) {
+ allowedValues.add(getIntValue(allowedValue));
+ }
+ return allowedValues;
+ }
+
+ /**
+ * For a given setting name returns the default value for that setting (string).
*/
- public String getDefaultValue(@NonNull @CecSettingName String name) {
+ public String getDefaultStringValue(@NonNull @CecSettingName String name) {
Setting setting = getSetting(name);
if (setting == null) {
throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
}
+ if (!setting.getValueType().equals(VALUE_TYPE_STRING)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
return getSetting(name).getDefaultValue().getStringValue();
}
/**
- * For a given setting name returns the current value of that setting.
+ * For a given setting name returns the default value for that setting (int).
*/
- public String getValue(@NonNull @CecSettingName String name) {
+ public int getDefaultIntValue(@NonNull @CecSettingName String name) {
Setting setting = getSetting(name);
if (setting == null) {
throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
}
+ if (!setting.getValueType().equals(VALUE_TYPE_INT)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
+ return getIntValue(getSetting(name).getDefaultValue());
+ }
+
+ /**
+ * For a given setting name returns the current value of that setting (string).
+ */
+ public String getStringValue(@NonNull @CecSettingName String name) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ if (!setting.getValueType().equals(VALUE_TYPE_STRING)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
+ Slog.d(TAG, "Getting CEC setting value '" + name + "'.");
+ return retrieveValue(setting, setting.getDefaultValue().getStringValue());
+ }
+
+ /**
+ * For a given setting name returns the current value of that setting (int).
+ */
+ public int getIntValue(@NonNull @CecSettingName String name) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ if (!setting.getValueType().equals(VALUE_TYPE_INT)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a int-type setting.");
+ }
Slog.d(TAG, "Getting CEC setting value '" + name + "'.");
- return retrieveValue(setting);
+ String defaultValue = Integer.toString(getIntValue(setting.getDefaultValue()));
+ String value = retrieveValue(setting, defaultValue);
+ return Integer.parseInt(value);
}
/**
- * For a given setting name and value sets the current value of that setting.
+ * For a given setting name and value sets the current value of that setting (string).
*/
- public void setValue(@NonNull @CecSettingName String name, @NonNull String value) {
+ public void setStringValue(@NonNull @CecSettingName String name, @NonNull String value) {
Setting setting = getSetting(name);
if (setting == null) {
throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -364,11 +468,38 @@ public class HdmiCecConfig {
if (!setting.getUserConfigurable()) {
throw new IllegalArgumentException("Updating CEC setting '" + name + "' prohibited.");
}
- if (!getAllowedValues(name).contains(value)) {
+ if (!setting.getValueType().equals(VALUE_TYPE_STRING)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a string-type setting.");
+ }
+ if (!getAllowedStringValues(name).contains(value)) {
throw new IllegalArgumentException("Invalid CEC setting '" + name
+ "' value: '" + value + "'.");
}
Slog.d(TAG, "Updating CEC setting '" + name + "' to '" + value + "'.");
storeValue(setting, value);
}
+
+ /**
+ * For a given setting name and value sets the current value of that setting (int).
+ */
+ public void setIntValue(@NonNull @CecSettingName String name, int value) {
+ Setting setting = getSetting(name);
+ if (setting == null) {
+ throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
+ }
+ if (!setting.getUserConfigurable()) {
+ throw new IllegalArgumentException("Updating CEC setting '" + name + "' prohibited.");
+ }
+ if (!setting.getValueType().equals(VALUE_TYPE_INT)) {
+ throw new IllegalArgumentException("Setting '" + name
+ + "' is not a int-type setting.");
+ }
+ if (!getAllowedIntValues(name).contains(value)) {
+ throw new IllegalArgumentException("Invalid CEC setting '" + name
+ + "' value: '" + value + "'.");
+ }
+ Slog.d(TAG, "Updating CEC setting '" + name + "' to '" + value + "'.");
+ storeValue(setting, Integer.toString(value));
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 62a67b6243d7..e7f302c1977a 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -351,6 +351,8 @@ abstract class HdmiCecLocalDevice {
return handleRequestShortAudioDescriptor(message);
case Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR:
return handleReportShortAudioDescriptor(message);
+ case Constants.MESSAGE_GIVE_FEATURES:
+ return handleGiveFeatures(message);
default:
return false;
}
@@ -551,6 +553,33 @@ abstract class HdmiCecLocalDevice {
return false;
}
+ protected abstract int getRcProfile();
+
+ protected abstract List<Integer> getRcFeatures();
+
+ protected abstract List<Integer> getDeviceFeatures();
+
+ protected boolean handleGiveFeatures(HdmiCecMessage message) {
+ if (mService.getCecVersion() < Constants.VERSION_2_0) {
+ return false;
+ }
+
+ List<Integer> localDeviceTypes = new ArrayList<>();
+ for (HdmiCecLocalDevice localDevice : mService.getAllLocalDevices()) {
+ localDeviceTypes.add(localDevice.mDeviceType);
+ }
+
+
+ int rcProfile = getRcProfile();
+ List<Integer> rcFeatures = getRcFeatures();
+ List<Integer> deviceFeatures = getDeviceFeatures();
+
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildReportFeatures(mAddress, mService.getCecVersion(),
+ localDeviceTypes, rcProfile, rcFeatures, deviceFeatures));
+ return true;
+ }
+
@ServiceThreadOnly
protected boolean handleStandby(HdmiCecMessage message) {
assertRunOnServiceThread();
@@ -997,6 +1026,11 @@ abstract class HdmiCecLocalDevice {
protected void onStandby(boolean initiatedByCec, int standbyAction) {}
/**
+ * Called when the initialization of local devices is complete.
+ */
+ protected void onInitializeCecComplete(int initiatedBy) {}
+
+ /**
* Disable device. {@code callback} is used to get notified when all pending actions are
* completed or timeout is issued.
*
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index fe4fd3805994..4110de6fee90 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -47,6 +47,8 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiUtils.CodecSad;
import com.android.server.hdmi.HdmiUtils.DeviceConfig;
+import com.google.android.collect.Lists;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
@@ -176,6 +178,11 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
}
@Override
+ protected List<Integer> getDeviceFeatures() {
+ return Lists.newArrayList(Constants.DEVICE_FEATURE_SOURCE_SUPPORTS_ARC_RX);
+ }
+
+ @Override
@ServiceThreadOnly
void onHotplug(int portId, boolean connected) {
assertRunOnServiceThread();
@@ -495,17 +502,17 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
private byte[] getSupportedShortAudioDescriptorsFromConfig(
List<DeviceConfig> deviceConfig, @AudioCodec int[] audioFormatCodes) {
DeviceConfig deviceConfigToUse = null;
+ String audioDeviceName = SystemProperties.get(
+ Constants.PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT,
+ "VX_AUDIO_DEVICE_IN_HDMI_ARC");
for (DeviceConfig device : deviceConfig) {
- // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
- if (device.name.equals("VX_AUDIO_DEVICE_IN_HDMI_ARC")) {
+ if (device.name.equals(audioDeviceName)) {
deviceConfigToUse = device;
break;
}
}
if (deviceConfigToUse == null) {
- // TODO(amyjojo) use PROPERTY_SYSTEM_AUDIO_MODE_AUDIO_PORT to get the audio device name
- Slog.w(TAG, "sadConfig.xml does not have required device info for "
- + "VX_AUDIO_DEVICE_IN_HDMI_ARC");
+ Slog.w(TAG, "sadConfig.xml does not have required device info for " + audioDeviceName);
return new byte[0];
}
HashMap<Integer, byte[]> map = new HashMap<>();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 6257032cf709..98779197db69 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -224,6 +224,21 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
@Override
@ServiceThreadOnly
+ protected void onInitializeCecComplete(int initiatedBy) {
+ if (initiatedBy == HdmiControlService.INITIATED_BY_SCREEN_ON) {
+ oneTouchPlay(new IHdmiControlCallback.Stub() {
+ @Override
+ public void onComplete(int result) {
+ if (result != HdmiControlManager.RESULT_SUCCESS) {
+ Slog.w(TAG, "Failed to complete One Touch Play. result=" + result);
+ }
+ }
+ });
+ }
+ }
+
+ @Override
+ @ServiceThreadOnly
void setAutoDeviceOff(boolean enabled) {
assertRunOnServiceThread();
mAutoTvOff = enabled;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 960510693f6a..62b7d8f95f5a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -28,6 +28,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.hdmi.Constants.LocalActivePort;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
+import com.google.android.collect.Lists;
+
import java.util.List;
/**
@@ -233,6 +235,24 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
// do nothing
}
+ @Override
+ protected int getRcProfile() {
+ return Constants.RC_PROFILE_SOURCE;
+ }
+
+ @Override
+ protected List<Integer> getRcFeatures() {
+ return Lists.newArrayList(Constants.RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU,
+ Constants.RC_PROFILE_SOURCE_HANDLES_ROOT_MENU,
+ Constants.RC_PROFILE_SOURCE_HANDLES_SETUP_MENU,
+ Constants.RC_PROFILE_SOURCE_HANDLES_TOP_MENU);
+ }
+
+ @Override
+ protected List<Integer> getDeviceFeatures() {
+ return Lists.newArrayList();
+ }
+
// Active source claiming needs to be handled in Service
// since service can decide who will be the active source when the device supports
// multiple device types in this method.
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index c2e80caadd3b..8cf6c9757fe8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -51,6 +51,8 @@ import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+import com.google.android.collect.Lists;
+
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -1479,6 +1481,22 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
@Override
+ protected int getRcProfile() {
+ return Constants.RC_PROFILE_TV;
+ }
+
+ @Override
+ protected List<Integer> getRcFeatures() {
+ return Lists.newArrayList(Constants.RC_PROFILE_TV_NONE);
+ }
+
+ @Override
+ protected List<Integer> getDeviceFeatures() {
+ return Lists.newArrayList(Constants.DEVICE_FEATURE_SINK_SUPPORTS_ARC_TX,
+ Constants.DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN);
+ }
+
+ @Override
protected void sendStandby(int deviceId) {
HdmiDeviceInfo targetDevice = mService.getHdmiCecNetwork().getDeviceInfo(deviceId);
if (targetDevice == null) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
index 7a6ce8de8c24..c85fd50c62fe 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
@@ -18,6 +18,8 @@ package com.android.server.hdmi;
import android.annotation.Nullable;
+import com.android.server.hdmi.Constants.FeatureOpcode;
+
import libcore.util.EmptyArray;
import java.util.Arrays;
@@ -126,7 +128,7 @@ public final class HdmiCecMessage {
return s.toString();
}
- private static String opcodeToString(int opcode) {
+ private static String opcodeToString(@FeatureOpcode int opcode) {
switch (opcode) {
case Constants.MESSAGE_FEATURE_ABORT:
return "Feature Abort";
@@ -264,6 +266,14 @@ public final class HdmiCecMessage {
return "Request ARC Initiation";
case Constants.MESSAGE_REQUEST_ARC_TERMINATION:
return "Request ARC Termination";
+ case Constants.MESSAGE_GIVE_FEATURES:
+ return "Give Features";
+ case Constants.MESSAGE_REPORT_FEATURES:
+ return "Report Features";
+ case Constants.MESSAGE_REQUEST_CURRENT_LATENCY:
+ return "Request Current Latency";
+ case Constants.MESSAGE_REPORT_CURRENT_LATENCY:
+ return "Report Current Latency";
case Constants.MESSAGE_TERMINATE_ARC:
return "Terminate ARC";
case Constants.MESSAGE_CDC_MESSAGE:
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 653323de8d60..1a481b632606 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -16,10 +16,14 @@
package com.android.server.hdmi;
+import android.hardware.hdmi.HdmiDeviceInfo;
+
import com.android.server.hdmi.Constants.AudioCodec;
+import com.android.server.hdmi.Constants.CecVersion;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
+import java.util.List;
/**
* A helper class to build {@link HdmiCecMessage} from various cec commands.
@@ -688,6 +692,40 @@ public class HdmiCecMessageBuilder {
return buildCommand(src, dest, Constants.MESSAGE_CLEAR_EXTERNAL_TIMER, params);
}
+ static HdmiCecMessage buildGiveFeatures(int src, int dest) {
+ return buildCommand(src, dest, Constants.MESSAGE_GIVE_FEATURES);
+ }
+
+ static HdmiCecMessage buildReportFeatures(int src, @CecVersion int cecVersion,
+ List<Integer> allDeviceTypes, int rcProfile, List<Integer> rcFeatures,
+ List<Integer> deviceFeatures) {
+ byte cecVersionByte = (byte) (cecVersion & 0xFF);
+ byte deviceTypes = 0;
+ for (Integer deviceType : allDeviceTypes) {
+ deviceTypes |= 1 << hdmiDeviceInfoDeviceTypeToShiftValue(deviceType);
+ }
+
+ byte rcProfileByte = 0;
+ rcProfileByte |= rcProfile << 6;
+ if (rcProfile == Constants.RC_PROFILE_SOURCE) {
+ for (Integer rcFeature : rcFeatures) {
+ rcProfileByte |= 1 << rcFeature;
+ }
+ } else {
+ byte rcProfileTv = (byte) (rcFeatures.get(0) & 0xFFFF);
+ rcProfileByte |= rcProfileTv;
+ }
+
+ byte deviceFeaturesByte = 0;
+ for (Integer deviceFeature : deviceFeatures) {
+ deviceFeaturesByte |= 1 << deviceFeature;
+ }
+
+ byte[] params = {cecVersionByte, deviceTypes, rcProfileByte, deviceFeaturesByte};
+ return buildCommand(src, Constants.ADDR_BROADCAST, Constants.MESSAGE_REPORT_FEATURES,
+ params);
+ }
+
/***** Please ADD new buildXXX() methods above. ******/
/**
@@ -738,4 +776,23 @@ public class HdmiCecMessageBuilder {
(byte) (physicalAddress & 0xFF)
};
}
+
+ private static int hdmiDeviceInfoDeviceTypeToShiftValue(int deviceType) {
+ switch (deviceType) {
+ case HdmiDeviceInfo.DEVICE_TV:
+ return Constants.ALL_DEVICE_TYPES_TV;
+ case HdmiDeviceInfo.DEVICE_RECORDER:
+ return Constants.ALL_DEVICE_TYPES_RECORDER;
+ case HdmiDeviceInfo.DEVICE_TUNER:
+ return Constants.ALL_DEVICE_TYPES_TUNER;
+ case HdmiDeviceInfo.DEVICE_PLAYBACK:
+ return Constants.ALL_DEVICE_TYPES_PLAYBACK;
+ case HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM:
+ return Constants.ALL_DEVICE_TYPES_AUDIO_SYSTEM;
+ case HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH:
+ return Constants.ALL_DEVICE_TYPES_SWITCH;
+ default:
+ throw new IllegalArgumentException("Unhandled device type: " + deviceType);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index fe97f701e089..baed9cc1b71d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -148,9 +148,25 @@ public class HdmiCecMessageValidator {
addValidationInfo(Constants.MESSAGE_SET_MENU_LANGUAGE,
new AsciiValidator(3), DEST_BROADCAST);
- // TODO: Handle messages for the Deck Control.
+ ParameterValidator statusRequestValidator = new OneByteRangeValidator(0x01, 0x03);
+ addValidationInfo(
+ Constants.MESSAGE_DECK_CONTROL, new OneByteRangeValidator(0x01, 0x04), DEST_DIRECT);
+ addValidationInfo(
+ Constants.MESSAGE_DECK_STATUS, new OneByteRangeValidator(0x11, 0x1F), DEST_DIRECT);
+ addValidationInfo(Constants.MESSAGE_GIVE_DECK_STATUS, statusRequestValidator, DEST_DIRECT);
+ addValidationInfo(Constants.MESSAGE_PLAY, new PlayModeValidator(), DEST_DIRECT);
// TODO: Handle messages for the Tuner Control.
+ addValidationInfo(
+ Constants.MESSAGE_GIVE_TUNER_DEVICE_STATUS, statusRequestValidator, DEST_DIRECT);
+ addValidationInfo(
+ Constants.MESSAGE_SELECT_ANALOG_SERVICE,
+ new SelectAnalogueServiceValidator(),
+ DEST_DIRECT);
+ addValidationInfo(
+ Constants.MESSAGE_SELECT_DIGITAL_SERVICE,
+ new SelectDigitalServiceValidator(),
+ DEST_DIRECT);
// Messages for the Vendor Specific Commands.
VariableLengthValidator maxLengthValidator = new VariableLengthValidator(0, 14);
@@ -176,9 +192,10 @@ public class HdmiCecMessageValidator {
Constants.MESSAGE_MENU_STATUS, new OneByteRangeValidator(0x00, 0x01), DEST_DIRECT);
// Messages for the Remote Control Passthrough.
- // TODO: Parse the first parameter and determine if it can have the next parameter.
- addValidationInfo(Constants.MESSAGE_USER_CONTROL_PRESSED,
- new VariableLengthValidator(1, 2), DEST_DIRECT);
+ addValidationInfo(
+ Constants.MESSAGE_USER_CONTROL_PRESSED,
+ new UserControlPressedValidator(),
+ DEST_DIRECT);
// Messages for the Power Status.
addValidationInfo(
@@ -211,6 +228,17 @@ public class HdmiCecMessageValidator {
new OneByteRangeValidator(0x00, 0x06),
DEST_DIRECT);
+ // Messages for Feature Discovery.
+ addValidationInfo(Constants.MESSAGE_GIVE_FEATURES, noneValidator, DEST_DIRECT);
+ addValidationInfo(Constants.MESSAGE_REPORT_FEATURES, new VariableLengthValidator(4, 14),
+ DEST_BROADCAST);
+
+ // Messages for Dynamic Auto Lipsync
+ addValidationInfo(Constants.MESSAGE_REQUEST_CURRENT_LATENCY, physicalAddressValidator,
+ DEST_BROADCAST);
+ addValidationInfo(Constants.MESSAGE_REPORT_CURRENT_LATENCY,
+ new VariableLengthValidator(4, 14), DEST_BROADCAST);
+
// All Messages for the ARC have no parameters.
// Messages for the Capability Discovery and Control.
@@ -515,6 +543,28 @@ public class HdmiCecMessageValidator {
}
/**
+ * Check if the given value is a valid Channel Identifier. A valid value is one which falls
+ * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section
+ * 17)
+ *
+ * @param params Channel Identifier parameters
+ * @param offset start offset of Channel Identifier
+ * @return true if the Channel Identifier is valid
+ */
+ private boolean isValidChannelIdentifier(byte[] params, int offset) {
+ // First 6 bits contain Channel Number Format
+ int channelNumberFormat = params[offset] & 0xFC;
+ if (channelNumberFormat == 0x04) {
+ // Validate it contains 1-part Channel Number data (16 bits)
+ return params.length - offset >= 3;
+ } else if (channelNumberFormat == 0x08) {
+ // Validate it contains Major Channel Number and Minor Channel Number (26 bits)
+ return params.length - offset >= 4;
+ }
+ return false;
+ }
+
+ /**
* Check if the given value is a valid Digital Service Identification. A valid value is one
* which falls within the range description defined in CEC 1.4 Specification : Operand
* Descriptions (Section 17)
@@ -544,15 +594,7 @@ public class HdmiCecMessageValidator {
} else if (serviceIdentificationMethod == 0x80) {
// Services identified by Channel
if (isValidDigitalBroadcastSystem(digitalBroadcastSystem)) {
- // First 6 bits contain Channel Number Format
- int channelNumberFormat = params[offset] & 0xFC;
- if (channelNumberFormat == 0x04) {
- // Validate it contains 1-part Channel Number data (16 bits)
- return params.length - offset >= 3;
- } else if (channelNumberFormat == 0x08) {
- // Validate it contains Major Channel Number and Minor Channel Number (26 bits)
- return params.length - offset >= 4;
- }
+ return isValidChannelIdentifier(params, offset);
}
}
return false;
@@ -632,6 +674,65 @@ public class HdmiCecMessageValidator {
return false;
}
+ /**
+ * Check if the given value is a valid Play mode. A valid value is one which falls within the
+ * range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ *
+ * @param value Play mode
+ * @return true if the Play mode is valid
+ */
+ private boolean isValidPlayMode(int value) {
+ return (isWithinRange(value, 0x05, 0x07)
+ || isWithinRange(value, 0x09, 0x0B)
+ || isWithinRange(value, 0x15, 0x17)
+ || isWithinRange(value, 0x19, 0x1B)
+ || isWithinRange(value, 0x24, 0x25)
+ || (value == 0x20));
+ }
+
+ /**
+ * Check if the given value is a valid UI Broadcast type. A valid value is one which falls
+ * within the range description defined in CEC 1.4 Specification : Operand Descriptions (Section
+ * 17)
+ *
+ * @param value UI Broadcast type
+ * @return true if the UI Broadcast type is valid
+ */
+ private boolean isValidUiBroadcastType(int value) {
+ return ((value == 0x00)
+ || (value == 0x01)
+ || (value == 0x10)
+ || (value == 0x20)
+ || (value == 0x30)
+ || (value == 0x40)
+ || (value == 0x50)
+ || (value == 0x60)
+ || (value == 0x70)
+ || (value == 0x80)
+ || (value == 0x90)
+ || (value == 0x91)
+ || (value == 0xA0));
+ }
+
+ /**
+ * Check if the given value is a valid UI Sound Presenation Control. A valid value is one which
+ * falls within the range description defined in CEC 1.4 Specification : Operand Descriptions
+ * (Section 17)
+ *
+ * @param value UI Sound Presenation Control
+ * @return true if the UI Sound Presenation Control is valid
+ */
+ private boolean isValidUiSoundPresenationControl(int value) {
+ value = value & 0xFF;
+ return ((value == 0x20)
+ || (value == 0x30)
+ || (value == 0x80)
+ || (value == 0x90)
+ || (value == 0xA0)
+ || (isWithinRange(value, 0xB1, 0xB3))
+ || (isWithinRange(value, 0xC1, 0xC3)));
+ }
+
private class PhysicalAddressValidator implements ParameterValidator {
@Override
public int isValid(byte[] params) {
@@ -863,4 +964,78 @@ public class HdmiCecMessageValidator {
return toErrorCode(isValidTimerStatusData(params, 0));
}
}
+
+ /**
+ * Check if the given play mode parameter is valid. A valid parameter should lie within the
+ * range description defined in CEC 1.4 Specification : Operand Descriptions (Section 17)
+ */
+ private class PlayModeValidator implements ParameterValidator {
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 1) {
+ return ERROR_PARAMETER_SHORT;
+ }
+ return toErrorCode(isValidPlayMode(params[0]));
+ }
+ }
+
+ /**
+ * Check if the given select analogue service parameter is valid. A valid parameter should lie
+ * within the range description defined in CEC 1.4 Specification : Operand Descriptions
+ * (Section 17)
+ */
+ private class SelectAnalogueServiceValidator implements ParameterValidator {
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 4) {
+ return ERROR_PARAMETER_SHORT;
+ }
+ return toErrorCode(isValidAnalogueBroadcastType(params[0])
+ && isValidAnalogueFrequency(HdmiUtils.twoBytesToInt(params, 1))
+ && isValidBroadcastSystem(params[3]));
+ }
+ }
+
+ /**
+ * Check if the given select digital service parameter is valid. A valid parameter should lie
+ * within the range description defined in CEC 1.4 Specification : Operand Descriptions
+ * (Section 17)
+ */
+ private class SelectDigitalServiceValidator implements ParameterValidator {
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 4) {
+ return ERROR_PARAMETER_SHORT;
+ }
+ return toErrorCode(isValidDigitalServiceIdentification(params, 0));
+ }
+ }
+
+ /** Check if the given user control press parameter is valid. */
+ private class UserControlPressedValidator implements ParameterValidator {
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 1) {
+ return ERROR_PARAMETER_SHORT;
+ }
+ if (params.length == 1) {
+ return OK;
+ }
+ int uiCommand = params[0];
+ switch (uiCommand) {
+ case HdmiCecKeycode.CEC_KEYCODE_PLAY_FUNCTION:
+ return toErrorCode(isValidPlayMode(params[1]));
+ case HdmiCecKeycode.CEC_KEYCODE_TUNE_FUNCTION:
+ return (params.length >= 4
+ ? toErrorCode(isValidChannelIdentifier(params, 1))
+ : ERROR_PARAMETER_SHORT);
+ case HdmiCecKeycode.CEC_KEYCODE_SELECT_BROADCAST_TYPE:
+ return toErrorCode(isValidUiBroadcastType(params[1]));
+ case HdmiCecKeycode.CEC_KEYCODE_SELECT_SOUND_PRESENTATION:
+ return toErrorCode(isValidUiSoundPresenationControl(params[1]));
+ default:
+ return OK;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index da4c6f115d55..dcd6c0260cff 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -26,9 +26,9 @@ import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE;
import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING;
import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE;
import static com.android.server.hdmi.Constants.OPTION_MHL_SERVICE_CONTROL;
-import static com.android.server.hdmi.Constants.VERSION_1_4;
import static com.android.server.power.ShutdownThread.SHUTDOWN_ACTION_PROPERTY;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -80,7 +80,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.SystemService;
-import com.android.server.hdmi.Constants.CecVersion;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
@@ -90,6 +89,8 @@ import libcore.util.EmptyArray;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -178,6 +179,19 @@ public class HdmiControlService extends SystemService {
private HdmiCecNetwork mHdmiCecNetwork;
+ static final int WAKE_UP_SCREEN_ON = 0;
+ static final int WAKE_UP_BOOT_UP = 1;
+
+ // The reason code for starting the wake-up procedure. This procedure starts either by
+ // Intent.ACTION_SCREEN_ON or after boot-up.
+ @IntDef({
+ WAKE_UP_SCREEN_ON,
+ WAKE_UP_BOOT_UP
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WakeReason {
+ }
+
// Logical address of the active source.
@GuardedBy("mLock")
protected final ActiveSource mActiveSource = new ActiveSource();
@@ -237,7 +251,7 @@ public class HdmiControlService extends SystemService {
break;
case Intent.ACTION_SCREEN_ON:
if (isPowerStandbyOrTransient()) {
- onWakeUp();
+ onWakeUp(WAKE_UP_SCREEN_ON);
}
break;
case Intent.ACTION_CONFIGURATION_CHANGED:
@@ -375,8 +389,8 @@ public class HdmiControlService extends SystemService {
@Nullable
private Looper mIoLooper;
- @CecVersion
- private int mCecVersion = Constants.VERSION_1_4;
+ @HdmiControlManager.HdmiCecVersion
+ private int mCecVersion;
// Last input port before switching to the MHL port. Should switch back to this port
// when the mobile device sends the request one touch play with off.
@@ -553,7 +567,7 @@ public class HdmiControlService extends SystemService {
private void bootCompleted() {
// on boot, if device is interactive, set HDMI CEC state as powered on as well
if (mPowerManager.isInteractive() && isPowerStandbyOrTransient()) {
- onWakeUp();
+ onWakeUp(WAKE_UP_BOOT_UP);
}
}
@@ -639,6 +653,12 @@ public class HdmiControlService extends SystemService {
reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING;
break;
case INITIATED_BY_SCREEN_ON:
+ reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP;
+ final List<HdmiCecLocalDevice> devices = getAllLocalDevices();
+ for (HdmiCecLocalDevice device : devices) {
+ device.onInitializeCecComplete(initiatedBy);
+ }
+ break;
case INITIATED_BY_WAKE_UP_MESSAGE:
reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP;
break;
@@ -798,7 +818,8 @@ public class HdmiControlService extends SystemService {
private void initializeCec(int initiatedBy) {
mAddressAllocated = false;
- mCecVersion = readIntSetting(Global.HDMI_CEC_VERSION, VERSION_1_4);
+ mCecVersion = getHdmiCecConfig().getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION);
mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
mCecController.setLanguage(mMenuLanguage);
@@ -1006,7 +1027,7 @@ public class HdmiControlService extends SystemService {
/**
* Returns version of CEC.
*/
- @CecVersion
+ @HdmiControlManager.HdmiCecVersion
int getCecVersion() {
return mCecVersion;
}
@@ -1527,61 +1548,8 @@ public class HdmiControlService extends SystemService {
@Nullable
public HdmiDeviceInfo getActiveSource() {
enforceAccessPermission();
- HdmiCecLocalDeviceTv tv = tv();
- if (tv == null) {
- if (isTvDevice()) {
- Slog.e(TAG, "Local tv device not available.");
- return null;
- }
- if (isPlaybackDevice()) {
- // if playback device itself is the active source,
- // return its own device info.
- if (playback() != null && playback().isActiveSource()) {
- return playback().getDeviceInfo();
- }
- // Otherwise get the active source and look for it from the device list
- ActiveSource activeSource = getLocalActiveSource();
- // If the physical address is not set yet, return null
- if (activeSource.physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS) {
- return null;
- }
- if (audioSystem() != null) {
- for (HdmiDeviceInfo info : mHdmiCecNetwork.getSafeCecDevicesLocked()) {
- if (info.getPhysicalAddress() == activeSource.physicalAddress) {
- return info;
- }
- }
- }
- // If the device info is not in the list yet, return a device info with minimum
- // information from mActiveSource.
- // If the Active Source has unregistered logical address, return with an
- // HdmiDeviceInfo built from physical address information only.
- return HdmiUtils.isValidAddress(activeSource.logicalAddress)
- ?
- new HdmiDeviceInfo(activeSource.logicalAddress,
- activeSource.physicalAddress,
- pathToPortId(activeSource.physicalAddress),
- HdmiUtils.getTypeFromAddress(activeSource.logicalAddress).get(0), 0,
- HdmiUtils.getDefaultDeviceName(activeSource.logicalAddress))
- :
- new HdmiDeviceInfo(activeSource.physicalAddress,
- pathToPortId(activeSource.physicalAddress));
- }
- return null;
- }
- ActiveSource activeSource = tv.getActiveSource();
- if (activeSource.isValid()) {
- return new HdmiDeviceInfo(activeSource.logicalAddress,
- activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID,
- HdmiDeviceInfo.DEVICE_INACTIVE, 0, "");
- }
- int activePath = tv.getActivePath();
- if (activePath != HdmiDeviceInfo.PATH_INVALID) {
- HdmiDeviceInfo info = mHdmiCecNetwork.getSafeDeviceInfoByPath(activePath);
- return (info != null) ? info : new HdmiDeviceInfo(activePath, tv.getActivePortId());
- }
- return null;
+ return HdmiControlService.this.getActiveSource();
}
@Override
@@ -2222,7 +2190,6 @@ public class HdmiControlService extends SystemService {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) return;
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
- pw.println("mCecVersion: " + mCecVersion);
pw.println("mProhibitMode: " + mProhibitMode);
pw.println("mPowerStatus: " + mPowerStatus);
@@ -2242,9 +2209,15 @@ public class HdmiControlService extends SystemService {
List<String> allSettings = hdmiCecConfig.getAllSettings();
Set<String> userSettings = new HashSet<>(hdmiCecConfig.getUserSettings());
for (String setting : allSettings) {
- pw.println(setting + ": " + hdmiCecConfig.getValue(setting)
- + " (default: " + hdmiCecConfig.getDefaultValue(setting) + ")"
- + (userSettings.contains(setting) ? " [modifiable]" : ""));
+ if (hdmiCecConfig.isStringValueType(setting)) {
+ pw.println(setting + " (string): " + hdmiCecConfig.getStringValue(setting)
+ + " (default: " + hdmiCecConfig.getDefaultStringValue(setting) + ")"
+ + (userSettings.contains(setting) ? " [modifiable]" : ""));
+ } else if (hdmiCecConfig.isIntValueType(setting)) {
+ pw.println(setting + " (int): " + hdmiCecConfig.getIntValue(setting)
+ + " (default: " + hdmiCecConfig.getDefaultIntValue(setting) + ")"
+ + (userSettings.contains(setting) ? " [modifiable]" : ""));
+ }
}
pw.decreaseIndent();
@@ -2273,33 +2246,68 @@ public class HdmiControlService extends SystemService {
}
@Override
- public List<String> getAllowedCecSettingValues(String name) {
+ public List<String> getAllowedCecSettingStringValues(String name) {
+ enforceAccessPermission();
+ long token = Binder.clearCallingIdentity();
+ try {
+ return HdmiControlService.this.getHdmiCecConfig().getAllowedStringValues(name);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public int[] getAllowedCecSettingIntValues(String name) {
+ enforceAccessPermission();
+ long token = Binder.clearCallingIdentity();
+ try {
+ List<Integer> allowedValues =
+ HdmiControlService.this.getHdmiCecConfig().getAllowedIntValues(name);
+ return allowedValues.stream().mapToInt(i->i).toArray();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public String getCecSettingStringValue(String name) {
enforceAccessPermission();
long token = Binder.clearCallingIdentity();
try {
- return HdmiControlService.this.getHdmiCecConfig().getAllowedValues(name);
+ return HdmiControlService.this.getHdmiCecConfig().getStringValue(name);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
- public String getCecSettingValue(String name) {
+ public void setCecSettingStringValue(String name, String value) {
enforceAccessPermission();
long token = Binder.clearCallingIdentity();
try {
- return HdmiControlService.this.getHdmiCecConfig().getValue(name);
+ HdmiControlService.this.getHdmiCecConfig().setStringValue(name, value);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
- public void setCecSettingValue(String name, String value) {
+ public int getCecSettingIntValue(String name) {
enforceAccessPermission();
long token = Binder.clearCallingIdentity();
try {
- HdmiControlService.this.getHdmiCecConfig().setValue(name, value);
+ return HdmiControlService.this.getHdmiCecConfig().getIntValue(name);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void setCecSettingIntValue(String name, int value) {
+ enforceAccessPermission();
+ long token = Binder.clearCallingIdentity();
+ try {
+ HdmiControlService.this.getHdmiCecConfig().setIntValue(name, value);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2372,6 +2380,39 @@ public class HdmiControlService extends SystemService {
source.queryDisplayStatus(callback);
}
+ protected HdmiDeviceInfo getActiveSource() {
+ // If a the device is a playback device that is the current active source, return the
+ // local device info
+ if (playback() != null && playback().isActiveSource()) {
+ return playback().getDeviceInfo();
+ }
+
+ // Otherwise get the active source and look for it from the device list
+ ActiveSource activeSource = getLocalActiveSource();
+
+ if (activeSource.isValid()) {
+ HdmiDeviceInfo activeSourceInfo = mHdmiCecNetwork.getSafeCecDeviceInfo(
+ activeSource.logicalAddress);
+ if (activeSourceInfo != null) {
+ return activeSourceInfo;
+ }
+
+ return new HdmiDeviceInfo(activeSource.physicalAddress,
+ pathToPortId(activeSource.physicalAddress));
+ }
+
+ if (tv() != null) {
+ int activePath = tv().getActivePath();
+ if (activePath != HdmiDeviceInfo.PATH_INVALID) {
+ HdmiDeviceInfo info = mHdmiCecNetwork.getSafeDeviceInfoByPath(activePath);
+ return (info != null) ? info : new HdmiDeviceInfo(activePath,
+ tv().getActivePortId());
+ }
+ }
+
+ return null;
+ }
+
private void addHdmiControlStatusChangeListener(
final IHdmiControlStatusChangeListener listener) {
final HdmiControlStatusChangeListenerRecord record =
@@ -2852,14 +2893,26 @@ public class HdmiControlService extends SystemService {
}
@ServiceThreadOnly
- private void onWakeUp() {
+ private void onWakeUp(@WakeReason final int wakeUpAction) {
assertRunOnServiceThread();
mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON;
if (mCecController != null) {
if (mHdmiControlEnabled) {
- int startReason = INITIATED_BY_SCREEN_ON;
- if (mWakeUpMessageReceived) {
- startReason = INITIATED_BY_WAKE_UP_MESSAGE;
+ int startReason = -1;
+ switch (wakeUpAction) {
+ case WAKE_UP_SCREEN_ON:
+ startReason = INITIATED_BY_SCREEN_ON;
+ if (mWakeUpMessageReceived) {
+ startReason = INITIATED_BY_WAKE_UP_MESSAGE;
+ }
+ break;
+ case WAKE_UP_BOOT_UP:
+ startReason = INITIATED_BY_BOOT_UP;
+ break;
+ default:
+ Slog.e(TAG, "wakeUpAction " + wakeUpAction + " not defined.");
+ return;
+
}
initializeCec(startReason);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index 45aaa73b757b..cdc28e687316 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -21,6 +21,7 @@ import static com.android.server.hdmi.Constants.ADDR_BACKUP_2;
import static com.android.server.hdmi.Constants.ADDR_TV;
import android.annotation.Nullable;
+import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.util.Slog;
import android.util.SparseArray;
@@ -134,7 +135,7 @@ final class HdmiUtils {
static boolean isEligibleAddressForCecVersion(int cecVersion, int logicalAddress) {
if (isValidAddress(logicalAddress)) {
if (logicalAddress == ADDR_BACKUP_1 || logicalAddress == ADDR_BACKUP_2) {
- return cecVersion == Constants.VERSION_2_0;
+ return cecVersion >= HdmiControlManager.HDMI_CEC_VERSION_2_0;
}
return true;
}
diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
index 0011387f1c28..d5761e170d1a 100644
--- a/services/core/java/com/android/server/hdmi/VolumeControlAction.java
+++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
@@ -138,7 +138,6 @@ final class VolumeControlAction extends HdmiCecFeatureAction {
}
private boolean handleReportAudioStatus(HdmiCecMessage cmd) {
- byte params[] = cmd.getParams();
boolean mute = HdmiUtils.isAudioStatusMute(cmd);
int volume = HdmiUtils.getAudioStatusVolume(cmd);
mLastAvrVolume = volume;
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 3f4ddea22a24..9658800fe952 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -2095,7 +2095,7 @@ public class InputManagerService extends IInputManager.Stub
DisplayThread.getHandler().post(() ->
Toast.makeText(mContext,
"Touch obscured by " + packageName
- + " will be blocked. Check go/s-untrusted-touches",
+ + " will be blocked. Check go/untrusted-touches",
Toast.LENGTH_SHORT).show());
}
diff --git a/services/core/java/com/android/server/input/InputShellCommand.java b/services/core/java/com/android/server/input/InputShellCommand.java
index 51e6cf413074..d08980cfbf24 100644
--- a/services/core/java/com/android/server/input/InputShellCommand.java
+++ b/services/core/java/com/android/server/input/InputShellCommand.java
@@ -48,6 +48,8 @@ public class InputShellCommand extends ShellCommand {
private static final float DEFAULT_PRECISION_X = 1.0f;
private static final float DEFAULT_PRECISION_Y = 1.0f;
private static final int DEFAULT_EDGE_FLAGS = 0;
+ private static final int DEFAULT_BUTTON_STATE = 0;
+ private static final int DEFAULT_FLAGS = 0;
private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{
put("keyboard", InputDevice.SOURCE_KEYBOARD);
@@ -110,15 +112,28 @@ public class InputShellCommand extends ShellCommand {
*/
private void injectMotionEvent(int inputSource, int action, long downTime, long when,
float x, float y, float pressure, int displayId) {
- MotionEvent event = MotionEvent.obtain(downTime, when, action, x, y, pressure,
- DEFAULT_SIZE, DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y,
- getInputDeviceId(inputSource), DEFAULT_EDGE_FLAGS);
- event.setSource(inputSource);
+ final int pointerCount = 1;
+ MotionEvent.PointerProperties[] pointerProperties =
+ new MotionEvent.PointerProperties[pointerCount];
+ MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[pointerCount];
+ for (int i = 0; i < pointerCount; i++) {
+ pointerProperties[i] = new MotionEvent.PointerProperties();
+ pointerProperties[i].id = i;
+ pointerProperties[i].toolType = getToolType(inputSource);
+ pointerCoords[i] = new MotionEvent.PointerCoords();
+ pointerCoords[i].x = x;
+ pointerCoords[i].y = y;
+ pointerCoords[i].pressure = pressure;
+ pointerCoords[i].size = DEFAULT_SIZE;
+ }
if (displayId == INVALID_DISPLAY
&& (inputSource & InputDevice.SOURCE_CLASS_POINTER) != 0) {
displayId = DEFAULT_DISPLAY;
}
- event.setDisplayId(displayId);
+ MotionEvent event = MotionEvent.obtain(downTime, when, action, pointerCount,
+ pointerProperties, pointerCoords, DEFAULT_META_STATE, DEFAULT_BUTTON_STATE,
+ DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, getInputDeviceId(inputSource),
+ DEFAULT_EDGE_FLAGS, inputSource, displayId, DEFAULT_FLAGS);
InputManager.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
@@ -131,6 +146,25 @@ public class InputShellCommand extends ShellCommand {
return inputSource == InputDevice.SOURCE_UNKNOWN ? defaultSource : inputSource;
}
+ private int getToolType(int inputSource) {
+ switch(inputSource) {
+ case InputDevice.SOURCE_MOUSE:
+ case InputDevice.SOURCE_MOUSE_RELATIVE:
+ case InputDevice.SOURCE_TRACKBALL:
+ return MotionEvent.TOOL_TYPE_MOUSE;
+
+ case InputDevice.SOURCE_STYLUS:
+ case InputDevice.SOURCE_BLUETOOTH_STYLUS:
+ return MotionEvent.TOOL_TYPE_STYLUS;
+
+ case InputDevice.SOURCE_TOUCHPAD:
+ case InputDevice.SOURCE_TOUCHSCREEN:
+ case InputDevice.SOURCE_TOUCH_NAVIGATION:
+ return MotionEvent.TOOL_TYPE_FINGER;
+ }
+ return MotionEvent.TOOL_TYPE_UNKNOWN;
+ }
+
@Override
public final int onCommand(String cmd) {
String arg = cmd;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 9a60afb7be68..6dd91e533a87 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -15,6 +15,7 @@
package com.android.server.inputmethod;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.server.inputmethod.InputMethodManagerServiceProto.ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD;
import static android.server.inputmethod.InputMethodManagerServiceProto.BACK_DISPOSITION;
import static android.server.inputmethod.InputMethodManagerServiceProto.BOUND_TO_METHOD;
@@ -110,6 +111,7 @@ import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
@@ -936,7 +938,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
* <p>TODO: Consider to follow what other system services have been doing to manage
* constants (e.g. {@link android.provider.Settings.Global#ACTIVITY_MANAGER_CONSTANTS}).</p>
*/
- private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 16;
+ private final static int ENTRY_SIZE_FOR_HIGH_RAM_DEVICE = 32;
/**
* Entry size for non low-RAM devices.
@@ -3106,6 +3108,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public boolean showSoftInput(IInputMethodClient client, IBinder windowToken, int flags,
ResultReceiver resultReceiver) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
int uid = Binder.getCallingUid();
synchronized (mMethodMap) {
if (!calledFromValidUserLocked()) {
@@ -3133,6 +3136,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
SoftInputShowHideReason.SHOW_SOFT_INPUT);
} finally {
Binder.restoreCallingIdentity(ident);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
}
@@ -3225,6 +3229,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
final long ident = Binder.clearCallingIdentity();
try {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideSoftInput");
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
// We need to check if this is the current client with
@@ -3248,6 +3253,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
SoftInputShowHideReason.HIDE_SOFT_INPUT);
} finally {
Binder.restoreCallingIdentity(ident);
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
}
@@ -3310,43 +3316,52 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Slog.e(TAG, "windowToken cannot be null.");
return InputBindResult.NULL;
}
- final int callingUserId = UserHandle.getCallingUserId();
- final int userId;
- if (attribute != null && attribute.targetInputMethodUser != null
- && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
- mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "Using EditorInfo.targetInputMethodUser requires INTERACT_ACROSS_USERS_FULL.");
- userId = attribute.targetInputMethodUser.getIdentifier();
- if (!mUserManagerInternal.isUserRunning(userId)) {
- // There is a chance that we hit here because of race condition. Let's just return
- // an error code instead of crashing the caller process, which at least has
- // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
- Slog.e(TAG, "User #" + userId + " is not running.");
- return InputBindResult.INVALID_USER;
+ try {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
+ "IMMS.startInputOrWindowGainedFocus");
+ final int callingUserId = UserHandle.getCallingUserId();
+ final int userId;
+ if (attribute != null && attribute.targetInputMethodUser != null
+ && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
+ mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "Using EditorInfo.targetInputMethodUser requires"
+ + " INTERACT_ACROSS_USERS_FULL.");
+ userId = attribute.targetInputMethodUser.getIdentifier();
+ if (!mUserManagerInternal.isUserRunning(userId)) {
+ // There is a chance that we hit here because of race condition. Let's just
+ // return an error code instead of crashing the caller process, which at least
+ // has INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important
+ // process.
+ Slog.e(TAG, "User #" + userId + " is not running.");
+ return InputBindResult.INVALID_USER;
+ }
+ } else {
+ userId = callingUserId;
}
- } else {
- userId = callingUserId;
- }
- final InputBindResult result;
- synchronized (mMethodMap) {
- final long ident = Binder.clearCallingIdentity();
- try {
- result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
- windowToken, startInputFlags, softInputMode, windowFlags, attribute,
- inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
+ final InputBindResult result;
+ synchronized (mMethodMap) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
+ windowToken, startInputFlags, softInputMode, windowFlags, attribute,
+ inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
+ if (result == null) {
+ // This must never happen, but just in case.
+ Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
+ + InputMethodDebug.startInputReasonToString(startInputReason)
+ + " windowFlags=#" + Integer.toHexString(windowFlags)
+ + " editorInfo=" + attribute);
+ return InputBindResult.NULL;
+ }
+
+ return result;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
- if (result == null) {
- // This must never happen, but just in case.
- Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
- + InputMethodDebug.startInputReasonToString(startInputReason)
- + " windowFlags=#" + Integer.toHexString(windowFlags)
- + " editorInfo=" + attribute);
- return InputBindResult.NULL;
- }
- return result;
}
@NonNull
@@ -4124,6 +4139,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
private void applyImeVisibility(IBinder token, IBinder windowToken, boolean setVisible) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.applyImeVisibility");
synchronized (mMethodMap) {
if (!calledWithValidTokenLocked(token)) {
return;
@@ -4145,6 +4161,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mWindowManagerInternal.showImePostLayout(mShowRequestWindowMap.get(windowToken));
}
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
@@ -4172,6 +4189,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@BinderThread
private void hideMySoftInput(@NonNull IBinder token, int flags) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideMySoftInput");
synchronized (mMethodMap) {
if (!calledWithValidTokenLocked(token)) {
return;
@@ -4186,10 +4204,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Binder.restoreCallingIdentity(ident);
}
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@BinderThread
private void showMySoftInput(@NonNull IBinder token, int flags) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showMySoftInput");
synchronized (mMethodMap) {
if (!calledWithValidTokenLocked(token)) {
return;
@@ -4202,6 +4222,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Binder.restoreCallingIdentity(ident);
}
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
void setEnabledSessionInMainThread(SessionState session) {
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index ac9b7ea0d808..d624019bfec8 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -554,8 +554,8 @@ public class LightsService extends SystemService {
@Override
public synchronized ILights get() {
if (mInstance == null) {
- IBinder binder = Binder.allowBlocking(ServiceManager.waitForDeclaredService(
- "android.hardware.light.ILights/default"));
+ IBinder binder = Binder.allowBlocking(
+ ServiceManager.waitForDeclaredService(ILights.DESCRIPTOR + "/default"));
if (binder != null) {
mInstance = ILights.Stub.asInterface(binder);
try {
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index bd2676e60825..fac7952fb86a 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -17,7 +17,7 @@
package com.android.server.location;
import android.annotation.Nullable;
-import android.location.Location;
+import android.location.LocationResult;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.Bundle;
@@ -27,8 +27,6 @@ import com.android.internal.location.ProviderRequest;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
@@ -56,13 +54,7 @@ public abstract class AbstractLocationProvider {
* Called when a provider has a new location available. May be invoked from any thread. Will
* be invoked with a cleared binder identity.
*/
- void onReportLocation(Location location);
-
- /**
- * Called when a provider has a new location available. May be invoked from any thread. Will
- * be invoked with a cleared binder identity.
- */
- void onReportLocation(List<Location> locations);
+ void onReportLocation(LocationResult locationResult);
}
/**
@@ -302,33 +294,12 @@ public abstract class AbstractLocationProvider {
/**
* Call this method to report a new location.
*/
- protected void reportLocation(Location location) {
- Listener listener = mInternalState.get().listener;
- if (listener != null) {
- final long identity = Binder.clearCallingIdentity();
- try {
- // copy location so if provider makes further changes they do not propagate
- listener.onReportLocation(new Location(location));
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- /**
- * Call this method to report a new location.
- */
- protected void reportLocation(List<Location> locations) {
+ protected void reportLocation(LocationResult locationResult) {
Listener listener = mInternalState.get().listener;
if (listener != null) {
final long identity = Binder.clearCallingIdentity();
try {
- // copy location so if provider makes further changes they do not propagate
- ArrayList<Location> copy = new ArrayList<>(locations.size());
- for (Location location : locations) {
- copy.add(new Location(location));
- }
- listener.onReportLocation(copy);
+ listener.onReportLocation(Objects.requireNonNull(locationResult));
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -339,6 +310,7 @@ public abstract class AbstractLocationProvider {
* Sets a new request and worksource for the provider.
*/
public final void setRequest(ProviderRequest request) {
+ // TODO: do we want to hold a wakelock until onSetRequest is run?
// all calls into the provider must be moved onto the provider thread to prevent deadlock
mExecutor.execute(() -> onSetRequest(request));
}
@@ -349,6 +321,23 @@ public abstract class AbstractLocationProvider {
protected abstract void onSetRequest(ProviderRequest request);
/**
+ * Requests that any applicable locations are flushed. Normally only relevant for batched
+ * locations.
+ */
+ public final void flush(Runnable listener) {
+ // all calls into the provider must be moved onto the provider thread to prevent deadlock
+ mExecutor.execute(() -> onFlush(listener));
+ }
+
+ /**
+ * Always invoked on the provider executor. The callback must always be invoked exactly once
+ * for every invocation, and should only be invoked after
+ * {@link #reportLocation(LocationResult)} has been called for every flushed location. If no
+ * locations are flushed, the callback may be invoked immediately.
+ */
+ protected abstract void onFlush(Runnable callback);
+
+ /**
* Sends an extra command to the provider for it to interpret as it likes.
*/
public final void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index 3b74d5a82a2a..3ac148ddab1b 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -60,7 +60,11 @@ public class GeocoderProxy {
}
private boolean register() {
- return mServiceWatcher.register();
+ boolean resolves = mServiceWatcher.checkServiceResolves();
+ if (resolves) {
+ mServiceWatcher.register();
+ }
+ return resolves;
}
/**
diff --git a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
index eed1aac79166..7b400b6e0309 100644
--- a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
+++ b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
@@ -75,7 +75,11 @@ public class HardwareActivityRecognitionProxy {
}
private boolean register() {
- return mServiceWatcher.register();
+ boolean resolves = mServiceWatcher.checkServiceResolves();
+ if (resolves) {
+ mServiceWatcher.register();
+ }
+ return resolves;
}
private void onBind(IBinder binder, ComponentName service) throws RemoteException {
diff --git a/services/core/java/com/android/server/location/LocationFudger.java b/services/core/java/com/android/server/location/LocationFudger.java
index ecdd429cd0c8..c2bfc5114e5a 100644
--- a/services/core/java/com/android/server/location/LocationFudger.java
+++ b/services/core/java/com/android/server/location/LocationFudger.java
@@ -18,6 +18,7 @@ package com.android.server.location;
import android.annotation.Nullable;
import android.location.Location;
+import android.location.LocationResult;
import android.os.SystemClock;
import com.android.internal.annotations.GuardedBy;
@@ -77,6 +78,11 @@ public class LocationFudger {
@GuardedBy("this")
@Nullable private Location mCachedCoarseLocation;
+ @GuardedBy("this")
+ @Nullable private LocationResult mCachedFineLocationResult;
+ @GuardedBy("this")
+ @Nullable private LocationResult mCachedCoarseLocationResult;
+
public LocationFudger(float accuracyM) {
this(accuracyM, SystemClock.elapsedRealtimeClock(), new SecureRandom());
}
@@ -100,6 +106,28 @@ public class LocationFudger {
}
/**
+ * Coarsens a LocationResult by coarsening every location within the location result with
+ * {@link #createCoarse(Location)}.
+ */
+ public LocationResult createCoarse(LocationResult fineLocationResult) {
+ synchronized (this) {
+ if (fineLocationResult == mCachedFineLocationResult
+ || fineLocationResult == mCachedCoarseLocationResult) {
+ return mCachedCoarseLocationResult;
+ }
+ }
+
+ LocationResult coarseLocationResult = fineLocationResult.map(this::createCoarse);
+
+ synchronized (this) {
+ mCachedFineLocationResult = fineLocationResult;
+ mCachedCoarseLocationResult = coarseLocationResult;
+ }
+
+ return coarseLocationResult;
+ }
+
+ /**
* Create a coarse location using two technique, random offsets and snap-to-grid.
*
* First we add a random offset to mitigate against detecting grid transitions. Without a random
@@ -154,7 +182,7 @@ public class LocationFudger {
mCachedCoarseLocation = coarse;
}
- return mCachedCoarseLocation;
+ return coarse;
}
/**
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 9c48d23dade6..086757f42e37 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -21,10 +21,10 @@ import static android.app.compat.CompatChanges.isChangeEnabled;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.location.LocationManager.BLOCK_PENDING_INTENT_SYSTEM_API_USAGE;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
-import static android.location.LocationManager.PREVENT_PENDING_INTENT_SYSTEM_API_USAGE;
import static android.location.LocationRequest.LOW_POWER_EXCEPTIONS;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
@@ -32,6 +32,7 @@ import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import android.Manifest;
import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -47,7 +48,6 @@ import android.location.Geofence;
import android.location.GnssCapabilities;
import android.location.GnssMeasurementCorrections;
import android.location.GnssRequest;
-import android.location.IBatchedLocationCallback;
import android.location.IGeocodeListener;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
@@ -219,6 +219,10 @@ public class LocationManagerService extends ILocationManager.Stub {
private volatile @Nullable GnssManagerService mGnssManagerService = null;
private GeocoderProxy mGeocodeProvider;
+ private final Object mDeprecatedGnssBatchingLock = new Object();
+ @GuardedBy("mDeprecatedGnssBatchingLock")
+ private @Nullable ILocationListener mDeprecatedGnssBatchingListener;
+
@GuardedBy("mLock")
private String mExtraLocationControllerPackage;
@GuardedBy("mLock")
@@ -245,7 +249,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// set up passive provider first since it will be required for all other location providers,
// which are loaded later once the system is ready.
mPassiveManager = new PassiveLocationProviderManager(mContext, injector);
- addLocationProviderManager(mPassiveManager, new PassiveProvider(mContext));
+ addLocationProviderManager(mPassiveManager, new PassiveLocationProvider(mContext));
// TODO: load the gps provider here as well, which will require refactoring
@@ -320,7 +324,9 @@ public class LocationManagerService extends ILocationManager.Stub {
}
void onSystemThirdPartyAppsCanStart() {
- LocationProviderProxy networkProvider = LocationProviderProxy.createAndRegister(
+ // network provider should always be initialized before the gps provider since the gps
+ // provider has unfortunate hard dependencies on the network provider
+ ProxyLocationProvider networkProvider = ProxyLocationProvider.createAndRegister(
mContext,
NETWORK_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableNetworkLocationOverlay,
@@ -339,7 +345,7 @@ public class LocationManagerService extends ILocationManager.Stub {
MATCH_DIRECT_BOOT_AWARE | MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM).isEmpty(),
"Unable to find a direct boot aware fused location provider");
- LocationProviderProxy fusedProvider = LocationProviderProxy.createAndRegister(
+ ProxyLocationProvider fusedProvider = ProxyLocationProvider.createAndRegister(
mContext,
FUSED_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableFusedLocationOverlay,
@@ -404,7 +410,7 @@ public class LocationManagerService extends ILocationManager.Stub {
Integer.parseInt(fragments[8]) /* powerRequirement */,
Integer.parseInt(fragments[9]) /* accuracy */);
getOrAddLocationProviderManager(name).setMockProvider(
- new MockProvider(properties, CallerIdentity.fromContext(mContext)));
+ new MockLocationProvider(properties, CallerIdentity.fromContext(mContext)));
}
}
@@ -442,40 +448,63 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public void setGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
- String attributionTag) {
- if (mGnssManagerService != null) {
- mGnssManagerService.setGnssBatchingCallback(callback, packageName, attributionTag);
- }
- }
+ public void startGnssBatch(long periodNanos, ILocationListener listener, String packageName,
+ String attributionTag, String listenerId) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
- @Override
- public void removeGnssBatchingCallback() {
- if (mGnssManagerService != null) {
- mGnssManagerService.removeGnssBatchingCallback();
+ if (mGnssManagerService == null) {
+ return;
}
- }
- @Override
- public void startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName,
- String attributionTag) {
- if (mGnssManagerService != null) {
- mGnssManagerService.startGnssBatch(periodNanos, wakeOnFifoFull, packageName,
- attributionTag);
+ long intervalMs = NANOSECONDS.toMillis(periodNanos);
+
+ synchronized (mDeprecatedGnssBatchingLock) {
+ stopGnssBatch();
+
+ registerLocationListener(
+ GPS_PROVIDER,
+ new LocationRequest.Builder(intervalMs)
+ .setMaxUpdateDelayMillis(
+ intervalMs * mGnssManagerService.getGnssBatchSize())
+ .setHiddenFromAppOps(true)
+ .build(),
+ listener,
+ packageName,
+ attributionTag,
+ listenerId);
+ mDeprecatedGnssBatchingListener = listener;
}
}
@Override
public void flushGnssBatch() {
- if (mGnssManagerService != null) {
- mGnssManagerService.flushGnssBatch();
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
+
+ if (mGnssManagerService == null) {
+ return;
+ }
+
+ synchronized (mDeprecatedGnssBatchingLock) {
+ if (mDeprecatedGnssBatchingListener != null) {
+ requestListenerFlush(GPS_PROVIDER, mDeprecatedGnssBatchingListener, 0);
+ }
}
}
@Override
public void stopGnssBatch() {
- if (mGnssManagerService != null) {
- mGnssManagerService.stopGnssBatch();
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
+
+ if (mGnssManagerService == null) {
+ return;
+ }
+
+ synchronized (mDeprecatedGnssBatchingLock) {
+ if (mDeprecatedGnssBatchingListener != null) {
+ ILocationListener listener = mDeprecatedGnssBatchingListener;
+ mDeprecatedGnssBatchingListener = null;
+ unregisterLocationListener(listener);
+ }
}
}
@@ -597,14 +626,15 @@ public class LocationManagerService extends ILocationManager.Stub {
// simplest to ensure these apis are simply never set for pending intent requests. the same
// does not apply for listener requests since those will have the process (including the
// listener) killed on permission removal
- boolean usesSystemApi = request.isLowPower()
- || request.isHiddenFromAppOps()
- || request.isLocationSettingsIgnored()
- || !request.getWorkSource().isEmpty();
- if (usesSystemApi
- && isChangeEnabled(PREVENT_PENDING_INTENT_SYSTEM_API_USAGE, identity.getUid())) {
- throw new SecurityException(
- "PendingIntent location requests may not use system APIs: " + request);
+ if (isChangeEnabled(BLOCK_PENDING_INTENT_SYSTEM_API_USAGE, identity.getUid())) {
+ boolean usesSystemApi = request.isLowPower()
+ || request.isHiddenFromAppOps()
+ || request.isLocationSettingsIgnored()
+ || !request.getWorkSource().isEmpty();
+ if (usesSystemApi) {
+ throw new SecurityException(
+ "PendingIntent location requests may not use system APIs: " + request);
+ }
}
request = validateLocationRequest(request, identity);
@@ -672,6 +702,25 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
+ public void requestListenerFlush(String provider, ILocationListener listener, int requestCode) {
+ LocationProviderManager manager = getLocationProviderManager(provider);
+ Preconditions.checkArgument(manager != null,
+ "provider \"" + provider + "\" does not exist");
+
+ manager.flush(Objects.requireNonNull(listener), requestCode);
+ }
+
+ @Override
+ public void requestPendingIntentFlush(String provider, PendingIntent pendingIntent,
+ int requestCode) {
+ LocationProviderManager manager = getLocationProviderManager(provider);
+ Preconditions.checkArgument(manager != null,
+ "provider \"" + provider + "\" does not exist");
+
+ manager.flush(Objects.requireNonNull(pendingIntent), requestCode);
+ }
+
+ @Override
public void unregisterLocationListener(ILocationListener listener) {
for (LocationProviderManager manager : mProviderManagers) {
manager.unregisterLocationRequest(listener);
@@ -987,9 +1036,13 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void getFromLocation(double latitude, double longitude, int maxResults,
GeocoderParams params, IGeocodeListener listener) {
+ // validate identity
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, params.getClientPackage(),
+ params.getClientAttributionTag());
+ Preconditions.checkArgument(identity.getUid() == params.getClientUid());
+
if (mGeocodeProvider != null) {
- mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
- params, listener);
+ mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, params, listener);
} else {
try {
listener.onResults(null, Collections.emptyList());
@@ -1004,6 +1057,11 @@ public class LocationManagerService extends ILocationManager.Stub {
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude, int maxResults,
GeocoderParams params, IGeocodeListener listener) {
+ // validate identity
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, params.getClientPackage(),
+ params.getClientAttributionTag());
+ Preconditions.checkArgument(identity.getUid() == params.getClientUid());
+
if (mGeocodeProvider != null) {
mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
@@ -1027,7 +1085,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
getOrAddLocationProviderManager(provider).setMockProvider(
- new MockProvider(properties, identity));
+ new MockLocationProvider(properties, identity));
}
@Override
@@ -1208,13 +1266,6 @@ public class LocationManagerService extends ILocationManager.Stub {
mGnssManagerService.sendNiResponse(notifId, userResponse);
}
}
-
- @Override
- public void reportGnssBatchLocations(List<Location> locations) {
- if (mGnssManagerService != null) {
- mGnssManagerService.onReportLocation(locations);
- }
- }
}
private static class SystemInjector implements Injector {
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index f8d1195be7fd..b0b5575da359 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -20,7 +20,9 @@ import static android.app.compat.CompatChanges.isChangeEnabled;
import static android.location.LocationManager.DELIVER_HISTORICAL_LOCATIONS;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
+import static android.location.LocationManager.KEY_FLUSH_COMPLETE;
import static android.location.LocationManager.KEY_LOCATION_CHANGED;
+import static android.location.LocationManager.KEY_LOCATION_RESULT;
import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
import static android.location.LocationManager.PASSIVE_PROVIDER;
import static android.os.IPowerManager.LOCATION_MODE_NO_CHANGE;
@@ -52,6 +54,7 @@ import android.location.LocationManager;
import android.location.LocationManagerInternal;
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.LocationRequest;
+import android.location.LocationResult;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.Build;
@@ -112,8 +115,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
import java.util.Objects;
+import java.util.function.Predicate;
class LocationProviderManager extends
ListenerMultiplexer<Object, LocationProviderManager.LocationTransport,
@@ -155,8 +158,9 @@ class LocationProviderManager extends
protected interface LocationTransport {
- void deliverOnLocationChanged(Location location, @Nullable Runnable onCompleteCallback)
- throws Exception;
+ void deliverOnLocationChanged(LocationResult locationResult,
+ @Nullable Runnable onCompleteCallback) throws Exception;
+ void deliverOnFlushComplete(int requestCode) throws Exception;
}
protected interface ProviderTransport {
@@ -174,9 +178,14 @@ class LocationProviderManager extends
}
@Override
- public void deliverOnLocationChanged(Location location,
+ public void deliverOnLocationChanged(LocationResult locationResult,
@Nullable Runnable onCompleteCallback) throws RemoteException {
- mListener.onLocationChanged(location, SingleUseCallback.wrap(onCompleteCallback));
+ mListener.onLocationChanged(locationResult, SingleUseCallback.wrap(onCompleteCallback));
+ }
+
+ @Override
+ public void deliverOnFlushComplete(int requestCode) throws RemoteException {
+ mListener.onFlushComplete(requestCode);
}
@Override
@@ -198,12 +207,26 @@ class LocationProviderManager extends
}
@Override
- public void deliverOnLocationChanged(Location location,
+ public void deliverOnLocationChanged(LocationResult locationResult,
@Nullable Runnable onCompleteCallback)
throws PendingIntent.CanceledException {
- mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_LOCATION_CHANGED, location),
+ mPendingIntent.send(
+ mContext,
+ 0,
+ new Intent()
+ .putExtra(KEY_LOCATION_CHANGED, locationResult.getLastLocation())
+ .putExtra(KEY_LOCATION_RESULT, locationResult),
onCompleteCallback != null ? (pI, i, rC, rD, rE) -> onCompleteCallback.run()
- : null, null, null,
+ : null,
+ null,
+ null,
+ PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
+ }
+
+ @Override
+ public void deliverOnFlushComplete(int requestCode) throws PendingIntent.CanceledException {
+ mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_FLUSH_COMPLETE, requestCode),
+ null, null, null,
PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
}
@@ -225,13 +248,20 @@ class LocationProviderManager extends
}
@Override
- public void deliverOnLocationChanged(Location location,
+ public void deliverOnLocationChanged(@Nullable LocationResult locationResult,
@Nullable Runnable onCompleteCallback)
throws RemoteException {
// ILocationCallback doesn't currently support completion callbacks
Preconditions.checkState(onCompleteCallback == null);
- mCallback.onLocation(location);
+ if (locationResult != null) {
+ mCallback.onLocation(locationResult.getLastLocation());
+ } else {
+ mCallback.onLocation(null);
+ }
}
+
+ @Override
+ public void deliverOnFlushComplete(int requestCode) {}
}
protected abstract class Registration extends RemoteListenerRegistration<LocationRequest,
@@ -377,6 +407,14 @@ class LocationProviderManager extends
return mPermitted;
}
+ public final void flush(int requestCode) {
+ // when the flush callback is invoked, we are guaranteed that locations have been
+ // queued on our executor, so by running the listener callback on the same executor it
+ // should be guaranteed that those locations will be delivered before the flush callback
+ mProvider.flush(() -> executeOperation(
+ listener -> listener.deliverOnFlushComplete(requestCode)));
+ }
+
@Override
protected final LocationProviderManager getOwner() {
return LocationProviderManager.this;
@@ -539,7 +577,7 @@ class LocationProviderManager extends
@GuardedBy("mLock")
abstract @Nullable ListenerOperation<LocationTransport> acceptLocationChange(
- Location fineLocation);
+ LocationResult fineLocationResult);
@Override
public String toString() {
@@ -668,7 +706,7 @@ class LocationProviderManager extends
getRequest().isLocationSettingsIgnored(),
maxLocationAgeMs);
if (lastLocation != null) {
- executeOperation(acceptLocationChange(lastLocation));
+ executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
}
}
}
@@ -677,22 +715,21 @@ class LocationProviderManager extends
@Override
public void onAlarm() {
if (D) {
- Log.d(TAG, "removing " + getIdentity() + " from " + mName
- + " provider due to expiration at " + TimeUtils.formatRealtime(
- mExpirationRealtimeMs));
+ Log.d(TAG, mName + " provider registration " + getIdentity()
+ + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
}
synchronized (mLock) {
- remove();
// no need to remove alarm after it's fired
mExpirationRealtimeMs = Long.MAX_VALUE;
+ remove();
}
}
@GuardedBy("mLock")
@Override
@Nullable ListenerOperation<LocationTransport> acceptLocationChange(
- Location fineLocation) {
+ LocationResult fineLocationResult) {
if (Build.IS_DEBUGGABLE) {
Preconditions.checkState(Thread.holdsLock(mLock));
}
@@ -700,30 +737,52 @@ class LocationProviderManager extends
// check expiration time - alarm is not guaranteed to go off at the right time,
// especially for short intervals
if (SystemClock.elapsedRealtime() >= mExpirationRealtimeMs) {
+ if (D) {
+ Log.d(TAG, mName + " provider registration " + getIdentity()
+ + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
+ }
remove();
return null;
}
- Location location = Objects.requireNonNull(
- getPermittedLocation(fineLocation, getPermissionLevel()));
+ LocationResult permittedLocationResult = Objects.requireNonNull(
+ getPermittedLocationResult(fineLocationResult, getPermissionLevel()));
+
+ LocationResult locationResult = permittedLocationResult.filter(
+ new Predicate<Location>() {
+ private Location mPreviousLocation = getLastDeliveredLocation();
+
+ @Override
+ public boolean test(Location location) {
+ if (mPreviousLocation != null) {
+ // check fastest interval
+ long deltaMs = location.getElapsedRealtimeMillis()
+ - mPreviousLocation.getElapsedRealtimeMillis();
+ long maxJitterMs = min((long) (FASTEST_INTERVAL_JITTER_PERCENTAGE
+ * getRequest().getIntervalMillis()),
+ MAX_FASTEST_INTERVAL_JITTER_MS);
+ if (deltaMs
+ < getRequest().getMinUpdateIntervalMillis() - maxJitterMs) {
+ return false;
+ }
+
+ // check smallest displacement
+ double smallestDisplacementM =
+ getRequest().getMinUpdateDistanceMeters();
+ if (smallestDisplacementM > 0.0 && location.distanceTo(
+ mPreviousLocation)
+ <= smallestDisplacementM) {
+ return false;
+ }
+ }
- Location lastDeliveredLocation = getLastDeliveredLocation();
- if (lastDeliveredLocation != null) {
- // check fastest interval
- long deltaMs = location.getElapsedRealtimeMillis()
- - lastDeliveredLocation.getElapsedRealtimeMillis();
- long maxJitterMs = min((long) (FASTEST_INTERVAL_JITTER_PERCENTAGE
- * getRequest().getIntervalMillis()), MAX_FASTEST_INTERVAL_JITTER_MS);
- if (deltaMs < getRequest().getMinUpdateIntervalMillis() - maxJitterMs) {
- return null;
- }
+ mPreviousLocation = location;
+ return true;
+ }
+ });
- // check smallest displacement
- double smallestDisplacementM = getRequest().getMinUpdateDistanceMeters();
- if (smallestDisplacementM > 0.0 && location.distanceTo(lastDeliveredLocation)
- <= smallestDisplacementM) {
- return null;
- }
+ if (locationResult == null) {
+ return null;
}
// note app ops
@@ -742,10 +801,17 @@ class LocationProviderManager extends
@Override
public void onPreExecute() {
- mUseWakeLock = !location.isFromMockProvider();
+ mUseWakeLock = false;
+ final int size = locationResult.size();
+ for (int i = 0; i < size; ++i) {
+ if (!locationResult.get(i).isFromMockProvider()) {
+ mUseWakeLock = true;
+ break;
+ }
+ }
// update last delivered location
- setLastDeliveredLocation(location);
+ setLastDeliveredLocation(locationResult.getLastLocation());
// don't acquire a wakelock for mock locations to prevent abuse
if (mUseWakeLock) {
@@ -757,16 +823,17 @@ class LocationProviderManager extends
public void operate(LocationTransport listener) throws Exception {
// if delivering to the same process, make a copy of the location first (since
// location is mutable)
- Location deliveryLocation;
+ LocationResult deliverLocationResult;
if (getIdentity().getPid() == Process.myPid()) {
- deliveryLocation = new Location(location);
+ deliverLocationResult = locationResult.deepCopy();
} else {
- deliveryLocation = location;
+ deliverLocationResult = locationResult;
}
- listener.deliverOnLocationChanged(deliveryLocation,
+ listener.deliverOnLocationChanged(deliverLocationResult,
mUseWakeLock ? mWakeLock::release : null);
- mLocationEventLog.logProviderDeliveredLocation(mName, getIdentity());
+ mLocationEventLog.logProviderDeliveredLocations(mName, locationResult.size(),
+ getIdentity());
}
@Override
@@ -781,8 +848,8 @@ class LocationProviderManager extends
boolean remove = ++mNumLocationsDelivered >= getRequest().getMaxUpdates();
if (remove) {
if (D) {
- Log.d(TAG, "removing " + getIdentity() + " from " + mName
- + " provider due to number of updates");
+ Log.d(TAG, mName + " provider registration " + getIdentity()
+ + " finished after " + mNumLocationsDelivered + " updates");
}
synchronized (mLock) {
@@ -848,14 +915,14 @@ class LocationProviderManager extends
onTransportFailure(exception);
}
- private void onTransportFailure(Exception exception) {
- if (exception instanceof RemoteException) {
- Log.w(TAG, "registration " + this + " removed", exception);
+ private void onTransportFailure(Exception e) {
+ if (e instanceof RemoteException) {
+ Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e);
synchronized (mLock) {
remove();
}
} else {
- throw new AssertionError(exception);
+ throw new AssertionError(e);
}
}
@@ -863,7 +930,7 @@ class LocationProviderManager extends
public void binderDied() {
try {
if (D) {
- Log.d(TAG, mName + " provider client died: " + getIdentity());
+ Log.d(TAG, mName + " provider registration " + getIdentity() + " died");
}
synchronized (mLock) {
@@ -910,19 +977,23 @@ class LocationProviderManager extends
onTransportFailure(exception);
}
- private void onTransportFailure(Exception exception) {
- if (exception instanceof PendingIntent.CanceledException) {
- Log.w(TAG, "registration " + this + " removed", exception);
+ private void onTransportFailure(Exception e) {
+ if (e instanceof RemoteException) {
+ Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e);
synchronized (mLock) {
remove();
}
} else {
- throw new AssertionError(exception);
+ throw new AssertionError(e);
}
}
@Override
public void onCancelled(PendingIntent intent) {
+ if (D) {
+ Log.d(TAG, mName + " provider registration " + getIdentity() + " cancelled");
+ }
+
synchronized (mLock) {
remove();
}
@@ -932,19 +1003,11 @@ class LocationProviderManager extends
protected final class GetCurrentLocationListenerRegistration extends Registration implements
IBinder.DeathRecipient, OnAlarmListener {
- private volatile LocationTransport mTransport;
-
private long mExpirationRealtimeMs = Long.MAX_VALUE;
protected GetCurrentLocationListenerRegistration(LocationRequest request,
CallerIdentity identity, LocationTransport transport, int permissionLevel) {
super(request, identity, transport, permissionLevel);
- mTransport = transport;
- }
-
- @Override
- protected void onListenerUnregister() {
- mTransport = null;
}
@GuardedBy("mLock")
@@ -988,45 +1051,41 @@ class LocationProviderManager extends
getRequest().isLocationSettingsIgnored(),
MAX_CURRENT_LOCATION_AGE_MS);
if (lastLocation != null) {
- executeOperation(acceptLocationChange(lastLocation));
+ executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
}
}
@GuardedBy("mLock")
@Override
protected void onProviderListenerInactive() {
- if (!getRequest().isLocationSettingsIgnored()) {
- // if we go inactive for any reason, fail immediately
- executeOperation(acceptLocationChange(null));
- }
+ // if we go inactive for any reason, fail immediately
+ executeOperation(acceptLocationChange(null));
}
void deliverNull() {
synchronized (mLock) {
- executeSafely(getExecutor(), () -> mTransport, acceptLocationChange(null));
+ executeOperation(acceptLocationChange(null));
}
}
@Override
public void onAlarm() {
if (D) {
- Log.d(TAG, "removing " + getIdentity() + " from " + mName
- + " provider due to expiration at " + TimeUtils.formatRealtime(
- mExpirationRealtimeMs));
+ Log.d(TAG, mName + " provider registration " + getIdentity()
+ + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
}
synchronized (mLock) {
// no need to remove alarm after it's fired
mExpirationRealtimeMs = Long.MAX_VALUE;
-
- deliverNull();
+ executeOperation(acceptLocationChange(null));
}
}
@GuardedBy("mLock")
@Override
@Nullable ListenerOperation<LocationTransport> acceptLocationChange(
- @Nullable Location fineLocation) {
+ @Nullable LocationResult fineLocationResult) {
if (Build.IS_DEBUGGABLE) {
Preconditions.checkState(Thread.holdsLock(mLock));
}
@@ -1034,44 +1093,79 @@ class LocationProviderManager extends
// check expiration time - alarm is not guaranteed to go off at the right time,
// especially for short intervals
if (SystemClock.elapsedRealtime() >= mExpirationRealtimeMs) {
- fineLocation = null;
+ if (D) {
+ Log.d(TAG, mName + " provider registration " + getIdentity()
+ + " expired at " + TimeUtils.formatRealtime(mExpirationRealtimeMs));
+ }
+ fineLocationResult = null;
}
// lastly - note app ops
- if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(getPermissionLevel()),
- getIdentity())) {
+ if (fineLocationResult != null && !mAppOpsHelper.noteOpNoThrow(
+ LocationPermissions.asAppOp(getPermissionLevel()), getIdentity())) {
if (D) {
Log.w(TAG, "noteOp denied for " + getIdentity());
}
- fineLocation = null;
+ fineLocationResult = null;
+ }
+
+ if (fineLocationResult != null) {
+ fineLocationResult = fineLocationResult.asLastLocationResult();
}
- Location location = getPermittedLocation(fineLocation, getPermissionLevel());
+ LocationResult locationResult = getPermittedLocationResult(fineLocationResult,
+ getPermissionLevel());
// deliver location
- return listener -> {
- // if delivering to the same process, make a copy of the location first (since
- // location is mutable)
- Location deliveryLocation = location;
- if (getIdentity().getPid() == Process.myPid() && location != null) {
- deliveryLocation = new Location(location);
+ return new ListenerOperation<LocationTransport>() {
+ @Override
+ public void operate(LocationTransport listener) throws Exception {
+ // if delivering to the same process, make a copy of the location first (since
+ // location is mutable)
+ LocationResult deliverLocationResult;
+ if (getIdentity().getPid() == Process.myPid() && locationResult != null) {
+ deliverLocationResult = locationResult.deepCopy();
+ } else {
+ deliverLocationResult = locationResult;
+ }
+
+ // we currently don't hold a wakelock for getCurrentLocation deliveries
+ listener.deliverOnLocationChanged(deliverLocationResult, null);
+ mLocationEventLog.logProviderDeliveredLocations(mName,
+ locationResult != null ? locationResult.size() : 0, getIdentity());
}
- // we currently don't hold a wakelock for getCurrentLocation deliveries
- listener.deliverOnLocationChanged(deliveryLocation, null);
- mLocationEventLog.logProviderDeliveredLocation(mName, getIdentity());
+ @Override
+ public void onPostExecute(boolean success) {
+ // on failure we're automatically removed anyways, no need to attempt removal
+ // again
+ if (success) {
+ synchronized (mLock) {
+ remove();
+ }
+ }
+ }
+ };
+ }
+ @Override
+ public void onOperationFailure(ListenerOperation<LocationTransport> operation,
+ Exception e) {
+ if (e instanceof RemoteException) {
+ Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e);
synchronized (mLock) {
remove();
}
- };
+ } else {
+ throw new AssertionError(e);
+ }
}
@Override
public void binderDied() {
try {
if (D) {
- Log.d(TAG, mName + " provider client died: " + getIdentity());
+ Log.d(TAG, mName + " provider registration " + getIdentity() + " died");
}
synchronized (mLock) {
@@ -1300,7 +1394,7 @@ class LocationProviderManager extends
}
}
- public void setMockProvider(@Nullable MockProvider provider) {
+ public void setMockProvider(@Nullable MockLocationProvider provider) {
synchronized (mLock) {
Preconditions.checkState(mState != STATE_STOPPED);
@@ -1572,6 +1666,41 @@ class LocationProviderManager extends
}
}
+ public void flush(ILocationListener listener, int requestCode) {
+ synchronized (mLock) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ boolean flushed = updateRegistration(listener.asBinder(), registration -> {
+ registration.flush(requestCode);
+ return false;
+ });
+ if (!flushed) {
+ throw new IllegalArgumentException("unregistered listener cannot be flushed");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ public void flush(PendingIntent pendingIntent, int requestCode) {
+ synchronized (mLock) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ boolean flushed = updateRegistration(pendingIntent, registration -> {
+ registration.flush(requestCode);
+ return false;
+ });
+ if (!flushed) {
+ throw new IllegalArgumentException(
+ "unregistered pending intent cannot be flushed");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
public void unregisterLocationRequest(ILocationListener listener) {
synchronized (mLock) {
Preconditions.checkState(mState != STATE_STOPPED);
@@ -1820,19 +1949,22 @@ class LocationProviderManager extends
long intervalMs = ProviderRequest.INTERVAL_DISABLED;
int quality = LocationRequest.QUALITY_LOW_POWER;
+ long maxUpdateDelayMs = Long.MAX_VALUE;
boolean locationSettingsIgnored = false;
boolean lowPower = true;
for (Registration registration : registrations) {
LocationRequest request = registration.getRequest();
- // passive requests do not contribute to the provider request
+ // passive requests do not contribute to the provider request, and passive requests
+ // must handle the batching parameters of non-passive requests
if (request.getIntervalMillis() == LocationRequest.PASSIVE_INTERVAL) {
continue;
}
intervalMs = min(request.getIntervalMillis(), intervalMs);
quality = min(request.getQuality(), quality);
+ maxUpdateDelayMs = min(request.getMaxUpdateDelayMillis(), maxUpdateDelayMs);
locationSettingsIgnored |= request.isLocationSettingsIgnored();
lowPower &= request.isLowPower();
}
@@ -1841,6 +1973,11 @@ class LocationProviderManager extends
return ProviderRequest.EMPTY_REQUEST;
}
+ if (maxUpdateDelayMs / 2 < intervalMs) {
+ // reduces churn if only the batching parameter has changed
+ maxUpdateDelayMs = 0;
+ }
+
// calculate who to blame for power in a somewhat arbitrary fashion. we pick a threshold
// interval slightly higher that the minimum interval, and spread the blame across all
// contributing registrations under that threshold (since worksource does not allow us to
@@ -1864,6 +2001,7 @@ class LocationProviderManager extends
return new ProviderRequest.Builder()
.setIntervalMillis(intervalMs)
.setQuality(quality)
+ .setMaxUpdateDelayMillis(maxUpdateDelayMs)
.setLocationSettingsIgnored(locationSettingsIgnored)
.setLowPower(lowPower)
.setWorkSource(workSource)
@@ -2026,51 +2164,52 @@ class LocationProviderManager extends
@GuardedBy("mLock")
@Override
- public void onReportLocation(Location location) {
+ public void onReportLocation(LocationResult locationResult) {
if (Build.IS_DEBUGGABLE) {
Preconditions.checkState(Thread.holdsLock(mLock));
}
- // don't validate mock locations
- if (!location.isFromMockProvider()) {
- if (location.getLatitude() == 0 && location.getLongitude() == 0) {
- Log.w(TAG, "blocking 0,0 location from " + mName + " provider");
+ LocationResult filtered;
+ if (mPassiveManager != null) {
+ filtered = locationResult.filter(location -> {
+ if (!location.isFromMockProvider()) {
+ if (location.getLatitude() == 0 && location.getLongitude() == 0) {
+ Log.w(TAG, "blocking 0,0 location from " + mName + " provider");
+ return false;
+ }
+ }
+
+ if (!location.isComplete()) {
+ Log.w(TAG, "blocking incomplete location from " + mName + " provider");
+ return false;
+ }
+
+ return true;
+ });
+
+ if (filtered == null) {
return;
}
- }
-
- if (!location.isComplete()) {
- Log.w(TAG, "blocking incomplete location from " + mName + " provider");
- return;
- }
- if (mPassiveManager != null) {
// don't log location received for passive provider because it's spammy
- mLocationEventLog.logProviderReceivedLocation(mName);
+ mLocationEventLog.logProviderReceivedLocations(mName, filtered.size());
+ } else {
+ // passive provider should get already filtered results as input
+ filtered = locationResult;
}
// update last location
- setLastLocation(location, UserHandle.USER_ALL);
+ setLastLocation(filtered.getLastLocation(), UserHandle.USER_ALL);
// attempt listener delivery
deliverToListeners(registration -> {
- return registration.acceptLocationChange(location);
+ return registration.acceptLocationChange(filtered);
});
// notify passive provider
if (mPassiveManager != null) {
- mPassiveManager.updateLocation(location);
- }
- }
-
- @GuardedBy("mLock")
- @Override
- public void onReportLocation(List<Location> locations) {
- if (!GPS_PROVIDER.equals(mName)) {
- return;
+ mPassiveManager.updateLocation(filtered);
}
-
- mLocationManagerInternal.reportGnssBatchLocations(locations);
}
@GuardedBy("mLock")
@@ -2206,6 +2345,20 @@ class LocationProviderManager extends
}
}
+ private @Nullable LocationResult getPermittedLocationResult(
+ @Nullable LocationResult fineLocationResult, @PermissionLevel int permissionLevel) {
+ switch (permissionLevel) {
+ case PERMISSION_FINE:
+ return fineLocationResult;
+ case PERMISSION_COARSE:
+ return fineLocationResult != null ? mLocationFudger.createCoarse(fineLocationResult)
+ : null;
+ default:
+ // shouldn't be possible to have a client added without location permissions
+ throw new AssertionError();
+ }
+ }
+
public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
synchronized (mLock) {
ipw.print(mName);
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockLocationProvider.java
index fc88f147ea9d..505a858e0c63 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockLocationProvider.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.annotation.Nullable;
import android.location.Location;
+import android.location.LocationResult;
import android.location.util.identity.CallerIdentity;
import android.os.Bundle;
@@ -34,11 +35,11 @@ import java.io.PrintWriter;
*
* {@hide}
*/
-public class MockProvider extends AbstractLocationProvider {
+public class MockLocationProvider extends AbstractLocationProvider {
@Nullable private Location mLocation;
- public MockProvider(ProviderProperties properties, CallerIdentity identity) {
+ public MockLocationProvider(ProviderProperties properties, CallerIdentity identity) {
// using a direct executor is ok because this class has no locks that could deadlock
super(DIRECT_EXECUTOR, identity);
setProperties(properties);
@@ -54,13 +55,18 @@ public class MockProvider extends AbstractLocationProvider {
Location location = new Location(l);
location.setIsFromMockProvider(true);
mLocation = location;
- reportLocation(location);
+ reportLocation(LocationResult.wrap(location));
}
@Override
public void onSetRequest(ProviderRequest request) {}
@Override
+ protected void onFlush(Runnable callback) {
+ callback.run();
+ }
+
+ @Override
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
@Override
diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java
index d8d435aa4ac0..fa5339ed0b6f 100644
--- a/services/core/java/com/android/server/location/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/MockableLocationProvider.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.annotation.Nullable;
import android.location.Location;
+import android.location.LocationResult;
import android.os.Bundle;
import com.android.internal.annotations.GuardedBy;
@@ -28,7 +29,6 @@ import com.android.internal.util.Preconditions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.List;
/**
* Represents a location provider that may switch between a mock implementation and a real
@@ -54,7 +54,7 @@ public class MockableLocationProvider extends AbstractLocationProvider {
@GuardedBy("mOwnerLock")
@Nullable private AbstractLocationProvider mRealProvider;
@GuardedBy("mOwnerLock")
- @Nullable private MockProvider mMockProvider;
+ @Nullable private MockLocationProvider mMockProvider;
@GuardedBy("mOwnerLock")
private ProviderRequest mRequest;
@@ -113,7 +113,7 @@ public class MockableLocationProvider extends AbstractLocationProvider {
* inline invocation of {@link Listener#onStateChanged(State, State)} if this results in a
* state change.
*/
- public void setMockProvider(@Nullable MockProvider provider) {
+ public void setMockProvider(@Nullable MockLocationProvider provider) {
synchronized (mOwnerLock) {
if (mMockProvider == provider) {
return;
@@ -215,6 +215,17 @@ public class MockableLocationProvider extends AbstractLocationProvider {
}
@Override
+ protected void onFlush(Runnable callback) {
+ synchronized (mOwnerLock) {
+ if (mProvider != null) {
+ mProvider.flush(callback);
+ } else {
+ callback.run();
+ }
+ }
+ }
+
+ @Override
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {
synchronized (mOwnerLock) {
if (mProvider != null) {
@@ -272,24 +283,13 @@ public class MockableLocationProvider extends AbstractLocationProvider {
}
@Override
- public final void onReportLocation(Location location) {
- synchronized (mOwnerLock) {
- if (mListenerProvider != mProvider) {
- return;
- }
-
- reportLocation(location);
- }
- }
-
- @Override
- public final void onReportLocation(List<Location> locations) {
+ public final void onReportLocation(LocationResult locationResult) {
synchronized (mOwnerLock) {
if (mListenerProvider != mProvider) {
return;
}
- reportLocation(locations);
+ reportLocation(locationResult);
}
}
}
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveLocationProvider.java
index f6896b86f9b9..ddae4ed5fb0c 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveLocationProvider.java
@@ -20,7 +20,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.content.Context;
import android.location.Criteria;
-import android.location.Location;
+import android.location.LocationResult;
import android.location.util.identity.CallerIdentity;
import android.os.Bundle;
@@ -37,7 +37,7 @@ import java.io.PrintWriter;
*
* {@hide}
*/
-public class PassiveProvider extends AbstractLocationProvider {
+public class PassiveLocationProvider extends AbstractLocationProvider {
private static final ProviderProperties PROPERTIES = new ProviderProperties(
/* requiresNetwork = */false,
@@ -50,7 +50,7 @@ public class PassiveProvider extends AbstractLocationProvider {
Criteria.POWER_LOW,
Criteria.ACCURACY_COARSE);
- public PassiveProvider(Context context) {
+ public PassiveLocationProvider(Context context) {
// using a direct executor is ok because this class has no locks that could deadlock
super(DIRECT_EXECUTOR, CallerIdentity.fromContext(context));
@@ -61,14 +61,19 @@ public class PassiveProvider extends AbstractLocationProvider {
/**
* Pass a location into the passive provider.
*/
- public void updateLocation(Location location) {
- reportLocation(location);
+ public void updateLocation(LocationResult locationResult) {
+ reportLocation(locationResult);
}
@Override
public void onSetRequest(ProviderRequest request) {}
@Override
+ protected void onFlush(Runnable callback) {
+ callback.run();
+ }
+
+ @Override
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
@Override
diff --git a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
index b7718611cffc..343379a55060 100644
--- a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
+++ b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
@@ -18,8 +18,8 @@ package com.android.server.location;
import android.annotation.Nullable;
import android.content.Context;
-import android.location.Location;
import android.location.LocationManager;
+import android.location.LocationResult;
import android.os.Binder;
import com.android.internal.location.ProviderRequest;
@@ -36,25 +36,25 @@ class PassiveLocationProviderManager extends LocationProviderManager {
@Override
public void setRealProvider(AbstractLocationProvider provider) {
- Preconditions.checkArgument(provider instanceof PassiveProvider);
+ Preconditions.checkArgument(provider instanceof PassiveLocationProvider);
super.setRealProvider(provider);
}
@Override
- public void setMockProvider(@Nullable MockProvider provider) {
+ public void setMockProvider(@Nullable MockLocationProvider provider) {
if (provider != null) {
throw new IllegalArgumentException("Cannot mock the passive provider");
}
}
- public void updateLocation(Location location) {
+ public void updateLocation(LocationResult locationResult) {
synchronized (mLock) {
- PassiveProvider passiveProvider = (PassiveProvider) mProvider.getProvider();
- Preconditions.checkState(passiveProvider != null);
+ PassiveLocationProvider passive = (PassiveLocationProvider) mProvider.getProvider();
+ Preconditions.checkState(passive != null);
final long identity = Binder.clearCallingIdentity();
try {
- passiveProvider.updateLocation(location);
+ passive.updateLocation(locationResult);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/ProxyLocationProvider.java
index b111c155fac5..555b2d2e2138 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/ProxyLocationProvider.java
@@ -21,7 +21,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
-import android.location.Location;
+import android.location.LocationResult;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.Bundle;
@@ -38,21 +38,22 @@ import com.android.server.ServiceWatcher;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Objects;
/**
* Proxy for ILocationProvider implementations.
*/
-public class LocationProviderProxy extends AbstractLocationProvider {
+public class ProxyLocationProvider extends AbstractLocationProvider {
/**
* Creates and registers this proxy. If no suitable service is available for the proxy, returns
* null.
*/
@Nullable
- public static LocationProviderProxy createAndRegister(Context context, String action,
+ public static ProxyLocationProvider createAndRegister(Context context, String action,
int enableOverlayResId, int nonOverlayPackageResId) {
- LocationProviderProxy proxy = new LocationProviderProxy(context, action, enableOverlayResId,
+ ProxyLocationProvider proxy = new ProxyLocationProvider(context, action, enableOverlayResId,
nonOverlayPackageResId);
if (proxy.register()) {
return proxy;
@@ -67,13 +68,16 @@ public class LocationProviderProxy extends AbstractLocationProvider {
final ServiceWatcher mServiceWatcher;
@GuardedBy("mLock")
+ final ArrayList<Runnable> mFlushListeners = new ArrayList<>(0);
+
+ @GuardedBy("mLock")
Proxy mProxy;
@GuardedBy("mLock")
@Nullable ComponentName mService;
private volatile ProviderRequest mRequest;
- private LocationProviderProxy(Context context, String action, int enableOverlayResId,
+ private ProxyLocationProvider(Context context, String action, int enableOverlayResId,
int nonOverlayPackageResId) {
// safe to use direct executor since our locks are not acquired in a code path invoked by
// our owning provider
@@ -88,7 +92,11 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
private boolean register() {
- return mServiceWatcher.register();
+ boolean resolves = mServiceWatcher.checkServiceResolves();
+ if (resolves) {
+ mServiceWatcher.register();
+ }
+ return resolves;
}
private void onBind(IBinder binder, ComponentName service) throws RemoteException {
@@ -107,10 +115,18 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
private void onUnbind() {
+ Runnable[] flushListeners;
synchronized (mLock) {
mProxy = null;
mService = null;
setState(State.EMPTY_STATE);
+ flushListeners = mFlushListeners.toArray(new Runnable[0]);
+ mFlushListeners.clear();
+ }
+
+ final int size = flushListeners.length;
+ for (int i = 0; i < size; ++i) {
+ flushListeners[i].run();
}
}
@@ -124,6 +140,38 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
@Override
+ protected void onFlush(Runnable callback) {
+ mServiceWatcher.runOnBinder(new ServiceWatcher.BinderRunner() {
+ @Override
+ public void run(IBinder binder) throws RemoteException {
+ ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
+
+ // at first glance it would be more straightforward to pass the flush callback
+ // through to the provider and allow it to be invoked directly. however, in this
+ // case the binder calls 1) provider delivering flushed locations 2) provider
+ // delivering flush complete, while correctly ordered within the provider, would
+ // be invoked on different binder objects and thus would have no defined order
+ // on the system server side. thus, we ensure that both (1) and (2) are invoked
+ // on the same binder object (the ILocationProviderManager) and have a well
+ // defined ordering, so that the flush callback will always happen after
+ // location delivery.
+ synchronized (mLock) {
+ mFlushListeners.add(callback);
+ }
+ provider.flush();
+ }
+
+ @Override
+ public void onError() {
+ synchronized (mLock) {
+ mFlushListeners.remove(callback);
+ }
+ callback.run();
+ }
+ });
+ }
+
+ @Override
public void onExtraCommand(int uid, int pid, String command, Bundle extras) {
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
@@ -209,12 +257,31 @@ public class LocationProviderProxy extends AbstractLocationProvider {
// executed on binder thread
@Override
- public void onReportLocation(Location location) {
+ public void onReportLocation(LocationResult locationResult) {
synchronized (mLock) {
if (mProxy != this) {
return;
}
- reportLocation(location);
+
+ reportLocation(locationResult.validate());
+ }
+ }
+
+ // executed on binder thread
+ @Override
+ public void onFlushComplete() {
+ Runnable callback = null;
+ synchronized (mLock) {
+ if (mProxy != this) {
+ return;
+ }
+ if (!mFlushListeners.isEmpty()) {
+ callback = mFlushListeners.remove(0);
+ }
+ }
+
+ if (callback != null) {
+ callback.run();
}
}
}
diff --git a/services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java b/services/core/java/com/android/server/location/contexthub/ConcurrentLinkedEvictingDeque.java
index 6910c353e546..0427007d7d50 100644
--- a/services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java
+++ b/services/core/java/com/android/server/location/contexthub/ConcurrentLinkedEvictingDeque.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 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.server.location;
+package com.android.server.location.contexthub;
import java.util.concurrent.ConcurrentLinkedDeque;
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
index e27eb65eccfc..20458b4db558 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 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.server.location;
+package com.android.server.location.contexthub;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -37,6 +37,8 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import com.android.server.location.ClientBrokerProto;
+
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
index 33ceeeff331f..eda89ab52c6f 100644
--- a/services/core/java/com/android/server/location/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 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.server.location;
+package com.android.server.location.contexthub;
import android.annotation.IntDef;
import android.app.PendingIntent;
@@ -29,6 +29,8 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import com.android.server.location.ClientManagerProto;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.DateFormat;
diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 7a2e4ed3cc0b..63a42f845cee 100644
--- a/services/core/java/com/android/server/location/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 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.server.location;
+package com.android.server.location.contexthub;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -54,6 +54,7 @@ import android.util.Log;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.DumpUtils;
+import com.android.server.location.ContextHubServiceProto;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceTransaction.java
index 62bd91bda1b8..a31aecbe4228 100644
--- a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceTransaction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 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.server.location;
+package com.android.server.location.contexthub;
import android.hardware.location.ContextHubTransaction;
import android.hardware.location.NanoAppState;
diff --git a/services/core/java/com/android/server/location/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
index 9145eca9ad6f..88ed1053616a 100644
--- a/services/core/java/com/android/server/location/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 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.server.location;
+package com.android.server.location.contexthub;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
diff --git a/services/core/java/com/android/server/location/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index d3fc7058bcf2..f81208fbf241 100644
--- a/services/core/java/com/android/server/location/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 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.server.location;
+package com.android.server.location.contexthub;
import android.hardware.contexthub.V1_0.IContexthub;
import android.hardware.contexthub.V1_0.Result;
diff --git a/services/core/java/com/android/server/location/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 9ac7c6b95583..4242d72239e2 100644
--- a/services/core/java/com/android/server/location/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.location;
+package com.android.server.location.contexthub;
import android.annotation.Nullable;
import android.hardware.contexthub.V1_1.Setting;
diff --git a/services/core/java/com/android/server/location/NanoAppStateManager.java b/services/core/java/com/android/server/location/contexthub/NanoAppStateManager.java
index e26ccc3a7286..60109fe4b9f6 100644
--- a/services/core/java/com/android/server/location/NanoAppStateManager.java
+++ b/services/core/java/com/android/server/location/contexthub/NanoAppStateManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 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.server.location;
+package com.android.server.location.contexthub;
import android.annotation.Nullable;
import android.hardware.contexthub.V1_0.HubAppInfo;
diff --git a/services/core/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java
index 6117a9b8749a..af3907e78432 100644
--- a/services/core/java/com/android/server/location/ComprehensiveCountryDetector.java
+++ b/services/core/java/com/android/server/location/countrydetector/ComprehensiveCountryDetector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 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.
@@ -11,10 +11,10 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
-package com.android.server.location;
+package com.android.server.location.countrydetector;
import android.content.Context;
import android.location.Country;
diff --git a/services/core/java/com/android/server/location/CountryDetectorBase.java b/services/core/java/com/android/server/location/countrydetector/CountryDetectorBase.java
index 682b104f6d7a..6e2e28caf4de 100644
--- a/services/core/java/com/android/server/location/CountryDetectorBase.java
+++ b/services/core/java/com/android/server/location/countrydetector/CountryDetectorBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 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.
@@ -11,10 +11,10 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
-package com.android.server.location;
+package com.android.server.location.countrydetector;
import android.content.Context;
import android.location.Country;
diff --git a/services/core/java/com/android/server/location/LocationBasedCountryDetector.java b/services/core/java/com/android/server/location/countrydetector/LocationBasedCountryDetector.java
index 8ee1285b41f2..638f36f80143 100644
--- a/services/core/java/com/android/server/location/LocationBasedCountryDetector.java
+++ b/services/core/java/com/android/server/location/countrydetector/LocationBasedCountryDetector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 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.
@@ -11,10 +11,10 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
-package com.android.server.location;
+package com.android.server.location.countrydetector;
import android.content.Context;
import android.location.Address;
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
index 7a59cba02dd9..c23bd85505da 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
@@ -296,15 +296,15 @@ public class GeofenceManager extends
@Nullable String attributionTag) {
LocationPermissions.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_FINE);
- CallerIdentity callerIdentity = CallerIdentity.fromBinder(mContext, packageName,
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName,
attributionTag, AppOpsManager.toReceiverId(pendingIntent));
- final long identity = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
putRegistration(new GeofenceKey(pendingIntent, geofence),
- new GeofenceRegistration(geofence, callerIdentity, pendingIntent));
+ new GeofenceRegistration(geofence, identity, pendingIntent));
} finally {
- Binder.restoreCallingIdentity(identity);
+ Binder.restoreCallingIdentity(ident);
}
}
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
index 686a66bb4d97..bdfa6d7aa67e 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
@@ -75,16 +75,16 @@ public final class GeofenceProxy {
}
private boolean register(Context context) {
- if (mServiceWatcher.register()) {
+ boolean resolves = mServiceWatcher.checkServiceResolves();
+ if (resolves) {
+ mServiceWatcher.register();
context.bindServiceAsUser(
new Intent(context, GeofenceHardwareService.class),
new GeofenceProxyServiceConnection(),
Context.BIND_AUTO_CREATE,
UserHandle.SYSTEM);
- return true;
}
-
- return false;
+ return resolves;
}
private class GeofenceProxyServiceConnection implements ServiceConnection {
diff --git a/services/core/java/com/android/server/location/gnss/GnssBatchingProvider.java b/services/core/java/com/android/server/location/gnss/GnssBatchingProvider.java
deleted file mode 100644
index 057b17886b10..000000000000
--- a/services/core/java/com/android/server/location/gnss/GnssBatchingProvider.java
+++ /dev/null
@@ -1,161 +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.location.gnss;
-
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Manages GNSS Batching operations.
- *
- * <p>This class is not thread safe (It's client's responsibility to make sure calls happen on
- * the same thread).
- */
-public class GnssBatchingProvider {
-
- private static final String TAG = "GnssBatchingProvider";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- private final GnssBatchingProviderNative mNative;
- private boolean mEnabled;
- private boolean mStarted;
- private long mPeriodNanos;
- private boolean mWakeOnFifoFull;
-
- GnssBatchingProvider() {
- this(new GnssBatchingProviderNative());
- }
-
- @VisibleForTesting
- GnssBatchingProvider(GnssBatchingProviderNative gnssBatchingProviderNative) {
- mNative = gnssBatchingProviderNative;
- }
-
- /**
- * Returns the GNSS batching size
- */
- public int getBatchSize() {
- return mNative.getBatchSize();
- }
-
- /** Enable GNSS batching. */
- public void enable() {
- mEnabled = mNative.initBatching();
- if (!mEnabled) {
- Log.e(TAG, "Failed to initialize GNSS batching");
- }
- }
-
- /**
- * Starts the hardware batching operation
- */
- public boolean start(long periodNanos, boolean wakeOnFifoFull) {
- if (!mEnabled) {
- throw new IllegalStateException();
- }
- if (periodNanos <= 0) {
- Log.e(TAG, "Invalid periodNanos " + periodNanos
- + " in batching request, not started");
- return false;
- }
- mStarted = mNative.startBatch(periodNanos, wakeOnFifoFull);
- if (mStarted) {
- mPeriodNanos = periodNanos;
- mWakeOnFifoFull = wakeOnFifoFull;
- }
- return mStarted;
- }
-
- /**
- * Forces a flush of existing locations from the hardware batching
- */
- public void flush() {
- if (!mStarted) {
- Log.w(TAG, "Cannot flush since GNSS batching has not started.");
- return;
- }
- mNative.flushBatch();
- }
-
- /**
- * Stops the batching operation
- */
- public boolean stop() {
- boolean stopped = mNative.stopBatch();
- if (stopped) {
- mStarted = false;
- }
- return stopped;
- }
-
- /** Disable GNSS batching. */
- public void disable() {
- stop();
- mNative.cleanupBatching();
- mEnabled = false;
- }
-
- // TODO(b/37460011): Use this with death recovery logic.
- void resumeIfStarted() {
- if (DEBUG) {
- Log.d(TAG, "resumeIfStarted");
- }
- if (mStarted) {
- mNative.startBatch(mPeriodNanos, mWakeOnFifoFull);
- }
- }
-
- @VisibleForTesting
- static class GnssBatchingProviderNative {
- public int getBatchSize() {
- return native_get_batch_size();
- }
-
- public boolean startBatch(long periodNanos, boolean wakeOnFifoFull) {
- return native_start_batch(periodNanos, wakeOnFifoFull);
- }
-
- public void flushBatch() {
- native_flush_batch();
- }
-
- public boolean stopBatch() {
- return native_stop_batch();
- }
-
- public boolean initBatching() {
- return native_init_batching();
- }
-
- public void cleanupBatching() {
- native_cleanup_batching();
- }
- }
-
- private static native int native_get_batch_size();
-
- private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
-
- private static native void native_flush_batch();
-
- private static native boolean native_stop_batch();
-
- private static native boolean native_init_batching();
-
- private static native void native_cleanup_batching();
-}
diff --git a/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java b/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java
index b8aa5776b45b..1c4fb10b8d0e 100644
--- a/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java
@@ -29,7 +29,7 @@ public class GnssCapabilitiesProvider {
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final long GNSS_CAPABILITIES_TOP_HAL =
- GnssCapabilities.LOW_POWER_MODE | GnssCapabilities.SATELLITE_BLACKLIST
+ GnssCapabilities.LOW_POWER_MODE | GnssCapabilities.SATELLITE_BLOCKLIST
| GnssCapabilities.GEOFENCING | GnssCapabilities.MEASUREMENTS
| GnssCapabilities.NAV_MESSAGES;
@@ -65,8 +65,8 @@ public class GnssCapabilitiesProvider {
gnssCapabilities |= GnssCapabilities.LOW_POWER_MODE;
}
if (hasCapability(topHalCapabilities,
- GnssLocationProvider.GPS_CAPABILITY_SATELLITE_BLACKLIST)) {
- gnssCapabilities |= GnssCapabilities.SATELLITE_BLACKLIST;
+ GnssLocationProvider.GPS_CAPABILITY_SATELLITE_BLOCKLIST)) {
+ gnssCapabilities |= GnssCapabilities.SATELLITE_BLOCKLIST;
}
if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_GEOFENCING)) {
gnssCapabilities |= GnssCapabilities.GEOFENCING;
diff --git a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
index 890f51b44ace..26283729f4e9 100644
--- a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
@@ -71,6 +71,11 @@ class GnssConfiguration {
private static final String CONFIG_GPS_LOCK = "GPS_LOCK";
private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC";
public static final String CONFIG_NFW_PROXY_APPS = "NFW_PROXY_APPS";
+ private static final String CONFIG_LONGTERM_PSDS_SERVER_1 = "LONGTERM_PSDS_SERVER_1";
+ private static final String CONFIG_LONGTERM_PSDS_SERVER_2 = "LONGTERM_PSDS_SERVER_2";
+ private static final String CONFIG_LONGTERM_PSDS_SERVER_3 = "LONGTERM_PSDS_SERVER_3";
+ private static final String CONFIG_NORMAL_PSDS_SERVER = "NORMAL_PSDS_SERVER";
+ private static final String CONFIG_REALTIME_PSDS_SERVER = "REALTIME_PSDS_SERVER";
// Limit on NI emergency mode time extension after emergency sessions ends
private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300; // 5 minute maximum
@@ -202,8 +207,8 @@ class GnssConfiguration {
/**
* Updates the GNSS HAL satellite denylist.
*/
- void setSatelliteBlacklist(int[] constellations, int[] svids) {
- native_set_satellite_blacklist(constellations, svids);
+ void setSatelliteBlocklist(int[] constellations, int[] svids) {
+ native_set_satellite_blocklist(constellations, svids);
}
HalInterfaceVersion getHalInterfaceVersion() {
@@ -227,11 +232,14 @@ class GnssConfiguration {
// override default value of this if lpp_prof is not empty
mProperties.setProperty(CONFIG_LPP_PROFILE, lpp_prof);
}
+
+ // Load Psds servers from resources
+ loadPsdsServersFromResources();
+
/*
* Overlay carrier properties from a debug configuration file.
*/
loadPropertiesFromGpsDebugConfig(mProperties);
-
mEsExtensionSec = getRangeCheckedConfigEsExtensionSec();
logConfigurations();
@@ -380,6 +388,34 @@ class GnssConfiguration {
}
}
+ void loadPsdsServersFromResources() {
+ String longTermPsdsServer1 = mContext.getResources().getString(
+ com.android.internal.R.string.config_longterm_psds_server_1);
+ if (!TextUtils.isEmpty(longTermPsdsServer1)) {
+ mProperties.setProperty(CONFIG_LONGTERM_PSDS_SERVER_1, longTermPsdsServer1);
+ }
+ String longTermPsdsServer2 = mContext.getResources().getString(
+ com.android.internal.R.string.config_longterm_psds_server_2);
+ if (!TextUtils.isEmpty(longTermPsdsServer2)) {
+ mProperties.setProperty(CONFIG_LONGTERM_PSDS_SERVER_2, longTermPsdsServer2);
+ }
+ String longTermPsdsServer3 = mContext.getResources().getString(
+ com.android.internal.R.string.config_longterm_psds_server_3);
+ if (!TextUtils.isEmpty(longTermPsdsServer3)) {
+ mProperties.setProperty(CONFIG_LONGTERM_PSDS_SERVER_3, longTermPsdsServer3);
+ }
+ String normalPsdsServer = mContext.getResources().getString(
+ com.android.internal.R.string.config_normal_psds_server);
+ if (!TextUtils.isEmpty(normalPsdsServer)) {
+ mProperties.setProperty(CONFIG_NORMAL_PSDS_SERVER, normalPsdsServer);
+ }
+ String realtimePsdsServer = mContext.getResources().getString(
+ com.android.internal.R.string.config_realtime_psds_server);
+ if (!TextUtils.isEmpty(realtimePsdsServer)) {
+ mProperties.setProperty(CONFIG_REALTIME_PSDS_SERVER, realtimePsdsServer);
+ }
+ }
+
private static boolean isConfigEsExtensionSecSupported(
HalInterfaceVersion gnssConfiguartionIfaceVersion) {
// ES_EXTENSION_SEC is introduced in @2.0::IGnssConfiguration.hal
@@ -414,7 +450,7 @@ class GnssConfiguration {
private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
- private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
+ private static native boolean native_set_satellite_blocklist(int[] constellations, int[] svIds);
private static native boolean native_set_es_extension_sec(int emergencyExtensionSeconds);
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 0c1e91d9bf24..593312e82f21 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -16,9 +16,12 @@
package com.android.server.location.gnss;
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
import android.app.AlarmManager;
import android.app.AppOpsManager;
-import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -39,13 +42,12 @@ import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationRequest;
+import android.location.LocationResult;
import android.location.util.identity.CallerIdentity;
import android.os.AsyncTask;
import android.os.BatteryStats;
-import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
@@ -74,11 +76,9 @@ import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.location.gnssmetrics.GnssMetrics;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.server.DeviceIdleInternal;
import com.android.server.FgThread;
-import com.android.server.LocalServices;
import com.android.server.location.AbstractLocationProvider;
-import com.android.server.location.gnss.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback;
+import com.android.server.location.gnss.GnssSatelliteBlocklistHelper.GnssSatelliteBlocklistCallback;
import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback;
import com.android.server.location.util.Injector;
@@ -88,6 +88,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -97,7 +98,7 @@ import java.util.Set;
*/
public class GnssLocationProvider extends AbstractLocationProvider implements
InjectNtpTimeCallback,
- GnssSatelliteBlacklistCallback {
+ GnssSatelliteBlocklistCallback {
private static final String TAG = "GnssLocationProvider";
@@ -171,7 +172,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
public static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100;
- public static final int GPS_CAPABILITY_SATELLITE_BLACKLIST = 0x0000200;
+ public static final int GPS_CAPABILITY_SATELLITE_BLOCKLIST = 0x0000200;
public static final int GPS_CAPABILITY_MEASUREMENT_CORRECTIONS = 0x0000400;
public static final int GPS_CAPABILITY_ANTENNA_INFO = 0x0000800;
@@ -179,12 +180,9 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private static final int AGPS_SUPL_MODE_MSA = 0x02;
private static final int AGPS_SUPL_MODE_MSB = 0x01;
- private static final int UPDATE_LOW_POWER_MODE = 1;
- private static final int SET_REQUEST = 3;
private static final int INJECT_NTP_TIME = 5;
// PSDS stands for Predicted Satellite Data Service
private static final int DOWNLOAD_PSDS_DATA = 6;
- private static final int INITIALIZE_HANDLER = 13;
private static final int REQUEST_LOCATION = 16;
private static final int REPORT_LOCATION = 17; // HAL reports location
private static final int REPORT_SV_STATUS = 18; // HAL reports SV status
@@ -267,8 +265,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}
- private final Object mLock = new Object();
-
// stop trying if we do not receive a fix within 60 seconds
private static final int NO_FIX_TIMEOUT = 60 * 1000;
@@ -290,6 +286,23 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private static final long DOWNLOAD_PSDS_DATA_TIMEOUT_MS = 60 * 1000;
private static final long WAKELOCK_TIMEOUT_MILLIS = 30 * 1000;
+ // threshold for delay in GNSS engine turning off before warning & error
+ private static final long LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS = 2 * 1000;
+ private static final long LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS = 15 * 1000;
+
+ private static final String DOWNLOAD_EXTRA_WAKELOCK_KEY = "GnssLocationProviderPsdsDownload";
+
+ // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
+ // stops output right at 600m/s, depriving this of the information of a device that reaches
+ // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases.
+ private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F;
+
+
+ private final Object mLock = new Object();
+
+ private final Context mContext;
+ private final Handler mHandler;
+
@GuardedBy("mLock")
private final ExponentialBackOff mPsdsBackOff = new ExponentialBackOff(RETRY_INTERVAL,
MAX_RETRY_INTERVAL);
@@ -298,35 +311,20 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
@GuardedBy("mLock")
private boolean mGpsEnabled;
- private boolean mShutdown;
-
@GuardedBy("mLock")
- private Set<Integer> mPendingDownloadPsdsTypes = new HashSet<>();
+ private boolean mBatchingEnabled;
- // true if GPS is navigating
+ private boolean mShutdown;
private boolean mNavigating;
-
- // requested frequency of fixes, in milliseconds
- private int mFixInterval = 1000;
-
- // true if low power mode for the GNSS chipset is part of the latest request.
- private boolean mLowPowerMode = false;
-
- // true if we started navigation in the HAL, only change value of this in setStarted
private boolean mStarted;
-
- // for logging of latest change, and warning of ongoing location after a stop
+ private boolean mBatchingStarted;
private long mStartedChangedElapsedRealtime;
+ private int mFixInterval = 1000;
- // threshold for delay in GNSS engine turning off before warning & error
- private static final long LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS = 2 * 1000;
- private static final long LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS = 15 * 1000;
-
- // capabilities reported through the top level IGnssCallback.hal
- private volatile int mTopHalCapabilities;
+ private ProviderRequest mProviderRequest;
- // true if PSDS is supported
- private boolean mSupportsPsds;
+ private int mPositionMode;
+ private GnssPositionMode mLastPositionMode;
// for calculating time to first fix
private long mFixRequestTime = 0;
@@ -335,25 +333,23 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// time we received our last fix
private long mLastFixTime;
- private int mPositionMode;
- private GnssPositionMode mLastPositionMode;
+ private final WorkSource mClientSource = new WorkSource();
- // Current request from underlying location clients.
- private ProviderRequest mProviderRequest;
- // True if gps should be disabled because of PowerManager controls
- private boolean mDisableGpsForPowerManager = false;
+ // capabilities reported through the top level IGnssCallback.hal
+ private volatile int mTopHalCapabilities;
- /**
- * True if the device idle controller has determined that the device is stationary. This is only
- * updated when the device enters idle mode.
- */
- private volatile boolean mIsDeviceStationary = false;
+ // true if PSDS is supported
+ private boolean mSupportsPsds;
+ @GuardedBy("mLock")
+ private final PowerManager.WakeLock mDownloadPsdsWakeLock;
+ @GuardedBy("mLock")
+ private final Set<Integer> mPendingDownloadPsdsTypes = new HashSet<>();
/**
* Properties loaded from PROPERTIES_FILE.
* It must be accessed only inside {@link #mHandler}.
*/
- private GnssConfiguration mGnssConfiguration;
+ private final GnssConfiguration mGnssConfiguration;
private String mSuplServerHost;
private int mSuplServerPort = TCP_MIN_PORT;
@@ -361,68 +357,46 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private int mC2KServerPort;
private boolean mSuplEsEnabled = false;
- private final Looper mLooper;
private final LocationExtras mLocationExtras = new LocationExtras();
private final GnssStatusProvider mGnssStatusListenerHelper;
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
private final GnssAntennaInfoProvider mGnssAntennaInfoProvider;
private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
- private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
- private final LocationChangeListener mFusedLocationListener = new FusedLocationListener();
private final NtpTimeHelper mNtpTimeHelper;
- private final GnssBatchingProvider mGnssBatchingProvider;
private final GnssGeofenceProvider mGnssGeofenceProvider;
private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
- private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper;
+ private final GnssSatelliteBlocklistHelper mGnssSatelliteBlocklistHelper;
// Available only on GNSS HAL 2.0 implementations and later.
private GnssVisibilityControl mGnssVisibilityControl;
- private final Context mContext;
- private Handler mHandler;
-
private final GnssNetworkConnectivityHandler mNetworkConnectivityHandler;
private final GpsNetInitiatedHandler mNIHandler;
// Wakelocks
- private static final String WAKELOCK_KEY = "GnssLocationProvider";
private final PowerManager.WakeLock mWakeLock;
- private static final String DOWNLOAD_EXTRA_WAKELOCK_KEY = "GnssLocationProviderPsdsDownload";
- @GuardedBy("mLock")
- private final PowerManager.WakeLock mDownloadPsdsWakeLock;
-
- // Alarms
- private static final String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
- private static final String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
- private final PowerManager mPowerManager;
private final AlarmManager mAlarmManager;
- private final PendingIntent mWakeupIntent;
- private final PendingIntent mTimeoutIntent;
+ private final AlarmManager.OnAlarmListener mWakeupListener = this::startNavigating;
+ private final AlarmManager.OnAlarmListener mTimeoutListener = this::hibernate;
private final AppOpsManager mAppOps;
private final IBatteryStats mBatteryStats;
- // Current list of underlying location clients.
- // only modified on handler thread
- private WorkSource mClientSource = new WorkSource();
-
private GeofenceHardwareImpl mGeofenceHardwareImpl;
// Volatile for simple inter-thread sync on these values.
private volatile int mHardwareYear = 0;
private volatile String mHardwareModelName;
- // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
- // stops output right at 600m/s, depriving this of the information of a device that reaches
- // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases.
- private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F;
-
private volatile boolean mItarSpeedLimitExceeded = false;
+ @GuardedBy("mLock")
+ private final ArrayList<Runnable> mFlushListeners = new ArrayList<>(0);
+
// GNSS Metrics
- private GnssMetrics mGnssMetrics;
+ private final GnssMetrics mGnssMetrics;
public GnssStatusProvider getGnssStatusProvider() {
return mGnssStatusListenerHelper;
@@ -448,57 +422,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
return mGnssNavigationMessageProvider;
}
- private final DeviceIdleInternal.StationaryListener mDeviceIdleStationaryListener =
- isStationary -> {
- mIsDeviceStationary = isStationary;
- // Call updateLowPowerMode on handler thread so it's always called from the same
- // thread.
- mHandler.sendEmptyMessage(UPDATE_LOW_POWER_MODE);
- };
-
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
- if (action == null) {
- return;
- }
-
- switch (action) {
- case ALARM_WAKEUP:
- startNavigating();
- break;
- case ALARM_TIMEOUT:
- hibernate();
- break;
- case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
- DeviceIdleInternal deviceIdleService = LocalServices.getService(
- DeviceIdleInternal.class);
- if (mPowerManager.isDeviceIdleMode()) {
- deviceIdleService.registerStationaryListener(mDeviceIdleStationaryListener);
- } else {
- deviceIdleService.unregisterStationaryListener(
- mDeviceIdleStationaryListener);
- }
- // Call updateLowPowerMode on handler thread so it's always called from the
- // same thread.
- mHandler.sendEmptyMessage(UPDATE_LOW_POWER_MODE);
- break;
- case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
- case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
- subscriptionOrCarrierConfigChanged();
- break;
- }
- }
- };
-
/**
- * Implements {@link GnssSatelliteBlacklistCallback#onUpdateSatelliteBlacklist}.
+ * Implements {@link GnssSatelliteBlocklistCallback#onUpdateSatelliteBlocklist}.
*/
@Override
- public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) {
- mHandler.post(() -> mGnssConfiguration.setSatelliteBlacklist(constellations, svids));
+ public void onUpdateSatelliteBlocklist(int[] constellations, int[] svids) {
+ mHandler.post(() -> mGnssConfiguration.setSatelliteBlocklist(constellations, svids));
mGnssMetrics.resetConstellationTypes();
}
@@ -542,16 +471,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}
- private void updateLowPowerMode() {
- // Disable GPS if we are in device idle mode and the device is stationary.
- boolean disableGpsForPowerManager = mPowerManager.isDeviceIdleMode() && mIsDeviceStationary;
- if (disableGpsForPowerManager != mDisableGpsForPowerManager) {
- mDisableGpsForPowerManager = disableGpsForPowerManager;
- updateEnabled();
- updateRequirements();
- }
- }
-
private void reloadGpsProperties() {
mGnssConfiguration.reloadGpsProperties();
setSuplHostPort();
@@ -570,23 +489,19 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
super(FgThread.getExecutor(), CallerIdentity.fromContext(context));
mContext = context;
- mLooper = FgThread.getHandler().getLooper();
// Create a wake lock
- mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
+ PowerManager powerManager = Objects.requireNonNull(
+ mContext.getSystemService(PowerManager.class));
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.setReferenceCounted(true);
// Create a separate wake lock for psds downloader as it may be released due to timeout.
- mDownloadPsdsWakeLock = mPowerManager.newWakeLock(
+ mDownloadPsdsWakeLock = powerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY);
mDownloadPsdsWakeLock.setReferenceCounted(true);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP),
- PendingIntent.FLAG_IMMUTABLE);
- mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT),
- PendingIntent.FLAG_IMMUTABLE);
// App ops service to keep track of who is accessing the GPS
mAppOps = mContext.getSystemService(AppOpsManager.class);
@@ -596,7 +511,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
BatteryStats.SERVICE_NAME));
// Construct internal handler
- mHandler = new ProviderHandler(mLooper);
+ mHandler = new ProviderHandler(FgThread.getHandler().getLooper());
// Load GPS configuration and register listeners in the background:
// some operations, such as opening files and registering broadcast receivers, can take a
@@ -612,7 +527,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// Trigger PSDS data download when the network comes up after booting.
mPendingDownloadPsdsTypes.add(GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX);
mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context,
- GnssLocationProvider.this::onNetworkAvailable, mLooper, mNIHandler);
+ GnssLocationProvider.this::onNetworkAvailable, mHandler.getLooper(), mNIHandler);
mGnssStatusListenerHelper = new GnssStatusProvider(injector);
mGnssMeasurementsProvider = new GnssMeasurementsProvider(injector);
@@ -621,11 +536,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(injector);
mGnssMetrics = new GnssMetrics(mContext, mBatteryStats);
- mNtpTimeHelper = new NtpTimeHelper(mContext, mLooper, this);
- mGnssSatelliteBlacklistHelper =
- new GnssSatelliteBlacklistHelper(mContext,
- mLooper, this);
- mGnssBatchingProvider = new GnssBatchingProvider();
+ mNtpTimeHelper = new NtpTimeHelper(mContext, mHandler.getLooper(), this);
+ mGnssSatelliteBlocklistHelper =
+ new GnssSatelliteBlocklistHelper(mContext,
+ mHandler.getLooper(), this);
mGnssGeofenceProvider = new GnssGeofenceProvider();
setProperties(PROPERTIES);
@@ -654,8 +568,64 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}, UserHandle.USER_ALL);
- sendMessage(INITIALIZE_HANDLER, 0, null);
- mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
+ mHandler.post(this::handleInitialize);
+ mHandler.post(mGnssSatelliteBlocklistHelper::updateSatelliteBlocklist);
+ }
+
+ private void handleInitialize() {
+ // it *appears* that native_init() needs to be called at least once before invoking any
+ // other gnss methods, so we cycle once on initialization.
+ native_init();
+ native_cleanup();
+
+ if (native_is_gnss_visibility_control_supported()) {
+ mGnssVisibilityControl = new GnssVisibilityControl(mContext, mHandler.getLooper(),
+ mNIHandler);
+ }
+
+ // load default GPS configuration
+ // (this configuration might change in the future based on SIM changes)
+ reloadGpsProperties();
+
+ // listen for events
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ intentFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
+ if (action == null) {
+ return;
+ }
+
+ switch (action) {
+ case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
+ case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
+ subscriptionOrCarrierConfigChanged();
+ break;
+ }
+ }
+ }, intentFilter, null, mHandler);
+
+ mNetworkConnectivityHandler.registerNetworkCallbacks();
+
+ // permanently passively listen to all network locations
+ LocationManager locationManager = Objects.requireNonNull(
+ mContext.getSystemService(LocationManager.class));
+ if (locationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
+ locationManager.requestLocationUpdates(
+ LocationManager.NETWORK_PROVIDER,
+ new LocationRequest.Builder(LocationRequest.PASSIVE_INTERVAL)
+ .setMinUpdateIntervalMillis(0)
+ .setHiddenFromAppOps(true)
+ .build(),
+ DIRECT_EXECUTOR,
+ this::injectLocation);
+ }
+
+ updateEnabled();
}
/**
@@ -702,19 +672,20 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
LocationManager locationManager = (LocationManager) mContext.getSystemService(
Context.LOCATION_SERVICE);
String provider;
- LocationChangeListener locationListener;
+ LocationListener locationListener;
LocationRequest.Builder locationRequest = new LocationRequest.Builder(
- LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS);
+ LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS).setMaxUpdates(1);
if (independentFromGnss) {
- // For fast GNSS TTFF
+ // For fast GNSS TTFF - we use an empty listener because we will rely on the passive
+ // network listener to actually inject the location. this prevents double injection
provider = LocationManager.NETWORK_PROVIDER;
- locationListener = mNetworkLocationListener;
+ locationListener = location -> { };
locationRequest.setQuality(LocationRequest.QUALITY_LOW_POWER);
} else {
// For Device-Based Hybrid (E911)
provider = LocationManager.FUSED_PROVIDER;
- locationListener = mFusedLocationListener;
+ locationListener = this::injectBestLocation;
locationRequest.setQuality(LocationRequest.QUALITY_HIGH_ACCURACY);
}
@@ -729,31 +700,26 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}
+ locationRequest.setDurationMillis(durationMillis);
+
Log.i(TAG,
String.format(
"GNSS HAL Requesting location updates from %s provider for %d millis.",
provider, durationMillis));
- try {
- locationManager.requestLocationUpdates(provider, locationRequest.build(),
- new HandlerExecutor(mHandler), locationListener);
- locationListener.mNumLocationUpdateRequest++;
- mHandler.postDelayed(() -> {
- if (--locationListener.mNumLocationUpdateRequest == 0) {
- Log.i(TAG,
- String.format("Removing location updates from %s provider.", provider));
- locationManager.removeUpdates(locationListener);
- }
- }, durationMillis);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "Unable to request location.", e);
- }
+ locationManager.requestLocationUpdates(provider, locationRequest.build(),
+ DIRECT_EXECUTOR, locationListener);
}
private void injectBestLocation(Location location) {
if (DEBUG) {
Log.d(TAG, "injectBestLocation: " + location);
}
+
+ if (location.isFromMockProvider()) {
+ return;
+ }
+
int gnssLocationFlags = LOCATION_HAS_LAT_LONG
| (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0)
| (location.hasSpeed() ? LOCATION_HAS_SPEED : 0)
@@ -854,10 +820,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
private void injectLocation(Location location) {
- if (location.hasAccuracy()) {
- if (DEBUG) {
- Log.d(TAG, "injectLocation: " + location);
- }
+ if (location.hasAccuracy() && !location.isFromMockProvider()) {
native_inject_location(location.getLatitude(), location.getLongitude(),
location.getAccuracy());
}
@@ -922,7 +885,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
mC2KServerHost, mC2KServerPort);
}
- mGnssBatchingProvider.enable();
+ mBatchingEnabled = native_init_batching() && native_get_batch_size() > 1;
if (mGnssVisibilityControl != null) {
mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ true);
}
@@ -938,14 +901,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
setGpsEnabled(false);
updateClientUids(new WorkSource());
stopNavigating();
- mAlarmManager.cancel(mWakeupIntent);
- mAlarmManager.cancel(mTimeoutIntent);
+ stopBatching();
if (mGnssVisibilityControl != null) {
mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ false);
}
- mGnssBatchingProvider.disable();
// do this before releasing wakelock
+ native_cleanup_batching();
native_cleanup();
}
@@ -954,9 +916,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
boolean enabled = mContext.getSystemService(LocationManager.class)
.isLocationEnabledForUser(UserHandle.CURRENT);
- // ... but disable if PowerManager overrides
- enabled &= !mDisableGpsForPowerManager;
-
// .. but enable anyway, if there's an active settings-ignored request (e.g. ELS)
enabled |= (mProviderRequest != null
&& mProviderRequest.isActive()
@@ -982,12 +941,32 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}
+ /**
+ * Returns the hardware batch size available in this hardware implementation. If the available
+ * size is variable, for example, based on other operations consuming memory, this is the
+ * minimum size guaranteed to be available for batching operations.
+ */
+ public int getBatchSize() {
+ return native_get_batch_size();
+ }
+
@Override
- public void onSetRequest(ProviderRequest request) {
- sendMessage(SET_REQUEST, 0, request);
+ protected void onFlush(Runnable listener) {
+ boolean added = false;
+ synchronized (mLock) {
+ if (mBatchingEnabled) {
+ added = mFlushListeners.add(listener);
+ }
+ }
+ if (!added) {
+ listener.run();
+ } else {
+ native_flush_batch();
+ }
}
- private void handleSetRequest(ProviderRequest request) {
+ @Override
+ public void onSetRequest(ProviderRequest request) {
mProviderRequest = request;
updateEnabled();
updateRequirements();
@@ -1005,52 +984,69 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
updateClientUids(mProviderRequest.getWorkSource());
mFixInterval = (int) mProviderRequest.getIntervalMillis();
- mLowPowerMode = mProviderRequest.isLowPower();
// check for overflow
if (mFixInterval != mProviderRequest.getIntervalMillis()) {
Log.w(TAG, "interval overflow: " + mProviderRequest.getIntervalMillis());
mFixInterval = Integer.MAX_VALUE;
}
+ // requested batch size, or zero to disable batching
+ int batchSize;
+ try {
+ batchSize = mBatchingEnabled ? Math.toIntExact(
+ mProviderRequest.getMaxUpdateDelayMillis() / mFixInterval) : 0;
+ } catch (ArithmeticException e) {
+ batchSize = Integer.MAX_VALUE;
+ }
+
+ if (batchSize < getBatchSize()) {
+ batchSize = 0;
+ }
// apply request to GPS engine
- if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
- // change period and/or lowPowerMode
- if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
- mFixInterval, 0, 0, mLowPowerMode)) {
- Log.e(TAG, "set_position_mode failed in updateRequirements");
- }
- } else if (!mStarted) {
- // start GPS
- startNavigating();
+ if (batchSize > 0) {
+ stopNavigating();
+ startBatching();
} else {
- // GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING
- mAlarmManager.cancel(mTimeoutIntent);
- if (mFixInterval >= NO_FIX_TIMEOUT) {
- // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
- // and our fix interval is not short
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
+ stopBatching();
+
+ if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
+ // change period and/or lowPowerMode
+ if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
+ mFixInterval, mProviderRequest.isLowPower())) {
+ Log.e(TAG, "set_position_mode failed in updateRequirements");
+ }
+ } else if (!mStarted) {
+ // start GPS
+ startNavigating();
+ } else {
+ // GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING
+ mAlarmManager.cancel(mTimeoutListener);
+ if (mFixInterval >= NO_FIX_TIMEOUT) {
+ // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
+ // and our fix interval is not short
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, TAG,
+ mTimeoutListener, mHandler);
+ }
}
}
} else {
updateClientUids(new WorkSource());
-
stopNavigating();
- mAlarmManager.cancel(mWakeupIntent);
- mAlarmManager.cancel(mTimeoutIntent);
+ stopBatching();
}
}
private boolean setPositionMode(int mode, int recurrence, int minInterval,
- int preferredAccuracy, int preferredTime, boolean lowPowerMode) {
+ boolean lowPowerMode) {
GnssPositionMode positionMode = new GnssPositionMode(mode, recurrence, minInterval,
- preferredAccuracy, preferredTime, lowPowerMode);
+ 0, 0, lowPowerMode);
if (mLastPositionMode != null && mLastPositionMode.equals(positionMode)) {
return true;
}
boolean result = native_set_position_mode(mode, recurrence, minInterval,
- preferredAccuracy, preferredTime, lowPowerMode);
+ 0, 0, lowPowerMode);
if (result) {
mLastPositionMode = positionMode;
} else {
@@ -1073,6 +1069,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// (2) Inform AppOps service about the list of changes to UIDs.
+ // TODO: this doesn't seem correct, work chain attribution tag != package?
List<WorkChain>[] diffs = WorkSource.diffChains(mClientSource, source);
if (diffs != null) {
List<WorkChain> newChains = diffs[0];
@@ -1096,6 +1093,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
// Update the flat UIDs and names list and inform app-ops of all changes.
+ // TODO: why is GnssLocationProvider the only component using these deprecated APIs?
WorkSource[] changes = mClientSource.setReturningDiffs(source);
if (changes != null) {
WorkSource newWork = changes[0];
@@ -1121,23 +1119,17 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
@Override
public void onExtraCommand(int uid, int pid, String command, Bundle extras) {
-
- final long identity = Binder.clearCallingIdentity();
- try {
- if ("delete_aiding_data".equals(command)) {
- deleteAidingData(extras);
- } else if ("force_time_injection".equals(command)) {
- requestUtcTime();
- } else if ("force_psds_injection".equals(command)) {
- if (mSupportsPsds) {
- downloadPsdsData(/* psdsType= */
- GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX);
- }
- } else {
- Log.w(TAG, "sendExtraCommand: unknown command " + command);
+ if ("delete_aiding_data".equals(command)) {
+ deleteAidingData(extras);
+ } else if ("force_time_injection".equals(command)) {
+ requestUtcTime();
+ } else if ("force_psds_injection".equals(command)) {
+ if (mSupportsPsds) {
+ downloadPsdsData(/* psdsType= */
+ GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX);
}
- } finally {
- Binder.restoreCallingIdentity(identity);
+ } else {
+ Log.w(TAG, "sendExtraCommand: unknown command " + command);
}
}
@@ -1208,9 +1200,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
- mLowPowerMode = mProviderRequest.isLowPower();
if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
- interval, 0, 0, mLowPowerMode)) {
+ interval, mProviderRequest.isLowPower())) {
setStarted(false);
Log.e(TAG, "set_position_mode failed in startNavigating()");
return;
@@ -1229,7 +1220,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// and our fix interval is not short
if (mFixInterval >= NO_FIX_TIMEOUT) {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
+ SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, TAG, mTimeoutListener,
+ mHandler);
}
}
}
@@ -1247,6 +1239,27 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// reset SV count to zero
mLocationExtras.reset();
}
+ mAlarmManager.cancel(mTimeoutListener);
+ mAlarmManager.cancel(mWakeupListener);
+ }
+
+ private void startBatching() {
+ if (DEBUG) {
+ Log.d(TAG, "startBatching " + mFixInterval);
+ }
+ if (native_start_batch(MILLISECONDS.toNanos(mFixInterval), true)) {
+ mBatchingStarted = true;
+ } else {
+ Log.e(TAG, "native_start_batch failed in startBatching()");
+ }
+ }
+
+ private void stopBatching() {
+ if (DEBUG) Log.d(TAG, "stopBatching");
+ if (mBatchingStarted) {
+ native_stop_batch();
+ mBatchingStarted = false;
+ }
}
private void setStarted(boolean started) {
@@ -1259,10 +1272,9 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private void hibernate() {
// stop GPS until our next fix interval arrives
stopNavigating();
- mAlarmManager.cancel(mTimeoutIntent);
- mAlarmManager.cancel(mWakeupIntent);
long now = SystemClock.elapsedRealtime();
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, TAG,
+ mWakeupListener, mHandler);
}
private boolean hasCapability(int capability) {
@@ -1291,7 +1303,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
location.setExtras(mLocationExtras.getBundle());
- reportLocation(location);
+ reportLocation(LocationResult.wrap(location).validate());
if (mStarted) {
mGnssMetrics.logReceivedLocationStatus(hasLatLong);
@@ -1340,7 +1352,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
// slow.
// As we just recievied a location, we'll cancel that timer.
if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
- mAlarmManager.cancel(mTimeoutIntent);
+ mAlarmManager.cancel(mTimeoutListener);
}
}
@@ -1359,11 +1371,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
case GPS_STATUS_SESSION_BEGIN:
mNavigating = true;
break;
- case GPS_STATUS_SESSION_END:
- mNavigating = false;
- break;
case GPS_STATUS_ENGINE_ON:
break;
+ case GPS_STATUS_SESSION_END:
+ // fall through
case GPS_STATUS_ENGINE_OFF:
mNavigating = false;
break;
@@ -1474,7 +1485,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
Log.i(TAG, "restartRequests");
restartLocationRequest();
- mGnssBatchingProvider.resumeIfStarted();
mGnssGeofenceProvider.resumeIfStarted();
}
@@ -1545,13 +1555,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
/**
- * @hide
- */
- public GnssBatchingProvider getGnssBatchingProvider() {
- return mGnssBatchingProvider;
- }
-
- /**
* Interface for GnssMetrics methods.
*/
public interface GnssMetricsProvider {
@@ -1565,7 +1568,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
* @hide
*/
public GnssMetricsProvider getGnssMetricsProvider() {
- return () -> mGnssMetrics.dumpGnssMetricsAsProtoString();
+ return mGnssMetrics::dumpGnssMetricsAsProtoString;
}
/**
@@ -1575,12 +1578,24 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
return mGnssCapabilitiesProvider;
}
- void reportLocationBatch(Location[] locationArray) {
- List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
+ void reportLocationBatch(Location[] locations) {
if (DEBUG) {
- Log.d(TAG, "Location batch of size " + locationArray.length + " reported");
+ Log.d(TAG, "Location batch of size " + locations.length + " reported");
+ }
+
+ Runnable[] listeners;
+ synchronized (mLock) {
+ listeners = mFlushListeners.toArray(new Runnable[0]);
+ mFlushListeners.clear();
+ }
+
+ if (locations.length > 0) {
+ reportLocation(LocationResult.create(Arrays.asList(locations)).validate());
+ }
+
+ for (Runnable listener : listeners) {
+ listener.run();
}
- reportLocation(locations);
}
void downloadPsdsData(int psdsType) {
@@ -1886,9 +1901,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
public void handleMessage(Message msg) {
int message = msg.what;
switch (message) {
- case SET_REQUEST:
- handleSetRequest((ProviderRequest) msg.obj);
- break;
case INJECT_NTP_TIME:
mNtpTimeHelper.retrieveAndInjectNtpTime();
break;
@@ -1898,18 +1910,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
case DOWNLOAD_PSDS_DATA:
handleDownloadPsdsData(msg.arg1);
break;
- case INITIALIZE_HANDLER:
- handleInitialize();
- break;
case REPORT_LOCATION:
handleReportLocation(msg.arg1 == 1, (Location) msg.obj);
break;
case REPORT_SV_STATUS:
handleReportSvStatus((GnssStatus) msg.obj);
break;
- case UPDATE_LOW_POWER_MODE:
- updateLowPowerMode();
- break;
}
if (msg.arg2 == 1) {
// wakelock was taken for this message, release it
@@ -1920,70 +1926,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
}
}
-
- /**
- * This method is bound to the constructor. It is in charge of loading properties and
- * registering for events that will be posted to this handler.
- */
- private void handleInitialize() {
- // it *appears* that native_init() needs to be called at least once before invoking any
- // other gnss methods, so we cycle once on initialization.
- native_init();
- native_cleanup();
-
- if (native_is_gnss_visibility_control_supported()) {
- mGnssVisibilityControl = new GnssVisibilityControl(mContext, mLooper, mNIHandler);
- }
-
- // load default GPS configuration
- // (this configuration might change in the future based on SIM changes)
- reloadGpsProperties();
-
- // listen for events
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(ALARM_WAKEUP);
- intentFilter.addAction(ALARM_TIMEOUT);
- intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
- intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
- intentFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
- mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
-
- mNetworkConnectivityHandler.registerNetworkCallbacks();
-
- // listen for PASSIVE_PROVIDER updates
- LocationManager locManager =
- (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
- locManager.requestLocationUpdates(
- LocationManager.PASSIVE_PROVIDER,
- new LocationRequest.Builder(0)
- .setHiddenFromAppOps(true)
- .build(),
- new HandlerExecutor(this),
- new NetworkLocationListener());
-
- updateEnabled();
- }
- }
-
- private abstract static class LocationChangeListener implements LocationListener {
- private int mNumLocationUpdateRequest;
- }
-
- private final class NetworkLocationListener extends LocationChangeListener {
- @Override
- public void onLocationChanged(Location location) {
- // this callback happens on mHandler looper
- if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
- injectLocation(location);
- }
- }
- }
-
- private final class FusedLocationListener extends LocationChangeListener {
- @Override
- public void onLocationChanged(Location location) {
- injectBestLocation(location);
- }
}
/**
@@ -1991,16 +1933,12 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
*/
private String messageIdAsString(int message) {
switch (message) {
- case SET_REQUEST:
- return "SET_REQUEST";
case INJECT_NTP_TIME:
return "INJECT_NTP_TIME";
case REQUEST_LOCATION:
return "REQUEST_LOCATION";
case DOWNLOAD_PSDS_DATA:
return "DOWNLOAD_PSDS_DATA";
- case INITIALIZE_HANDLER:
- return "INITIALIZE_HANDLER";
case REPORT_LOCATION:
return "REPORT_LOCATION";
case REPORT_SV_STATUS:
@@ -2032,9 +1970,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
TimeUtils.formatDuration(SystemClock.elapsedRealtime()
- mStartedChangedElapsedRealtime, s);
s.append(" ago)").append('\n');
+ s.append("mBatchingEnabled=").append(mBatchingEnabled).append('\n');
+ s.append("mBatchingStarted=").append(mBatchingStarted).append('\n');
+ s.append("mBatchSize=").append(getBatchSize()).append('\n');
s.append("mFixInterval=").append(mFixInterval).append('\n');
- s.append("mLowPowerMode=").append(mLowPowerMode).append('\n');
- s.append("mDisableGpsForPowerManager=").append(mDisableGpsForPowerManager).append('\n');
s.append("mTopHalCapabilities=0x").append(Integer.toHexString(mTopHalCapabilities));
s.append(" ( ");
if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
@@ -2046,7 +1985,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
if (hasCapability(GPS_CAPABILITY_LOW_POWER_MODE)) s.append("LOW_POWER_MODE ");
- if (hasCapability(GPS_CAPABILITY_SATELLITE_BLACKLIST)) s.append("SATELLITE_BLACKLIST ");
+ if (hasCapability(GPS_CAPABILITY_SATELLITE_BLOCKLIST)) s.append("SATELLITE_BLOCKLIST ");
if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) {
s.append("MEASUREMENT_CORRECTIONS ");
}
@@ -2067,7 +2006,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
// preallocated to avoid memory allocation in reportNmea()
- private byte[] mNmeaBuffer = new byte[120];
+ private final byte[] mNmeaBuffer = new byte[120];
private static native boolean native_is_gnss_visibility_control_supported();
@@ -2119,4 +2058,16 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
int lac, int cid);
private native void native_agps_set_id(int type, String setid);
+
+ private static native boolean native_init_batching();
+
+ private static native void native_cleanup_batching();
+
+ private static native int native_get_batch_size();
+
+ private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
+
+ private static native void native_flush_batch();
+
+ private static native boolean native_stop_batch();
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index 2bf6af25422a..47c528b68fb9 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -16,18 +16,14 @@
package com.android.server.location.gnss;
-import static android.location.LocationManager.GPS_PROVIDER;
-
import android.Manifest;
import android.annotation.Nullable;
-import android.app.AppOpsManager;
import android.content.Context;
import android.location.GnssAntennaInfo;
import android.location.GnssMeasurementCorrections;
import android.location.GnssMeasurementsEvent;
import android.location.GnssNavigationMessage;
import android.location.GnssRequest;
-import android.location.IBatchedLocationCallback;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
@@ -37,12 +33,10 @@ import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationManagerInternal;
import android.location.util.identity.CallerIdentity;
-import android.os.Binder;
import android.os.RemoteException;
import android.util.IndentingPrintWriter;
import android.util.Log;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
@@ -77,21 +71,9 @@ public class GnssManagerService implements GnssNative.Callbacks {
private final GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
private final GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
- private final GnssBatchingProvider mGnssBatchingProvider;
private final INetInitiatedListener mNetInitiatedListener;
private final IGpsGeofenceHardware mGpsGeofenceProxy;
- private final Object mGnssBatchingLock = new Object();
-
- @GuardedBy("mGnssBatchingLock")
- @Nullable private IBatchedLocationCallback mGnssBatchingCallback;
- @GuardedBy("mGnssBatchingLock")
- @Nullable private CallerIdentity mGnssBatchingIdentity;
- @GuardedBy("mGnssBatchingLock")
- @Nullable private Binder.DeathRecipient mGnssBatchingDeathRecipient;
- @GuardedBy("mGnssBatchingLock")
- private boolean mGnssBatchingInProgress = false;
-
public GnssManagerService(Context context, Injector injector) {
this(context, injector, null);
}
@@ -121,7 +103,6 @@ public class GnssManagerService implements GnssNative.Callbacks {
mGnssSystemInfoProvider = mGnssLocationProvider.getGnssSystemInfoProvider();
mGnssMetricsProvider = mGnssLocationProvider.getGnssMetricsProvider();
mGnssCapabilitiesProvider = mGnssLocationProvider.getGnssCapabilitiesProvider();
- mGnssBatchingProvider = mGnssLocationProvider.getGnssBatchingProvider();
mNetInitiatedListener = mGnssLocationProvider.getNetInitiatedListener();
mGpsGeofenceProxy = mGnssLocationProvider.getGpsGeofenceProxy();
@@ -171,108 +152,7 @@ public class GnssManagerService implements GnssNative.Callbacks {
* Get size of GNSS batch (GNSS location results are batched together for power savings).
*/
public int getGnssBatchSize() {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
-
- synchronized (mGnssBatchingLock) {
- return mGnssBatchingProvider.getBatchSize();
- }
- }
-
- /**
- * Starts GNSS batch collection. GNSS positions are collected in a batch before being delivered
- * as a collection.
- */
- public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName,
- String attributionTag) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
- mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
-
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
- if (!mAppOpsHelper.checkOpNoThrow(AppOpsManager.OP_FINE_LOCATION, identity)) {
- return false;
- }
-
- synchronized (mGnssBatchingLock) {
- if (mGnssBatchingInProgress) {
- // Current design does not expect multiple starts to be called repeatedly
- Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
- stopGnssBatch();
- }
-
- mGnssBatchingInProgress = true;
- return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
- }
- }
-
- /**
- * Adds a GNSS batching callback for delivering GNSS location batch results.
- */
- public boolean setGnssBatchingCallback(IBatchedLocationCallback callback, String packageName,
- @Nullable String attributionTag) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
- mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
-
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
-
- synchronized (mGnssBatchingLock) {
- Binder.DeathRecipient deathRecipient = () -> {
- synchronized (mGnssBatchingLock) {
- stopGnssBatch();
- removeGnssBatchingCallback();
- }
- };
-
- try {
- callback.asBinder().linkToDeath(mGnssBatchingDeathRecipient, 0);
- mGnssBatchingCallback = callback;
- mGnssBatchingIdentity = identity;
- mGnssBatchingDeathRecipient = deathRecipient;
- return true;
- } catch (RemoteException e) {
- return false;
- }
- }
- }
-
- /**
- * Force flush GNSS location results from batch.
- */
- public void flushGnssBatch() {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
-
- synchronized (mGnssBatchingLock) {
- mGnssBatchingProvider.flush();
- }
- }
-
- /**
- * Removes GNSS batching callback.
- */
- public void removeGnssBatchingCallback() {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
-
- synchronized (mGnssBatchingLock) {
- if (mGnssBatchingCallback == null) {
- return;
- }
-
- mGnssBatchingCallback.asBinder().unlinkToDeath(mGnssBatchingDeathRecipient, 0);
- mGnssBatchingCallback = null;
- mGnssBatchingIdentity = null;
- mGnssBatchingDeathRecipient = null;
- }
- }
-
- /**
- * Stop GNSS batch collection.
- */
- public boolean stopGnssBatch() {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
-
- synchronized (mGnssBatchingLock) {
- mGnssBatchingInProgress = false;
- return mGnssBatchingProvider.stop();
- }
+ return mGnssLocationProvider.getBatchSize();
}
/**
@@ -377,34 +257,6 @@ public class GnssManagerService implements GnssNative.Callbacks {
}
/**
- * Report location results to GNSS batching listener.
- */
- public void onReportLocation(List<Location> locations) {
- IBatchedLocationCallback callback;
- CallerIdentity identity;
- synchronized (mGnssBatchingLock) {
- callback = mGnssBatchingCallback;
- identity = mGnssBatchingIdentity;
- }
-
- if (callback == null || identity == null) {
- return;
- }
-
- if (!mLocationManagerInternal.isProviderEnabledForUser(GPS_PROVIDER,
- identity.getUserId())) {
- Log.w(TAG, "reportLocationBatch() called without user permission");
- return;
- }
-
- try {
- callback.onLocationBatch(locations);
- } catch (RemoteException e) {
- // ignore
- }
- }
-
- /**
* Dump info for debugging.
*/
public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
@@ -434,12 +286,6 @@ public class GnssManagerService implements GnssNative.Callbacks {
ipw.increaseIndent();
mGnssStatusProvider.dump(fd, ipw, args);
ipw.decreaseIndent();
-
- synchronized (mGnssBatchingLock) {
- if (mGnssBatchingInProgress) {
- ipw.println("GNSS batching in progress");
- }
- }
}
// all native callbacks - to be funneled to various locations as appropriate
diff --git a/services/core/java/com/android/server/location/gnss/GnssSatelliteBlacklistHelper.java b/services/core/java/com/android/server/location/gnss/GnssSatelliteBlocklistHelper.java
index 426ce8c2c258..baee5bfec899 100644
--- a/services/core/java/com/android/server/location/gnss/GnssSatelliteBlacklistHelper.java
+++ b/services/core/java/com/android/server/location/gnss/GnssSatelliteBlocklistHelper.java
@@ -33,72 +33,72 @@ import java.util.List;
/**
* Detects denylist change and updates the denylist.
*/
-class GnssSatelliteBlacklistHelper {
+class GnssSatelliteBlocklistHelper {
- private static final String TAG = "GnssBlacklistHelper";
- private static final String BLACKLIST_DELIMITER = ",";
+ private static final String TAG = "GnssBlocklistHelper";
+ private static final String BLOCKLIST_DELIMITER = ",";
private final Context mContext;
- private final GnssSatelliteBlacklistCallback mCallback;
+ private final GnssSatelliteBlocklistCallback mCallback;
- interface GnssSatelliteBlacklistCallback {
- void onUpdateSatelliteBlacklist(int[] constellations, int[] svids);
+ interface GnssSatelliteBlocklistCallback {
+ void onUpdateSatelliteBlocklist(int[] constellations, int[] svids);
}
- GnssSatelliteBlacklistHelper(Context context, Looper looper,
- GnssSatelliteBlacklistCallback callback) {
+ GnssSatelliteBlocklistHelper(Context context, Looper looper,
+ GnssSatelliteBlocklistCallback callback) {
mContext = context;
mCallback = callback;
ContentObserver contentObserver = new ContentObserver(new Handler(looper)) {
@Override
public void onChange(boolean selfChange) {
- updateSatelliteBlacklist();
+ updateSatelliteBlocklist();
}
};
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(
- Settings.Global.GNSS_SATELLITE_BLACKLIST),
+ Settings.Global.GNSS_SATELLITE_BLOCKLIST),
true,
contentObserver, UserHandle.USER_ALL);
}
- void updateSatelliteBlacklist() {
+ void updateSatelliteBlocklist() {
ContentResolver resolver = mContext.getContentResolver();
- String blacklist = Settings.Global.getString(
+ String blocklist = Settings.Global.getString(
resolver,
- Settings.Global.GNSS_SATELLITE_BLACKLIST);
- if (blacklist == null) {
- blacklist = "";
+ Settings.Global.GNSS_SATELLITE_BLOCKLIST);
+ if (blocklist == null) {
+ blocklist = "";
}
- Log.i(TAG, String.format("Update GNSS satellite blacklist: %s", blacklist));
+ Log.i(TAG, String.format("Update GNSS satellite blocklist: %s", blocklist));
- List<Integer> blacklistValues;
+ List<Integer> blocklistValues;
try {
- blacklistValues = parseSatelliteBlacklist(blacklist);
+ blocklistValues = parseSatelliteBlocklist(blocklist);
} catch (NumberFormatException e) {
- Log.e(TAG, "Exception thrown when parsing blacklist string.", e);
+ Log.e(TAG, "Exception thrown when parsing blocklist string.", e);
return;
}
- if (blacklistValues.size() % 2 != 0) {
- Log.e(TAG, "blacklist string has odd number of values."
- + "Aborting updateSatelliteBlacklist");
+ if (blocklistValues.size() % 2 != 0) {
+ Log.e(TAG, "blocklist string has odd number of values."
+ + "Aborting updateSatelliteBlocklist");
return;
}
- int length = blacklistValues.size() / 2;
+ int length = blocklistValues.size() / 2;
int[] constellations = new int[length];
int[] svids = new int[length];
for (int i = 0; i < length; i++) {
- constellations[i] = blacklistValues.get(i * 2);
- svids[i] = blacklistValues.get(i * 2 + 1);
+ constellations[i] = blocklistValues.get(i * 2);
+ svids[i] = blocklistValues.get(i * 2 + 1);
}
- mCallback.onUpdateSatelliteBlacklist(constellations, svids);
+ mCallback.onUpdateSatelliteBlocklist(constellations, svids);
}
@VisibleForTesting
- static List<Integer> parseSatelliteBlacklist(String blacklist) throws NumberFormatException {
- String[] strings = blacklist.split(BLACKLIST_DELIMITER);
+ static List<Integer> parseSatelliteBlocklist(String blocklist) throws NumberFormatException {
+ String[] strings = blocklist.split(BLOCKLIST_DELIMITER);
List<Integer> parsed = new ArrayList<>(strings.length);
for (String string : strings) {
string = string.trim();
diff --git a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
index d6b179bab5a2..709e23615b14 100644
--- a/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/BinderListenerRegistration.java
@@ -32,8 +32,7 @@ import android.util.Log;
* @param <TListener> listener type
*/
public abstract class BinderListenerRegistration<TRequest, TListener> extends
- RemoteListenerRegistration<TRequest, TListener> implements
- Binder.DeathRecipient {
+ RemoteListenerRegistration<TRequest, TListener> implements Binder.DeathRecipient {
/**
* Interface to allow binder retrieval when keys are not themselves IBinders.
diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
index 6b936169c82f..33b08d41c07d 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
@@ -79,8 +79,7 @@ import java.util.function.Predicate;
* @param <TMergedRegistration> merged registration type
*/
public abstract class ListenerMultiplexer<TKey, TListener,
- TRegistration extends ListenerRegistration<TListener>,
- TMergedRegistration> {
+ TRegistration extends ListenerRegistration<TListener>, TMergedRegistration> {
@GuardedBy("mRegistrations")
private final ArrayMap<TKey, TRegistration> mRegistrations = new ArrayMap<>();
@@ -484,6 +483,38 @@ public abstract class ListenerMultiplexer<TKey, TListener,
}
}
+ /**
+ * Evaluates the predicate on a registration with the given key. The predicate should return
+ * true if the active state of the registration may have changed as a result. If the active
+ * state of the registration has changed, {@link #updateService()} will automatically be invoked
+ * to handle the resulting changes. Returns true if there is a registration with the given key
+ * (and thus the predicate was invoked), and false otherwise.
+ */
+ protected final boolean updateRegistration(@NonNull Object key,
+ @NonNull Predicate<TRegistration> predicate) {
+ synchronized (mRegistrations) {
+ // since updating a registration can invoke a variety of callbacks, we need to ensure
+ // those callbacks themselves do not re-enter, as this could lead to out-of-order
+ // callbacks. note that try-with-resources ordering is meaningful here as well. we want
+ // to close the reentrancy guard first, as this may generate additional service updates,
+ // then close the update service buffer.
+ try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
+ ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {
+
+ int index = mRegistrations.indexOfKey(key);
+ if (index < 0) {
+ return false;
+ }
+
+ TRegistration registration = mRegistrations.valueAt(index);
+ if (predicate.test(registration)) {
+ onRegistrationActiveChanged(registration);
+ }
+ return true;
+ }
+ }
+ }
+
@GuardedBy("mRegistrations")
private void onRegistrationActiveChanged(TRegistration registration) {
if (Build.IS_DEBUGGABLE) {
diff --git a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
index fa21b3a8e369..711dde89ef13 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
@@ -16,7 +16,6 @@
package com.android.server.location.listeners;
-
import android.annotation.Nullable;
import com.android.internal.listeners.ListenerExecutor;
@@ -108,8 +107,8 @@ public class ListenerRegistration<TListener> implements ListenerExecutor {
* May be overridden by subclasses to handle listener operation failures. The default behavior
* is to further propagate any exceptions. Will always be invoked on the executor thread.
*/
- protected void onOperationFailure(ListenerOperation<TListener> operation, Exception e) {
- throw new AssertionError(e);
+ protected void onOperationFailure(ListenerOperation<TListener> operation, Exception exception) {
+ throw new AssertionError(exception);
}
/**
diff --git a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
index 43eb3ca128c6..280d59af7d2a 100644
--- a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
@@ -211,6 +211,8 @@ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider {
* {@link SimulatedLocationTimeZoneProviderProxy}. If not, the event is logged but discarded.
*/
void simulateBinderProviderEvent(SimulatedBinderProviderEvent event) {
+ mThreadingDomain.assertCurrentThread();
+
if (!(mProxy instanceof SimulatedLocationTimeZoneProviderProxy)) {
Slog.w(TAG, mProxy + " is not a " + SimulatedLocationTimeZoneProviderProxy.class
+ ", event=" + event);
diff --git a/services/core/java/com/android/server/location/timezone/ControllerImpl.java b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
index d48263722d38..70c1aeff0ce8 100644
--- a/services/core/java/com/android/server/location/timezone/ControllerImpl.java
+++ b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
@@ -404,13 +404,6 @@ class ControllerImpl extends LocationTimeZoneProviderController {
return;
}
- // Consistency check for user. This may be possible as there are various races around
- // current user switches.
- if (!Objects.equals(event.getUserHandle(), mCurrentUserConfiguration.getUserHandle())) {
- warnLog("Using event=" + event + " from a different user="
- + mCurrentUserConfiguration);
- }
-
if (!mCurrentUserConfiguration.getGeoDetectionEnabledBehavior()) {
// This should not happen: the provider should not be in an enabled state if the user
// does not have geodetection enabled.
@@ -567,10 +560,12 @@ class ControllerImpl extends LocationTimeZoneProviderController {
}
/**
- * Asynchronously passes a {@link SimulatedBinderProviderEvent] to the appropriate provider.
+ * Passes a {@link SimulatedBinderProviderEvent] to the appropriate provider.
* If the provider name does not match a known provider, then the event is logged and discarded.
*/
void simulateBinderProviderEvent(@NonNull SimulatedBinderProviderEvent event) {
+ mThreadingDomain.assertCurrentThread();
+
String targetProviderName = event.getProviderName();
LocationTimeZoneProvider targetProvider;
if (Objects.equals(mPrimaryProvider.getName(), targetProviderName)) {
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
index a817759c9783..74491c5739f3 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
@@ -87,7 +87,7 @@ public class LocationTimeZoneManagerService extends Binder {
// Binder and is registered as a binder service so it can receive shell commands.
publishBinderService("location_time_zone_manager", mService);
} else {
- Slog.i(TAG, getClass() + " is compile-time disabled");
+ Slog.i(TAG, getClass() + " is disabled");
}
}
diff --git a/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
index 38018779aed1..94062faa7a1b 100644
--- a/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
@@ -78,10 +78,14 @@ class RealLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
}
private boolean register() {
- return mServiceWatcher.register();
+ boolean resolves = mServiceWatcher.checkServiceResolves();
+ if (resolves) {
+ mServiceWatcher.register();
+ }
+ return resolves;
}
- private void onBind(IBinder binder, ComponentName componentName) throws RemoteException {
+ private void onBind(IBinder binder, ComponentName componentName) {
processServiceWatcherCallbackOnThreadingDomainThread(() -> onBindOnHandlerThread(binder));
}
diff --git a/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java b/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
index f1d37237872b..6bf6539f95dc 100644
--- a/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
+++ b/services/core/java/com/android/server/location/timezone/SimulatedBinderProviderEvent.java
@@ -25,11 +25,9 @@ import static com.android.server.location.timezone.LocationTimeZoneManagerServic
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.location.timezone.LocationTimeZoneEvent;
import android.os.ShellCommand;
import android.os.SystemClock;
-import android.os.UserHandle;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -119,8 +117,7 @@ final class SimulatedBinderProviderEvent {
private static LocationTimeZoneEvent parseLocationTimeZoneEventArgs(ShellCommand shellCommand) {
LocationTimeZoneEvent.Builder eventBuilder = new LocationTimeZoneEvent.Builder()
- .setElapsedRealtimeNanos(SystemClock.elapsedRealtime())
- .setUserHandle(UserHandle.of(ActivityManager.getCurrentUser()));
+ .setElapsedRealtimeNanos(SystemClock.elapsedRealtime());
String eventTypeString = shellCommand.getNextArgRequired();
switch (eventTypeString.toUpperCase()) {
diff --git a/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
index 462bcab80c1b..604ff74e71ac 100644
--- a/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/SimulatedLocationTimeZoneProviderProxy.java
@@ -37,10 +37,11 @@ import java.util.Objects;
*/
class SimulatedLocationTimeZoneProviderProxy extends LocationTimeZoneProviderProxy {
- @GuardedBy("mProxyLock")
+ @GuardedBy("mSharedLock")
@NonNull private LocationTimeZoneProviderRequest mRequest;
- @NonNull private ReferenceWithHistory<String> mLastEvent = new ReferenceWithHistory<>(50);
+ @GuardedBy("mSharedLock")
+ @NonNull private final ReferenceWithHistory<String> mLastEvent = new ReferenceWithHistory<>(50);
SimulatedLocationTimeZoneProviderProxy(
@NonNull Context context, @NonNull ThreadingDomain threadingDomain) {
@@ -49,29 +50,36 @@ class SimulatedLocationTimeZoneProviderProxy extends LocationTimeZoneProviderPro
}
void simulate(@NonNull SimulatedBinderProviderEvent event) {
- switch (event.getEventType()) {
- case INJECTED_EVENT_TYPE_ON_BIND: {
- mLastEvent.set("Simulating onProviderBound(), event=" + event);
- mThreadingDomain.post(this::onBindOnHandlerThread);
- break;
- }
- case INJECTED_EVENT_TYPE_ON_UNBIND: {
- mLastEvent.set("Simulating onProviderUnbound(), event=" + event);
- mThreadingDomain.post(this::onUnbindOnHandlerThread);
- break;
- }
- case INJECTED_EVENT_TYPE_LOCATION_TIME_ZONE_EVENT: {
- if (!mRequest.getReportLocationTimeZone()) {
- mLastEvent.set("Test event=" + event + " is testing an invalid case:"
- + " reporting is off. mRequest=" + mRequest);
+ mThreadingDomain.assertCurrentThread();
+
+ Objects.requireNonNull(event);
+
+ synchronized (mSharedLock) {
+ switch (event.getEventType()) {
+ case INJECTED_EVENT_TYPE_ON_BIND: {
+ mLastEvent.set("Simulating onProviderBound(), event=" + event);
+ mThreadingDomain.post(this::onBindOnHandlerThread);
+ break;
+ }
+ case INJECTED_EVENT_TYPE_ON_UNBIND: {
+ mLastEvent.set("Simulating onProviderUnbound(), event=" + event);
+ mThreadingDomain.post(this::onUnbindOnHandlerThread);
+ break;
+ }
+ case INJECTED_EVENT_TYPE_LOCATION_TIME_ZONE_EVENT: {
+ if (!mRequest.getReportLocationTimeZone()) {
+ mLastEvent.set("Test event=" + event + " is testing an invalid case:"
+ + " reporting is off. mRequest=" + mRequest);
+ }
+ mLastEvent.set("Simulating LocationTimeZoneEvent, event=" + event);
+ handleLocationTimeZoneEvent(event.getLocationTimeZoneEvent());
+ break;
+ }
+ default: {
+ mLastEvent.set("Unknown simulated event type. event=" + event);
+ throw new IllegalArgumentException(
+ "Unknown simulated event type. event=" + event);
}
- mLastEvent.set("Simulating LocationTimeZoneEvent, event=" + event);
- handleLocationTimeZoneEvent(event.getLocationTimeZoneEvent());
- break;
- }
- default: {
- mLastEvent.set("Unknown simulated event type. event=" + event);
- throw new IllegalArgumentException("Unknown simulated event type. event=" + event);
}
}
}
diff --git a/services/core/java/com/android/server/location/util/LocationEventLog.java b/services/core/java/com/android/server/location/util/LocationEventLog.java
index e4c354b1c070..134b1422eee6 100644
--- a/services/core/java/com/android/server/location/util/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/util/LocationEventLog.java
@@ -22,6 +22,8 @@ import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF
import static android.os.PowerManager.LOCATION_MODE_NO_CHANGE;
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
+import static com.android.server.location.LocationManagerService.D;
+
import android.annotation.Nullable;
import android.location.LocationRequest;
import android.location.util.identity.CallerIdentity;
@@ -29,14 +31,13 @@ import android.os.Build;
import android.os.PowerManager.LocationPowerSaveMode;
import com.android.internal.location.ProviderRequest;
-import com.android.server.location.LocationManagerService;
import com.android.server.utils.eventlog.LocalEventLog;
/** In memory event log for location events. */
public class LocationEventLog extends LocalEventLog {
private static int getLogSize() {
- if (Build.IS_DEBUGGABLE || LocationManagerService.D) {
+ if (Build.IS_DEBUGGABLE || D) {
return 500;
} else {
return 200;
@@ -90,14 +91,18 @@ public class LocationEventLog extends LocalEventLog {
}
/** Logs a new incoming location for a location provider. */
- public synchronized void logProviderReceivedLocation(String provider) {
- addLogEvent(EVENT_PROVIDER_RECEIVE_LOCATION, provider);
+ public synchronized void logProviderReceivedLocations(String provider, int numLocations) {
+ if (Build.IS_DEBUGGABLE || D) {
+ addLogEvent(EVENT_PROVIDER_RECEIVE_LOCATION, provider, numLocations);
+ }
}
/** Logs a location deliver for a client of a location provider. */
- public synchronized void logProviderDeliveredLocation(String provider,
+ public synchronized void logProviderDeliveredLocations(String provider, int numLocations,
CallerIdentity identity) {
- addLogEvent(EVENT_PROVIDER_DELIVER_LOCATION, provider, identity);
+ if (Build.IS_DEBUGGABLE || D) {
+ addLogEvent(EVENT_PROVIDER_DELIVER_LOCATION, provider, numLocations, identity);
+ }
}
/** Logs that the location power save mode has changed. */
@@ -126,10 +131,11 @@ public class LocationEventLog extends LocalEventLog {
return new ProviderUpdateEvent(timeDelta, (String) args[0],
(ProviderRequest) args[1]);
case EVENT_PROVIDER_RECEIVE_LOCATION:
- return new ProviderReceiveLocationEvent(timeDelta, (String) args[0]);
+ return new ProviderReceiveLocationEvent(timeDelta, (String) args[0],
+ (Integer) args[1]);
case EVENT_PROVIDER_DELIVER_LOCATION:
return new ProviderDeliverLocationEvent(timeDelta, (String) args[0],
- (CallerIdentity) args[1]);
+ (Integer) args[1], (CallerIdentity) args[2]);
case EVENT_LOCATION_POWER_SAVE_MODE_CHANGE:
return new LocationPowerSaveModeEvent(timeDelta, (Integer) args[0]);
default:
@@ -226,33 +232,38 @@ public class LocationEventLog extends LocalEventLog {
private static class ProviderReceiveLocationEvent extends LogEvent {
private final String mProvider;
+ private final int mNumLocations;
- private ProviderReceiveLocationEvent(long timeDelta, String provider) {
+ private ProviderReceiveLocationEvent(long timeDelta, String provider, int numLocations) {
super(timeDelta);
mProvider = provider;
+ mNumLocations = numLocations;
}
@Override
public String getLogString() {
- return mProvider + " provider received location";
+ return mProvider + " provider received location[" + mNumLocations + "]";
}
}
private static class ProviderDeliverLocationEvent extends LogEvent {
private final String mProvider;
+ private final int mNumLocations;
@Nullable private final CallerIdentity mIdentity;
- private ProviderDeliverLocationEvent(long timeDelta, String provider,
+ private ProviderDeliverLocationEvent(long timeDelta, String provider, int numLocations,
@Nullable CallerIdentity identity) {
super(timeDelta);
mProvider = provider;
+ mNumLocations = numLocations;
mIdentity = identity;
}
@Override
public String getLogString() {
- return mProvider + " provider delivered location to " + mIdentity;
+ return mProvider + " provider delivered location[" + mNumLocations + "] to "
+ + mIdentity;
}
}
diff --git a/services/core/java/com/android/server/media/MediaServerUtils.java b/services/core/java/com/android/server/media/MediaServerUtils.java
new file mode 100644
index 000000000000..5fa2b1ceaae9
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaServerUtils.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.server.media;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+
+import java.io.PrintWriter;
+
+/**
+ * Util class for media server.
+ */
+class MediaServerUtils {
+ /**
+ * Verify that caller holds {@link android.Manifest.permission#DUMP}.
+ */
+ public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
+ if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump " + tag + " from from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ + " due to missing android.permission.DUMP permission");
+ return false;
+ } else {
+ return true;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 828a0ac94c0c..c23bfc442bd9 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -44,7 +44,7 @@ import android.content.pm.UserInfo;
import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioSystem;
-import android.media.IRemoteVolumeController;
+import android.media.IRemoteVolumeControllerCallback;
import android.media.Session2Token;
import android.media.session.IActiveSessionsListener;
import android.media.session.IOnMediaKeyEventDispatchedListener;
@@ -83,9 +83,7 @@ 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.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.Watchdog;
import com.android.server.Watchdog.Monitor;
@@ -146,7 +144,7 @@ public class MediaSessionService extends SystemService implements Monitor {
// Used to notify System UI and Settings when remote volume was changed.
@GuardedBy("mLock")
- final RemoteCallbackList<IRemoteVolumeController> mRemoteVolumeControllers =
+ final RemoteCallbackList<IRemoteVolumeControllerCallback> mRemoteVolumeControllers =
new RemoteCallbackList<>();
private SessionPolicyProvider mCustomSessionPolicyProvider;
@@ -309,8 +307,9 @@ public class MediaSessionService extends SystemService implements Monitor {
MediaSession.Token token = session.getSessionToken();
for (int i = size - 1; i >= 0; i--) {
try {
- IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
- cb.remoteVolumeChanged(token, flags);
+ IRemoteVolumeControllerCallback cb =
+ mRemoteVolumeControllers.getBroadcastItem(i);
+ cb.onVolumeChanged(token, flags);
} catch (Exception e) {
Log.w(TAG, "Error sending volume change.", e);
}
@@ -715,8 +714,9 @@ public class MediaSessionService extends SystemService implements Monitor {
for (int i = size - 1; i >= 0; i--) {
try {
- IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
- cb.updateRemoteController(token);
+ IRemoteVolumeControllerCallback cb =
+ mRemoteVolumeControllers.getBroadcastItem(i);
+ cb.onSessionChanged(token);
} catch (Exception e) {
Log.w(TAG, "Error sending default remote volume.", e);
}
@@ -991,6 +991,8 @@ public class MediaSessionService extends SystemService implements Monitor {
} else if (mCurrentFullUserRecord.mLastMediaButtonReceiverHolder != null) {
String packageName = mLastMediaButtonReceiverHolder.getPackageName();
callback.onMediaKeyEventSessionChanged(packageName, null);
+ } else {
+ callback.onMediaKeyEventSessionChanged("", null);
}
} catch (RemoteException e) {
Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
@@ -1843,7 +1845,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
@Override
- public void registerRemoteVolumeController(IRemoteVolumeController rvc) {
+ public void registerRemoteVolumeControllerCallback(IRemoteVolumeControllerCallback rvc) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
@@ -1858,7 +1860,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
@Override
- public void unregisterRemoteVolumeController(IRemoteVolumeController rvc) {
+ public void unregisterRemoteVolumeControllerCallback(IRemoteVolumeControllerCallback rvc) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
@@ -1881,7 +1883,7 @@ public class MediaSessionService extends SystemService implements Monitor {
@Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ if (!MediaServerUtils.checkDumpPermission(mContext, TAG, pw)) return;
pw.println("MEDIA SESSION SERVICE (dumpsys media_session)");
pw.println();
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 06cebac501e7..661d38df12ae 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -18,6 +18,8 @@ package com.android.server.net;
import static android.provider.Settings.ACTION_VPN_SETTINGS;
+import static com.android.server.connectivity.NetworkNotificationManager.NOTIFICATION_VPN;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
@@ -42,7 +44,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
-import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.ConnectivityService;
import com.android.server.EventLogTags;
import com.android.server.connectivity.Vpn;
@@ -256,7 +257,7 @@ public class LockdownVpnTracker {
private void showNotification(int titleRes, int iconRes) {
final Notification.Builder builder =
- new Notification.Builder(mContext, SystemNotificationChannels.VPN)
+ new Notification.Builder(mContext, NOTIFICATION_VPN)
.setWhen(0)
.setSmallIcon(iconRes)
.setContentTitle(mContext.getString(titleRes))
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 35d36216e63e..dd6c8f558354 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -559,6 +559,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
/** Set of all merged subscriberId as of last update */
@GuardedBy("mNetworkPoliciesSecondLock")
private List<String[]> mMergedSubscriberIds = new ArrayList<>();
+ /** Map from subId to carrierConfig as of last update */
+ @GuardedBy("mNetworkPoliciesSecondLock")
+ private final SparseArray<PersistableBundle> mSubIdToCarrierConfig =
+ new SparseArray<PersistableBundle>();
/**
* Indicates the uids restricted by admin from accessing metered data. It's a mapping from
@@ -1186,7 +1190,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long totalBytes = getTotalBytes(policy.template, cycleStart, cycleEnd);
// Carrier might want to manage notifications themselves
- final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
+ final PersistableBundle config = mSubIdToCarrierConfig.get(subId);
if (!CarrierConfigManager.isConfigForIdentifiedCarrier(config)) {
if (LOGV) Slog.v(TAG, "isConfigForIdentifiedCarrier returned false");
// Don't show notifications until we confirm that the loaded config is from an
@@ -1831,8 +1835,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final List<String[]> mergedSubscriberIdsList = new ArrayList();
final SparseArray<String> subIdToSubscriberId = new SparseArray<>(subList.size());
+ final SparseArray<PersistableBundle> subIdToCarrierConfig =
+ new SparseArray<PersistableBundle>();
for (final SubscriptionInfo sub : subList) {
- final TelephonyManager tmSub = tm.createForSubscriptionId(sub.getSubscriptionId());
+ final int subId = sub.getSubscriptionId();
+ final TelephonyManager tmSub = tm.createForSubscriptionId(subId);
final String subscriberId = tmSub.getSubscriberId();
if (!TextUtils.isEmpty(subscriberId)) {
subIdToSubscriberId.put(tmSub.getSubscriptionId(), subscriberId);
@@ -1843,6 +1850,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final String[] mergedSubscriberId = ArrayUtils.defeatNullable(
tmSub.getMergedImsisFromGroup());
mergedSubscriberIdsList.add(mergedSubscriberId);
+
+ final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
+ if (config != null) {
+ subIdToCarrierConfig.put(subId, config);
+ } else {
+ Slog.e(TAG, "Missing CarrierConfig for subId " + subId);
+ }
}
synchronized (mNetworkPoliciesSecondLock) {
@@ -1853,6 +1867,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
mMergedSubscriberIds = mergedSubscriberIdsList;
+
+ mSubIdToCarrierConfig.clear();
+ for (int i = 0; i < subIdToCarrierConfig.size(); i++) {
+ mSubIdToCarrierConfig.put(subIdToCarrierConfig.keyAt(i),
+ subIdToCarrierConfig.valueAt(i));
+ }
}
Trace.traceEnd(TRACE_TAG_NETWORK);
@@ -2172,7 +2192,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
} else {
- final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
+ final PersistableBundle config = mSubIdToCarrierConfig.get(subId);
final int currentCycleDay;
if (policy.cycleRule.isMonthly()) {
currentCycleDay = policy.cycleRule.start.getDayOfMonth();
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 12c24d418611..81a6641de8a4 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -1084,12 +1084,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return nativeIfaceStats;
} else {
// When tethering offload is in use, nativeIfaceStats does not contain usage from
- // offload, add it back here.
- // When tethering offload is not in use, nativeIfaceStats contains tethering usage.
- // this does not cause double-counting of tethering traffic, because
- // NetdTetheringStatsProvider returns zero NetworkStats
- // when called with STATS_PER_IFACE.
- return nativeIfaceStats + getTetherStats(iface, type);
+ // offload, add it back here. Note that the included statistics might be stale
+ // since polling newest stats from hardware might impact system health and not
+ // suitable for TrafficStats API use cases.
+ return nativeIfaceStats + getProviderIfaceStats(iface, type);
}
}
@@ -1100,39 +1098,28 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return nativeTotalStats;
} else {
// Refer to comment in getIfaceStats
- return nativeTotalStats + getTetherStats(IFACE_ALL, type);
+ return nativeTotalStats + getProviderIfaceStats(IFACE_ALL, type);
}
}
- private long getTetherStats(String iface, int type) {
- final NetworkStats tetherSnapshot;
- final long token = Binder.clearCallingIdentity();
- try {
- tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE);
- } catch (RemoteException e) {
- Slog.w(TAG, "Error get TetherStats: " + e);
- return 0;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- HashSet<String> limitIfaces;
+ private long getProviderIfaceStats(@Nullable String iface, int type) {
+ final NetworkStats providerSnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE);
+ final HashSet<String> limitIfaces;
if (iface == IFACE_ALL) {
limitIfaces = null;
} else {
- limitIfaces = new HashSet<String>();
+ limitIfaces = new HashSet<>();
limitIfaces.add(iface);
}
- NetworkStats.Entry entry = tetherSnapshot.getTotal(null, limitIfaces);
- if (LOGD) Slog.d(TAG, "TetherStats: iface=" + iface + " type=" + type +
- " entry=" + entry);
+ final NetworkStats.Entry entry = providerSnapshot.getTotal(null, limitIfaces);
switch (type) {
- case 0: // TYPE_RX_BYTES
+ case TrafficStats.TYPE_RX_BYTES:
return entry.rxBytes;
- case 1: // TYPE_RX_PACKETS
+ case TrafficStats.TYPE_RX_PACKETS:
return entry.rxPackets;
- case 2: // TYPE_TX_BYTES
+ case TrafficStats.TYPE_TX_BYTES:
return entry.txBytes;
- case 3: // TYPE_TX_PACKETS
+ case TrafficStats.TYPE_TX_PACKETS:
return entry.txPackets;
default:
return 0;
@@ -1429,14 +1416,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final NetworkStats devSnapshot = readNetworkStatsSummaryDev();
Trace.traceEnd(TRACE_TAG_NETWORK);
- // Tethering snapshot for dev and xt stats. Counts per-interface data from tethering stats
- // providers that isn't already counted by dev and XT stats.
- Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotTether");
- final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE);
- Trace.traceEnd(TRACE_TAG_NETWORK);
- xtSnapshot.combineAllValues(tetherSnapshot);
- devSnapshot.combineAllValues(tetherSnapshot);
-
// Snapshot for dev/xt stats from all custom stats providers. Counts per-interface data
// from stats providers that isn't already counted by dev and XT stats.
Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotStatsProvider");
@@ -1511,29 +1490,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0;
final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
- // Request asynchronous stats update from all providers for next poll. And wait a bit of
- // time to allow providers report-in given that normally binder call should be fast. Note
- // that size of list might be changed because addition/removing at the same time. For
- // addition, the stats of the missed provider can only be collected in next poll;
- // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS
- // once that happened.
- // TODO: request with a valid token.
- Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate");
- final int registeredCallbackCount = mStatsProviderCbList.size();
- mStatsProviderSem.drainPermits();
- invokeForAllStatsProviderCallbacks(
- (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */));
- try {
- mStatsProviderSem.tryAcquire(registeredCallbackCount,
- MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- // Strictly speaking it's possible a provider happened to deliver between the timeout
- // and the log, and that doesn't matter too much as this is just a debug log.
- Log.d(TAG, "requestStatsUpdate - providers responded "
- + mStatsProviderSem.availablePermits()
- + "/" + registeredCallbackCount + " : " + e);
- }
- Trace.traceEnd(TRACE_TAG_NETWORK);
+ performPollFromProvidersLocked();
// TODO: consider marking "untrusted" times in historical stats
final long currentTime = mClock.millis();
@@ -1578,6 +1535,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
Trace.traceEnd(TRACE_TAG_NETWORK);
}
+ @GuardedBy("mStatsLock")
+ private void performPollFromProvidersLocked() {
+ // Request asynchronous stats update from all providers for next poll. And wait a bit of
+ // time to allow providers report-in given that normally binder call should be fast. Note
+ // that size of list might be changed because addition/removing at the same time. For
+ // addition, the stats of the missed provider can only be collected in next poll;
+ // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS
+ // once that happened.
+ // TODO: request with a valid token.
+ Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate");
+ final int registeredCallbackCount = mStatsProviderCbList.size();
+ mStatsProviderSem.drainPermits();
+ invokeForAllStatsProviderCallbacks(
+ (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */));
+ try {
+ mStatsProviderSem.tryAcquire(registeredCallbackCount,
+ MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // Strictly speaking it's possible a provider happened to deliver between the timeout
+ // and the log, and that doesn't matter too much as this is just a debug log.
+ Log.d(TAG, "requestStatsUpdate - providers responded "
+ + mStatsProviderSem.availablePermits()
+ + "/" + registeredCallbackCount + " : " + e);
+ }
+ Trace.traceEnd(TRACE_TAG_NETWORK);
+ }
+
/**
* Sample recent statistics summary into {@link EventLog}.
*/
@@ -1931,9 +1915,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
/**
- * Return snapshot of current tethering statistics. Will return empty
- * {@link NetworkStats} if any problems are encountered.
+ * Return snapshot of current non-offloaded tethering statistics. Will return empty
+ * {@link NetworkStats} if any problems are encountered, or queried by {@code STATS_PER_IFACE}
+ * since it is already included by {@link #nativeGetIfaceStat}.
+ * See {@code OffloadTetheringStatsProvider} for offloaded tethering stats.
*/
+ // TODO: Remove this by implementing {@link NetworkStatsProvider} for non-offloaded
+ // tethering stats.
private NetworkStats getNetworkStatsTethering(int how) throws RemoteException {
try {
return mNetworkManager.getNetworkStatsTethering(how);
@@ -2226,13 +2214,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
- private static int TYPE_RX_BYTES;
- private static int TYPE_RX_PACKETS;
- private static int TYPE_TX_BYTES;
- private static int TYPE_TX_PACKETS;
- private static int TYPE_TCP_RX_PACKETS;
- private static int TYPE_TCP_TX_PACKETS;
-
private static native long nativeGetTotalStat(int type, boolean useBpfStats);
private static native long nativeGetIfaceStat(String iface, int type, boolean useBpfStats);
private static native long nativeGetUidStat(int uid, int type, boolean useBpfStats);
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java
index 3b24f46d4714..487482bcf6c6 100644
--- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java
@@ -23,7 +23,6 @@ import android.os.RemoteException;
import android.os.ShellCommand;
import android.provider.Settings;
-import java.io.FileInputStream;
import java.io.InputStream;
import java.io.PrintWriter;
@@ -75,8 +74,9 @@ class NetworkWatchlistShellCommand extends ShellCommand {
pw.println("Error: can't open input file " + configXmlPath);
return -1;
}
- final InputStream fileStream = new FileInputStream(pfd.getFileDescriptor());
- WatchlistConfig.getInstance().setTestMode(fileStream);
+ try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+ WatchlistConfig.getInstance().setTestMode(inputStream);
+ }
pw.println("Success!");
} catch (Exception ex) {
pw.println("Error: " + ex.toString());
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index ea7779a4dc8f..f2e3708051c4 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -67,6 +67,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
import com.android.server.notification.NotificationManagerService.DumpFilter;
+import com.android.server.utils.TimingsTraceAndSlog;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -1289,6 +1290,8 @@ abstract public class ManagedServices {
*/
@VisibleForTesting
void unbindOtherUserServices(int currentUser) {
+ TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+ t.traceBegin("ManagedServices.unbindOtherUserServices_current" + currentUser);
final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
synchronized (mMutex) {
@@ -1303,6 +1306,7 @@ abstract public class ManagedServices {
}
}
unbindFromServices(componentsToUnbind);
+ t.traceEnd();
}
protected void unbindFromServices(SparseArray<Set<ComponentName>> componentsToUnbind) {
diff --git a/services/core/java/com/android/server/notification/NotificationChannelLogger.java b/services/core/java/com/android/server/notification/NotificationChannelLogger.java
index 51faac76c447..36eec26511c3 100644
--- a/services/core/java/com/android/server/notification/NotificationChannelLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationChannelLogger.java
@@ -215,6 +215,13 @@ public interface NotificationChannelLogger {
}
/**
+ * @return Small hash of the conversation ID, if present, or 0 otherwise.
+ */
+ static int getConversationIdHash(@NonNull NotificationChannel channel) {
+ return SmallHash.hash(channel.getConversationId());
+ }
+
+ /**
* @return Small hash of the channel ID, if present, or 0 otherwise.
*/
static int getIdHash(@NonNull NotificationChannelGroup group) {
diff --git a/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java
index fd3dd568f634..5a7bc48091bb 100644
--- a/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationChannelLoggerImpl.java
@@ -41,7 +41,12 @@ public class NotificationChannelLoggerImpl implements NotificationChannelLogger
/* String package_name */ pkg,
/* int32 channel_id_hash */ NotificationChannelLogger.getIdHash(channel),
/* int old_importance*/ oldImportance,
- /* int importance*/ newImportance);
+ /* int importance*/ newImportance,
+ /* bool is_conversation */ channel.isConversation(),
+ /* int32 conversation_id_hash */
+ NotificationChannelLogger.getConversationIdHash(channel),
+ /* bool is_conversation_demoted */ channel.isDemoted(),
+ /* bool is_conversation_priority */ channel.isImportantConversation());
}
@Override
@@ -53,7 +58,11 @@ public class NotificationChannelLoggerImpl implements NotificationChannelLogger
/* String package_name */ pkg,
/* int32 channel_id_hash */ NotificationChannelLogger.getIdHash(channelGroup),
/* int old_importance*/ NotificationChannelLogger.getImportance(wasBlocked),
- /* int importance*/ NotificationChannelLogger.getImportance(channelGroup));
+ /* int importance*/ NotificationChannelLogger.getImportance(channelGroup),
+ /* bool is_conversation */ false,
+ /* int32 conversation_id_hash */ 0,
+ /* bool is_conversation_demoted */ false,
+ /* bool is_conversation_priority */ false);
}
@Override
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1516cded50a6..1e2898b91a27 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -494,6 +494,10 @@ public class NotificationManagerService extends SystemService {
final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
+ // True if the toast that's on top of the queue is being shown at the moment.
+ @GuardedBy("mToastQueue")
+ private boolean mIsCurrentToastShown = false;
+
// The last key in this list owns the hardware.
ArrayList<String> mLights = new ArrayList<>();
@@ -7297,10 +7301,15 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mToastQueue")
void showNextToastLocked() {
+ if (mIsCurrentToastShown) {
+ return; // Don't show the same toast twice.
+ }
+
ToastRecord record = mToastQueue.get(0);
while (record != null) {
if (record.show()) {
scheduleDurationReachedLocked(record);
+ mIsCurrentToastShown = true;
return;
}
int index = mToastQueue.indexOf(record);
@@ -7316,6 +7325,10 @@ public class NotificationManagerService extends SystemService {
ToastRecord record = mToastQueue.get(index);
record.hide();
+ if (index == 0) {
+ mIsCurrentToastShown = false;
+ }
+
ToastRecord lastToast = mToastQueue.remove(index);
mWindowManagerInternal.removeWindowToken(lastToast.windowToken, false /* removeWindows */,
diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java
index 72803ac35a3f..780c522d2ae7 100644
--- a/services/core/java/com/android/server/pm/IncrementalStates.java
+++ b/services/core/java/com/android/server/pm/IncrementalStates.java
@@ -101,21 +101,18 @@ public final class IncrementalStates {
if (DEBUG) {
Slog.i(TAG, "received package commit event");
}
+ final boolean startableStateChanged;
synchronized (mLock) {
- if (!mStartableState.isStartable()) {
- mStartableState.adoptNewStartableStateLocked(true);
- }
+ startableStateChanged = mStartableState.adoptNewStartableStateLocked(true);
if (!isIncremental) {
updateProgressLocked(1);
}
}
- mHandler.post(PooledLambda.obtainRunnable(
- IncrementalStates::reportStartableState,
- IncrementalStates.this).recycleOnUse());
+ if (startableStateChanged) {
+ onStartableStateChanged();
+ }
if (!isIncremental) {
- mHandler.post(PooledLambda.obtainRunnable(
- IncrementalStates::reportFullyLoaded,
- IncrementalStates.this).recycleOnUse());
+ onLoadingStateChanged();
}
}
@@ -131,8 +128,7 @@ public final class IncrementalStates {
synchronized (mLock) {
if (mStartableState.isStartable() && mLoadingState.isLoading()) {
// Changing from startable -> unstartable only if app is still loading.
- mStartableState.adoptNewStartableStateLocked(false);
- startableStateChanged = true;
+ startableStateChanged = mStartableState.adoptNewStartableStateLocked(false);
} else {
// If the app is fully loaded, the crash or ANR is caused by the app itself, so
// we do not change the startable state.
@@ -140,12 +136,15 @@ public final class IncrementalStates {
}
}
if (startableStateChanged) {
- mHandler.post(PooledLambda.obtainRunnable(
- IncrementalStates::reportStartableState,
- IncrementalStates.this).recycleOnUse());
+ onStartableStateChanged();
}
}
+ private void onStartableStateChanged() {
+ // Disable startable state broadcasts
+ // TODO(b/171920377): completely remove unstartable state.
+ }
+
private void reportStartableState() {
final Callback callback;
final boolean startable;
@@ -165,6 +164,12 @@ public final class IncrementalStates {
}
}
+ private void onLoadingStateChanged() {
+ mHandler.post(PooledLambda.obtainRunnable(
+ IncrementalStates::reportFullyLoaded,
+ IncrementalStates.this).recycleOnUse());
+ }
+
private void reportFullyLoaded() {
final Callback callback;
synchronized (mLock) {
@@ -178,23 +183,20 @@ public final class IncrementalStates {
private class StatusConsumer implements Consumer<Integer> {
@Override
public void accept(Integer storageStatus) {
- final boolean oldState, newState;
+ final boolean startableStateChanged;
synchronized (mLock) {
if (!mLoadingState.isLoading()) {
// Do nothing if the package is already fully loaded
return;
}
- oldState = mStartableState.isStartable();
mStorageHealthStatus = storageStatus;
- updateStartableStateLocked();
- newState = mStartableState.isStartable();
+ startableStateChanged = updateStartableStateLocked();
}
- if (oldState != newState) {
- mHandler.post(PooledLambda.obtainRunnable(IncrementalStates::reportStartableState,
- IncrementalStates.this).recycleOnUse());
+ if (startableStateChanged) {
+ onStartableStateChanged();
}
}
- };
+ }
/**
* By calling this method, the caller indicates that there issues with the Incremental
@@ -239,14 +241,10 @@ public final class IncrementalStates {
newStartableState = mStartableState.isStartable();
}
if (!newLoadingState) {
- mHandler.post(PooledLambda.obtainRunnable(
- IncrementalStates::reportFullyLoaded,
- IncrementalStates.this).recycleOnUse());
+ onLoadingStateChanged();
}
if (newStartableState != oldStartableState) {
- mHandler.post(PooledLambda.obtainRunnable(
- IncrementalStates::reportStartableState,
- IncrementalStates.this).recycleOnUse());
+ onStartableStateChanged();
}
}
@@ -284,8 +282,9 @@ public final class IncrementalStates {
* health
* status. If the next state is different from the current state, proceed with state
* change.
+ * @return True if the new startable state is different from the old one.
*/
- private void updateStartableStateLocked() {
+ private boolean updateStartableStateLocked() {
final boolean currentState = mStartableState.isStartable();
boolean nextState = currentState;
if (!currentState) {
@@ -302,9 +301,9 @@ public final class IncrementalStates {
}
}
if (nextState == currentState) {
- return;
+ return false;
}
- mStartableState.adoptNewStartableStateLocked(nextState);
+ return mStartableState.adoptNewStartableStateLocked(nextState);
}
private void updateProgressLocked(float progress) {
@@ -343,12 +342,30 @@ public final class IncrementalStates {
return mUnstartableReason;
}
- public void adoptNewStartableStateLocked(boolean nextState) {
+ /**
+ * Adopt new startable state if it is different from the current state.
+ * @param nextState True if startable, false if unstartable.
+ * @return True if the state has changed, false otherwise.
+ */
+ public boolean adoptNewStartableStateLocked(boolean nextState) {
+ if (mIsStartable == nextState) {
+ return false;
+ }
+ if (!nextState) {
+ // Do nothing if the next state is "unstartable"; keep package always startable.
+ // TODO(b/171920377): completely remove unstartable state.
+ if (DEBUG) {
+ Slog.i(TAG, "Attempting to set startable state to false. Abort.");
+ }
+ return false;
+ }
if (DEBUG) {
- Slog.i(TAG, "startable state changed from " + mIsStartable + " to " + nextState);
+ Slog.i(TAG,
+ "startable state changed from " + mIsStartable + " to " + nextState);
}
mIsStartable = nextState;
mUnstartableReason = getUnstartableReasonLocked();
+ return true;
}
private int getUnstartableReasonLocked() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 925d3cc587d3..05006168d66a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -545,7 +545,6 @@ public class PackageManagerService extends IPackageManager.Stub
static final int SCAN_AS_SYSTEM_EXT = 1 << 21;
static final int SCAN_AS_ODM = 1 << 22;
static final int SCAN_AS_APK_IN_APEX = 1 << 23;
- static final int SCAN_EXPECTED_BETTER = 1 << 24;
@IntDef(flag = true, prefix = { "SCAN_" }, value = {
SCAN_NO_DEX,
@@ -805,12 +804,11 @@ public class PackageManagerService extends IPackageManager.Stub
final SparseIntArray mIsolatedOwners = new SparseIntArray();
/**
- * Tracks packages that we expect to find updated versions of on disk.
- * Keys are package name, values are package location and package version code.
- *
- * @see #expectBetter(String, File, long)
+ * Tracks new system packages [received in an OTA] that we expect to
+ * find updated user-installed versions. Keys are package name, values
+ * are package location.
*/
- private final ArrayMap<String, List<Pair<File, Long>>> mExpectingBetter = new ArrayMap<>();
+ final private ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
/**
* Tracks existing packages prior to receiving an OTA. Keys are package name.
@@ -3351,7 +3349,7 @@ public class PackageManagerService extends IPackageManager.Stub
+ ", versionCode=" + ps.versionCode
+ "; scanned versionCode=" + scannedPkg.getLongVersionCode());
removePackageLI(scannedPkg, true);
- expectBetter(ps.name, ps.getPath(), ps.versionCode);
+ mExpectingBetter.put(ps.name, ps.getPath());
}
continue;
@@ -3381,8 +3379,7 @@ public class PackageManagerService extends IPackageManager.Stub
// We're expecting that the system app should remain disabled, but add
// it to expecting better to recover in case the data version cannot
// be scanned.
- expectBetter(disabledPs.name, disabledPs.getPath(),
- disabledPs.versionCode);
+ mExpectingBetter.put(disabledPs.name, disabledPs.getPath());
}
}
}
@@ -3483,49 +3480,39 @@ public class PackageManagerService extends IPackageManager.Stub
for (int i = 0; i < mExpectingBetter.size(); i++) {
final String packageName = mExpectingBetter.keyAt(i);
if (!mPackages.containsKey(packageName)) {
+ final File scanFile = mExpectingBetter.valueAt(i);
+
logCriticalInfo(Log.WARN, "Expected better " + packageName
+ " but never showed up; reverting to system");
- final List<Pair<File, Long>> scanFiles = mExpectingBetter.valueAt(i);
- // Sort ascending and iterate backwards to take highest version code
- Collections.sort(scanFiles,
- (first, second) -> Long.compare(first.second, second.second));
- for (int index = scanFiles.size() - 1; index >= 0; index--) {
- File scanFile = scanFiles.get(index).first;
-
- @ParseFlags int reparseFlags = 0;
- @ScanFlags int rescanFlags = 0;
- for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
- final ScanPartition partition = mDirsToScanAsSystem.get(i1);
- if (partition.containsPrivApp(scanFile)) {
- reparseFlags = systemParseFlags;
- rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
- | partition.scanFlag;
- break;
- }
- if (partition.containsApp(scanFile)) {
- reparseFlags = systemParseFlags;
- rescanFlags = systemScanFlags | partition.scanFlag;
- break;
- }
- }
- if (rescanFlags == 0) {
- Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
- continue;
+ @ParseFlags int reparseFlags = 0;
+ @ScanFlags int rescanFlags = 0;
+ for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
+ final ScanPartition partition = mDirsToScanAsSystem.get(i1);
+ if (partition.containsPrivApp(scanFile)) {
+ reparseFlags = systemParseFlags;
+ rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
+ | partition.scanFlag;
+ break;
}
- mSettings.enableSystemPackageLPw(packageName);
-
- rescanFlags |= SCAN_EXPECTED_BETTER;
-
- try {
- scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
- // Take first success and break out of for loop
+ if (partition.containsApp(scanFile)) {
+ reparseFlags = systemParseFlags;
+ rescanFlags = systemScanFlags | partition.scanFlag;
break;
- } catch (PackageManagerException e) {
- Slog.e(TAG, "Failed to parse original system package: "
- + e.getMessage());
}
}
+ if (rescanFlags == 0) {
+ Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
+ continue;
+ }
+ mSettings.enableSystemPackageLPw(packageName);
+
+ try {
+ scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "Failed to parse original system package: "
+ + e.getMessage());
+ }
}
}
@@ -3914,33 +3901,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
/**
- * Mark a package as skipped during initial scan, expecting a more up to date version to be
- * available on the scan of a higher priority partition. This can be either a system partition
- * or the data partition.
- *
- * If for some reason that newer version cannot be scanned successfully, the data structure
- * created here will be used to backtrack in the scanning process to try and take the highest
- * version code of the package left on disk that scans successfully.
- *
- * This can occur if an OTA adds a new system package which the user has already installed an
- * update on data for. Or if the device image includes multiple versions of the same package,
- * for cases where the maintainer of a higher priority partition wants to update an app on
- * a lower priority partition before shipping a device to users.
- *
- * @param pkgName the package name identifier to queue under
- * @param codePath the path to re-scan if needed
- * @param knownVersionCode the version of the package so that the set of files can be sorted
- */
- private void expectBetter(String pkgName, File codePath, long knownVersionCode) {
- List<Pair<File, Long>> pairs = mExpectingBetter.get(pkgName);
- if (pairs == null) {
- pairs = new ArrayList<>(0);
- mExpectingBetter.put(pkgName, pairs);
- }
- pairs.add(Pair.create(codePath, knownVersionCode));
- }
-
- /**
* Extract, install and enable a stub package.
* <p>If the compressed file can not be extracted / installed for any reason, the stub
* APK will be installed and the package will be disabled. To recover from this situation,
@@ -10858,7 +10818,7 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
final PackageSetting staticLibPkgSetting = getPackageSetting(
- toStaticSharedLibraryPackageName(sharedLibraryInfo.getPackageName(),
+ toStaticSharedLibraryPackageName(sharedLibraryInfo.getName(),
sharedLibraryInfo.getLongVersion()));
if (staticLibPkgSetting == null) {
Slog.wtf(TAG, "Shared lib without setting: " + sharedLibraryInfo);
@@ -11311,23 +11271,7 @@ public class PackageManagerService extends IPackageManager.Stub
isUpdatedSystemApp = disabledPkgSetting != null;
}
applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, isUpdatedSystemApp);
- try {
- assertPackageIsValid(parsedPackage, pkgSetting, parseFlags, scanFlags);
- } catch (PackageManagerException e) {
- if (e.error == INSTALL_FAILED_VERSION_DOWNGRADE
- && ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0)
- && ((scanFlags & SCAN_BOOTING) != 0)) {
- if (pkgSetting != null && pkgSetting.getPkg() == null) {
- // If a package for the pkgSetting hasn't already been found, this is
- // skipping a downgrade on a lower priority partition, and so a later scan
- // is expected to fill the package.
- expectBetter(pkgSetting.name, new File(parsedPackage.getPath()),
- parsedPackage.getLongVersionCode());
- }
- }
-
- throw e;
- }
+ assertPackageIsValid(parsedPackage, parseFlags, scanFlags);
SharedUserSetting sharedUserSetting = null;
if (parsedPackage.getSharedUserId() != null) {
@@ -12179,9 +12123,9 @@ public class PackageManagerService extends IPackageManager.Stub
*
* @throws PackageManagerException If the package fails any of the validation checks
*/
- private void assertPackageIsValid(AndroidPackage pkg,
- @Nullable PackageSetting existingPkgSetting, final @ParseFlags int parseFlags,
- final @ScanFlags int scanFlags) throws PackageManagerException {
+ private void assertPackageIsValid(AndroidPackage pkg, final @ParseFlags int parseFlags,
+ final @ScanFlags int scanFlags)
+ throws PackageManagerException {
if ((parseFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) {
assertCodePolicy(pkg);
}
@@ -12196,11 +12140,11 @@ public class PackageManagerService extends IPackageManager.Stub
// after OTA.
final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0;
final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
- String pkgName = pkg.getPackageName();
if ((isUserInstall || isFirstBootOrUpgrade)
- && mApexManager.isApexPackage(pkgName)) {
+ && mApexManager.isApexPackage(pkg.getPackageName())) {
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
- pkgName + " is an APEX package and can't be installed as an APK.");
+ pkg.getPackageName()
+ + " is an APEX package and can't be installed as an APK.");
}
// Make sure we're not adding any bogus keyset info
@@ -12209,7 +12153,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
// The special "android" package can only be defined once
- if (pkgName.equals("android")) {
+ if (pkg.getPackageName().equals("android")) {
if (mAndroidApplication != null) {
Slog.w(TAG, "*************************************************");
Slog.w(TAG, "Core android package being redefined. Skipping.");
@@ -12220,46 +12164,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- final long newLongVersionCode = pkg.getLongVersionCode();
- if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
- boolean runDuplicateCheck = false;
-
- // It's possible to re-scan a package if an updated system app was expected, but
- // no update on /data could be found. To avoid infinitely looping, a flag is passed
- // in when re-scanning and this first branch is skipped if the flag is set.
- if ((scanFlags & SCAN_EXPECTED_BETTER) == 0 && existingPkgSetting != null) {
- long existingLongVersionCode = existingPkgSetting.versionCode;
- if (newLongVersionCode <= existingLongVersionCode) {
- // Must check that real name is equivalent, as it's possible to downgrade
- // version code if the package is actually a different package taking over
- // a package name through <original-package/>. It is assumed that this
- // migration is one time, one way, and that there is no failsafe if this
- // doesn't hold true.
- if (Objects.equals(existingPkgSetting.realName, pkg.getRealPackage())) {
- if (newLongVersionCode != existingLongVersionCode) {
- throw new PackageManagerException(
- INSTALL_FAILED_VERSION_DOWNGRADE,
- "Ignoring lower version " + newLongVersionCode
- + " for package " + pkgName
- + " with expected version "
- + existingLongVersionCode);
- }
- }
- } else if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0
- && (scanFlags & SCAN_BOOTING) != 0) {
- // During system boot scan, if there's already a package known, but this
- // package is higher version, use it instead, ignoring the duplicate check.
- // This will store the higher version in the setting object, and the above
- // branch/exception will cause future scans to skip the lower versions.
- runDuplicateCheck = false;
- }
- }
-
- if (runDuplicateCheck && mPackages.containsKey(pkgName)) {
- throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
- "Application package " + pkgName
- + " already installed. Skipping duplicate.");
- }
+ // A package name must be unique; don't allow duplicates
+ if ((scanFlags & SCAN_NEW_INSTALL) == 0
+ && mPackages.containsKey(pkg.getPackageName())) {
+ throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
+ "Application package " + pkg.getPackageName()
+ + " already installed. Skipping duplicate.");
}
if (pkg.isStaticSharedLibrary()) {
@@ -12379,8 +12289,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
}
- if (newLongVersionCode < minVersionCode
- || newLongVersionCode > maxVersionCode) {
+ if (pkg.getLongVersionCode() < minVersionCode
+ || pkg.getLongVersionCode() > maxVersionCode) {
throw new PackageManagerException("Static shared"
+ " lib version codes must be ordered as lib versions");
}
@@ -12395,10 +12305,11 @@ public class PackageManagerService extends IPackageManager.Stub
// to the user-installed location. If we don't allow this change, any newer,
// user-installed version of the application will be ignored.
if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
- if (mExpectingBetter.containsKey(pkgName)) {
- Slog.w(TAG, "Relax SCAN_REQUIRE_KNOWN requirement for package " + pkgName);
+ if (mExpectingBetter.containsKey(pkg.getPackageName())) {
+ Slog.w(TAG, "Relax SCAN_REQUIRE_KNOWN requirement for package "
+ + pkg.getPackageName());
} else {
- PackageSetting known = mSettings.getPackageLPr(pkgName);
+ PackageSetting known = mSettings.getPackageLPr(pkg.getPackageName());
if (known != null) {
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Examining " + pkg.getPath()
@@ -12406,14 +12317,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (!pkg.getPath().equals(known.getPathString())) {
throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
- "Application package " + pkgName
+ "Application package " + pkg.getPackageName()
+ " found at " + pkg.getPath()
+ " but expected at " + known.getPathString()
+ "; ignoring.");
}
} else {
throw new PackageManagerException(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
- "Application package " + pkgName
+ "Application package " + pkg.getPackageName()
+ " not found; ignoring.");
}
}
@@ -12436,7 +12347,7 @@ public class PackageManagerService extends IPackageManager.Stub
INSTALL_FAILED_PROCESS_NOT_DEFINED,
"Can't install because application tag's process attribute "
+ pkg.getProcessName()
- + " (in package " + pkgName
+ + " (in package " + pkg.getPackageName()
+ ") is not included in the <processes> list");
}
assertPackageProcesses(pkg, pkg.getActivities(), procs, "activity");
@@ -12460,7 +12371,7 @@ public class PackageManagerService extends IPackageManager.Stub
pkg.getSigningDetails().signatures)) {
throw new PackageManagerException("Apps that share a user with a " +
"privileged app must themselves be marked as privileged. " +
- pkgName + " shares privileged user " +
+ pkg.getPackageName() + " shares privileged user " +
pkg.getSharedUserId() + ".");
}
}
@@ -12477,21 +12388,21 @@ public class PackageManagerService extends IPackageManager.Stub
// upgraded.
Objects.requireNonNull(mOverlayConfig,
"Parsing non-system dir before overlay configs are initialized");
- if (!mOverlayConfig.isMutable(pkgName)) {
+ if (!mOverlayConfig.isMutable(pkg.getPackageName())) {
throw new PackageManagerException("Overlay "
- + pkgName
+ + pkg.getPackageName()
+ " is static and cannot be upgraded.");
}
} else {
if ((scanFlags & SCAN_AS_VENDOR) != 0) {
if (pkg.getTargetSdkVersion() < getVendorPartitionVersion()) {
- Slog.w(TAG, "System overlay " + pkgName
+ Slog.w(TAG, "System overlay " + pkg.getPackageName()
+ " targets an SDK below the required SDK level of vendor"
+ " overlays (" + getVendorPartitionVersion() + ")."
+ " This will become an install error in a future release");
}
} else if (pkg.getTargetSdkVersion() < Build.VERSION.SDK_INT) {
- Slog.w(TAG, "System overlay " + pkgName
+ Slog.w(TAG, "System overlay " + pkg.getPackageName()
+ " targets an SDK below the required SDK level of system"
+ " overlays (" + Build.VERSION.SDK_INT + ")."
+ " This will become an install error in a future release");
@@ -12507,7 +12418,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!comparePackageSignatures(platformPkgSetting,
pkg.getSigningDetails().signatures)) {
throw new PackageManagerException("Overlay "
- + pkgName
+ + pkg.getPackageName()
+ " must target Q or later, "
+ "or be signed with the platform certificate");
}
@@ -12529,7 +12440,7 @@ public class PackageManagerService extends IPackageManager.Stub
// check reference signature
if (mOverlayConfigSignaturePackage == null) {
throw new PackageManagerException("Overlay "
- + pkgName + " and target "
+ + pkg.getPackageName() + " and target "
+ pkg.getOverlayTarget() + " signed with"
+ " different certificates, and the overlay lacks"
+ " <overlay android:targetName>");
@@ -12539,7 +12450,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (!comparePackageSignatures(refPkgSetting,
pkg.getSigningDetails().signatures)) {
throw new PackageManagerException("Overlay "
- + pkgName + " signed with a different "
+ + pkg.getPackageName() + " signed with a different "
+ "certificate than both the reference package and "
+ "target " + pkg.getOverlayTarget() + ", and the "
+ "overlay lacks <overlay android:targetName>");
@@ -12559,7 +12470,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (pkg.getSigningDetails().signatureSchemeVersion < minSignatureSchemeVersion) {
throw new PackageManagerException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
- + " or newer for package " + pkgName);
+ + " or newer for package " + pkg.getPackageName());
}
}
}
@@ -16567,8 +16478,8 @@ public class PackageManagerService extends IPackageManager.Stub
healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS;
healthCheckParams.unhealthyMonitoringMs =
INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS;
- mIncrementalManager.registerHealthListener(codePath,
- new StorageHealthCheckParams(), incrementalHealthListener);
+ mIncrementalManager.registerHealthListener(codePath, healthCheckParams,
+ incrementalHealthListener);
}
// Ensure that the uninstall reason is UNKNOWN for users with the package installed.
@@ -19695,7 +19606,7 @@ public class PackageManagerService extends IPackageManager.Stub
ps.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
}
- writeRuntimePermissionsForUserLPrTEMP(userId, false);
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
// Regardless of writeSettings we need to ensure that this restriction
// state propagation is persisted
@@ -25841,7 +25752,7 @@ public class PackageManagerService extends IPackageManager.Stub
public void writePermissionSettings(int[] userIds, boolean async) {
synchronized (mLock) {
for (int userId : userIds) {
- writeRuntimePermissionsForUserLPrTEMP(userId, !async);
+ mSettings.writeRuntimePermissionsForUserLPr(userId, !async);
}
}
}
@@ -26490,17 +26401,6 @@ public class PackageManagerService extends IPackageManager.Stub
mSettings.writeLPr();
}
- /**
- * Temporary method that wraps mSettings.writeRuntimePermissionsForUserLPr() and calls
- * mPermissionManager.writeLegacyPermissionStateTEMP() beforehand.
- *
- * TODO(zhanghai): This should be removed once we finish migration of permission storage.
- */
- private void writeRuntimePermissionsForUserLPrTEMP(@UserIdInt int userId, boolean async) {
- mPermissionManager.writeLegacyPermissionStateTEMP();
- mSettings.writeRuntimePermissionsForUserLPr(userId, async);
- }
-
@Override
public IBinder getHoldLockToken() {
if (!Build.IS_DEBUGGABLE) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index cd9a4e72672f..71e7358701fd 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -5390,6 +5390,8 @@ public final class Settings {
mHandler.removeMessages(userId);
mWriteScheduled.delete(userId);
+ mPermissionDataProvider.writeLegacyPermissionStateTEMP();
+
int version = mVersions.get(userId, INITIAL_VERSION);
String fingerprint = mFingerprints.get(userId);
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 3fcf02cd9bd8..d535f7b8e0f7 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -919,10 +919,10 @@ public class StagingManager {
} catch (PackageManagerException e) {
onInstallationFailure(session, e);
} catch (Exception e) {
- final String errorMsg = "Staged install failed due to unhandled exception";
- Slog.e(TAG, errorMsg, e);
+ Slog.e(TAG, "Staged install failed due to unhandled exception", e);
onInstallationFailure(session, new PackageManagerException(
- SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg));
+ SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
+ "Staged install failed due to unhandled exception: " + e));
}
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 7f29cd94bfca..24082b86132c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3993,7 +3993,7 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public @UserManager.RemoveResult int removeUserOrSetEphemeral(@UserIdInt int userId) {
Slog.i(LOG_TAG, "removeUserOrSetEphemeral u" + userId);
- checkManageUsersPermission("Only the system can remove users");
+ checkManageOrCreateUsersPermission("Only the system can remove users");
final String restriction = getUserRemovalRestriction(userId);
if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(restriction, false)) {
Slog.w(LOG_TAG, "Cannot remove user. " + restriction + " is enabled.");
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index f058ad991e02..252ba6061b7a 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -418,6 +418,8 @@ class UserSystemPackageInstaller {
@VisibleForTesting
static boolean hasAutoGeneratedRROSuffix(String name) {
return name.endsWith(".auto_generated_rro_product__")
+ // TODO(b/172956245): temporary workaround until OEMs can customize name
+ || name.endsWith("carui.rro") || name.endsWith("carui.overlayable.rro")
|| name.endsWith(".auto_generated_rro_vendor__");
}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
index 3463daf748a6..74ec16140c94 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageCacher.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
@@ -57,16 +57,7 @@ public class PackageCacher {
* Returns the cache key for a specified {@code packageFile} and {@code flags}.
*/
private String getCacheKey(File packageFile, int flags) {
- StringBuilder sb = new StringBuilder();
-
- // To support packages with the same file name across partitions, use the partition name
- // as a prefix. The cache should only be used for cases where the file paths have been
- // established using the unique partition names, without canonicalization, so any links
- // which would point to the same partition name should be handled separately.
- String cachePrefix = packageFile.toPath().getName(0).toString();
- sb.append(cachePrefix);
- sb.append('-');
- sb.append(packageFile.getName());
+ StringBuilder sb = new StringBuilder(packageFile.getName());
sb.append('-');
sb.append(flags);
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 2d2e72a3facb..9dde7dfd5978 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -275,8 +275,8 @@ public class PackageInfoUtils {
return null;
}
- ActivityInfo info =
- PackageInfoWithoutStateUtils.generateActivityInfoUnchecked(a, applicationInfo);
+ final ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfoUnchecked(
+ a, flags, applicationInfo);
assignSharedFieldsForComponentInfo(info, a, pkgSetting, userId);
return info;
}
@@ -310,8 +310,8 @@ public class PackageInfoUtils {
return null;
}
- ServiceInfo info =
- PackageInfoWithoutStateUtils.generateServiceInfoUnchecked(s, applicationInfo);
+ final ServiceInfo info = PackageInfoWithoutStateUtils.generateServiceInfoUnchecked(
+ s, flags, applicationInfo);
assignSharedFieldsForComponentInfo(info, s, pkgSetting, userId);
return info;
}
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index 46d31d9e907e..851ddd1eae48 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -135,7 +135,7 @@ public class PackageParser2 implements AutoCloseable {
}
/**
- * TODO(b/155493909): Document new package parsing
+ * TODO(b/135203078): Document new package parsing
*/
@AnyThread
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
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 1ae430a3281a..7a37bdda5fab 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -820,7 +820,7 @@ public final class DefaultPermissionGrantPolicy {
CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS);
}
- // Atthention Service
+ // Attention Service
String attentionServicePackageName =
mContext.getPackageManager().getAttentionServicePackageName();
if (!TextUtils.isEmpty(attentionServicePackageName)) {
@@ -1272,7 +1272,12 @@ public final class DefaultPermissionGrantPolicy {
newFlags |= (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT);
// If we are allowlisting the permission, update the exempt flag before grant.
- if (whitelistRestrictedPermissions && pm.isPermissionRestricted(permission)) {
+ // If the permission can't be allowlisted by an installer, skip it here because
+ // this is where the platform takes the role of the installer for exempting
+ // preinstalled apps.
+ if (whitelistRestrictedPermissions && pm.isPermissionRestricted(permission)
+ && !pm.getPermissionInfo(permission).isInstallerExemptIgnored()) {
+
pm.updatePermissionFlags(permission, pkg,
PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT,
PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, user);
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java
index 0e790b1899ed..46e4e59bb15b 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java
@@ -61,4 +61,14 @@ public interface LegacyPermissionDataProvider {
*/
@NonNull
int[] getGidsForUid(int uid);
+
+ /**
+ * This method should be in PermissionManagerServiceInternal, however it is made available here
+ * as well to avoid serious performance regression in writePermissionSettings(), which seems to
+ * be a hot spot and we should delay calling this method until wre are actually writing the
+ * file, instead of every time an async write is requested.
+ *
+ * @see PermissionManagerServiceInternal#writeLegacyPermissionStateTEMP()
+ */
+ void writeLegacyPermissionStateTEMP();
}
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java
index 0e60367c243b..72d76285fe40 100644
--- a/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionState.java
@@ -89,8 +89,19 @@ public final class LegacyPermissionState {
return false;
}
final LegacyPermissionState other = (LegacyPermissionState) object;
- return Objects.equals(mUserStates, other.mUserStates)
- && Objects.equals(mMissing, other.mMissing);
+ // Hand-code equals() for mUserStates, since SparseArray only has the
+ // default equals() method.
+ final int userStatesSize = mUserStates.size();
+ if (userStatesSize != other.mUserStates.size()) {
+ return false;
+ }
+ for (int i = 0; i < userStatesSize; i++) {
+ final int userId = mUserStates.keyAt(i);
+ if (!Objects.equals(mUserStates.get(userId), other.mUserStates.get(userId))) {
+ return false;
+ }
+ }
+ return Objects.equals(mMissing, other.mMissing);
}
/**
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index 4e8ddac88529..0245b28884ea 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -425,7 +425,7 @@ public final class Permission {
permission = new Permission(permissionInfo.name, permissionInfo.packageName,
TYPE_MANIFEST);
}
- boolean wasNormal = permission.isNormal();
+ boolean wasNonRuntime = !permission.isRuntime();
StringBuilder r = null;
if (!permission.mReconciled) {
if (permission.mPermissionInfo.packageName == null
@@ -465,8 +465,8 @@ public final class Permission {
r.append("DUP:");
r.append(permissionInfo.name);
}
- if (permission.isRuntime() && (ownerChanged || wasNormal)) {
- // If this is a runtime permission and the owner has changed, or this was a normal
+ if (permission.isRuntime() && (ownerChanged || wasNonRuntime)) {
+ // If this is a runtime permission and the owner has changed, or this wasn't a runtime
// permission, then permission state should be cleaned up
permission.mDefinitionChanged = true;
}
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 84f98239a39c..ff661a8860d0 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -70,11 +70,16 @@ import android.app.ApplicationPackageManager;
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
+import android.app.role.RoleManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.PermissionGroupInfoFlags;
import android.content.pm.PackageManager.PermissionInfoFlags;
@@ -84,6 +89,7 @@ import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
+import android.content.pm.UserInfo;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.permission.SplitPermissionInfoParcelable;
@@ -177,6 +183,7 @@ import java.util.function.Consumer;
*/
public class PermissionManagerService extends IPermissionManager.Stub {
private static final String TAG = "PackageManager";
+ private static final String LOG_TAG = PermissionManagerService.class.getSimpleName();
private static final long BACKUP_TIMEOUT_MILLIS = SECONDS.toMillis(60);
@@ -417,6 +424,105 @@ public class PermissionManagerService extends IPermissionManager.Stub {
new PermissionManagerServiceInternalImpl();
LocalServices.addService(PermissionManagerServiceInternal.class, localService);
LocalServices.addService(PermissionManagerInternal.class, localService);
+
+ context.getMainThreadHandler().post(() -> context.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+ return;
+ }
+
+ try {
+ fixBgMicCamera(context);
+ } catch (Throwable t) {
+ // Don't crash the system if this fails for any reason. Any intermediate state
+ // this can leave the permissions in is okay and in the worst case the state is
+ // the same as before the user rebooted.
+ Log.e(LOG_TAG, "Unable to fix background permissions", t);
+ }
+ }
+
+
+ private void fixBgMicCamera(Context context) {
+ PackageManager pm = context.getPackageManager();
+ for (UserInfo userInfo : context.getSystemService(UserManager.class).getUsers()) {
+ UserHandle user = userInfo.getUserHandle();
+ List<String> assistants = context.getSystemService(RoleManager.class)
+ .getRoleHoldersAsUser(RoleManager.ROLE_ASSISTANT, user);
+ List<PackageInfo> packages =
+ pm.getInstalledPackagesAsUser(PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.GET_PERMISSIONS, user.getIdentifier());
+ for (PackageInfo packageInfo : packages) {
+ String[] requestedPermissions = packageInfo.requestedPermissions;
+ if (requestedPermissions == null) {
+ continue;
+ }
+ for (String permName : requestedPermissions) {
+ String pkg = packageInfo.packageName;
+ switch (permName) {
+ case Manifest.permission.BACKGROUND_CAMERA:
+ removeFromAllowlistsAndRevoke(pm, pkg, permName, user);
+ break;
+ case Manifest.permission.RECORD_BACKGROUND_AUDIO:
+ if (assistants.contains(pkg)) {
+ removeFromAllowlistsAndRevokeForAssistant(pm, pkg, permName,
+ user);
+ } else {
+ removeFromAllowlistsAndRevoke(pm, pkg, permName, user);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private void removeFromAllowlistsAndRevoke(PackageManager pm, String pkg,
+ String permName, UserHandle user) {
+ if ((pm.getPermissionFlags(permName, pkg, user)
+ & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0) {
+ Slog.i(LOG_TAG, "removing " + pkg + " " + permName + " from all allowlists");
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_UPGRADE);
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_SYSTEM);
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_INSTALLER);
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_ALLOWLIST_ROLE);
+ }
+ if (pm.checkPermission(permName, pkg) == PackageManager.PERMISSION_GRANTED) {
+ Slog.i(LOG_TAG, "revoking " + pkg + " " + permName);
+ pm.revokeRuntimePermission(pkg, permName, user);
+ }
+ }
+
+ private void removeFromAllowlistsAndRevokeForAssistant(PackageManager pm, String pkg,
+ String permName, UserHandle user) {
+ int anyNonRoleExempt =
+ FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
+ | FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
+ | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
+
+ if ((pm.getPermissionFlags(permName, pkg, user) & anyNonRoleExempt) != 0) {
+ Slog.i(LOG_TAG, "removing " + pkg + " " + permName
+ + " from all allowlists except role");
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_UPGRADE);
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_SYSTEM);
+ pm.removeWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_WHITELIST_INSTALLER);
+ }
+ if ((pm.getPermissionFlags(permName, pkg, user)
+ & FLAG_PERMISSION_RESTRICTION_ROLE_EXEMPT) == 0) {
+ Slog.i(LOG_TAG, "adding " + pkg + " " + permName
+ + " to role allowlist");
+ pm.addWhitelistedRestrictedPermission(pkg, permName,
+ FLAG_PERMISSION_ALLOWLIST_ROLE);
+ }
+ }
+ }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)));
}
@Override
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8b677a99b22a..f7e6822612d8 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -20,7 +20,6 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.AppOpsManager.OP_TOAST_WINDOW;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.Context.CONTEXT_RESTRICTED;
import static android.content.Context.WINDOW_SERVICE;
import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
@@ -45,10 +44,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SYSTEM_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -178,7 +175,6 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicyConstants;
import android.view.accessibility.AccessibilityEvent;
@@ -603,8 +599,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private final MutableBoolean mTmpBoolean = new MutableBoolean(false);
- private boolean mAodShowing;
-
private boolean mPerDisplayFocusEnabled = false;
private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;
@@ -630,7 +624,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private static final int MSG_SYSTEM_KEY_PRESS = 21;
private static final int MSG_HANDLE_ALL_APPS = 22;
private static final int MSG_LAUNCH_ASSIST = 23;
- private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 24;
private static final int MSG_POWER_VERY_LONG_PRESS = 25;
private static final int MSG_RINGER_TOGGLE_CHORD = 26;
@@ -670,9 +663,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final String hint = (String) msg.obj;
launchAssistAction(hint, deviceId);
break;
- case MSG_LAUNCH_ASSIST_LONG_PRESS:
- launchAssistLongPressAction();
- break;
case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
launchVoiceAssistWithWakeLock();
break;
@@ -2271,44 +2261,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- private boolean shouldBeHiddenByKeyguard(WindowState win, WindowState imeTarget) {
- final LayoutParams attrs = win.getAttrs();
-
- boolean hideDockDivider = attrs.type == TYPE_DOCK_DIVIDER
- && !mWindowManagerInternal.isStackVisibleLw(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- if (hideDockDivider) {
- return true;
- }
-
- // If AOD is showing, the IME should be hidden. However, sometimes the AOD is considered
- // hidden because it's in the process of hiding, but it's still being shown on screen.
- // In that case, we want to continue hiding the IME until the windows have completed
- // drawing. This way, we know that the IME can be safely shown since the other windows are
- // now shown.
- final boolean hideIme = win.isInputMethodWindow()
- && (mAodShowing || !mDefaultDisplayPolicy.isWindowManagerDrawComplete());
- if (hideIme) {
- return true;
- }
-
- final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleLw()
- && (imeTarget.canShowWhenLocked() || !canBeHiddenByKeyguardLw(imeTarget));
-
- // Show IME over the keyguard if the target allows it
- boolean allowWhenLocked = win.isInputMethodWindow() && showImeOverKeyguard;
-
- final boolean isKeyguardShowing = mKeyguardDelegate.isShowing();
-
- if (isKeyguardShowing && isKeyguardOccluded()) {
- // Show SHOW_WHEN_LOCKED windows if Keyguard is occluded.
- allowWhenLocked |= win.canShowWhenLocked()
- // Show error dialogs over apps that are shown on lockscreen
- || (attrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
- }
-
- return isKeyguardShowing && !allowWhenLocked && win.getDisplayId() == DEFAULT_DISPLAY;
- }
-
/** {@inheritDoc} */
@Override
public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme,
@@ -2418,6 +2370,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
params.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ // Setting as trusted overlay to let touches pass through. This is safe because this
+ // window is controlled by the system.
+ params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
if (!compatInfo.supportsScreen()) {
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
@@ -2429,6 +2384,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
view = win.getDecorView();
+ // Ignore to show splash screen if the decorView is not opaque.
+ if (!view.isOpaque()) {
+ if (DEBUG_SPLASH_SCREEN) {
+ Slog.d(TAG, "addSplashScreen: the view of " + packageName
+ + " is not opaque, cancel it");
+ }
+ return null;
+ }
+
if (DEBUG_SPLASH_SCREEN) Slog.d(TAG, "Adding splash screen window for "
+ packageName + " / " + appToken + ": " + (view.getParent() != null ? view : null));
@@ -3249,28 +3213,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// There are several different flavors of "assistant" that can be launched from
// various parts of the UI.
- /** starts ACTION_SEARCH_LONG_PRESS, usually a voice search prompt */
- private void launchAssistLongPressAction() {
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
- "Assist - Long Press");
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
-
- // launch the search activity
- Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- // TODO: This only stops the factory-installed search manager.
- // Need to formalize an API to handle others
- SearchManager searchManager = getSearchManager();
- if (searchManager != null) {
- searchManager.stopSearch();
- }
- startActivityAsUser(intent, UserHandle.CURRENT);
- } catch (ActivityNotFoundException e) {
- Slog.w(TAG, "No activity to handle assist long press action.", e);
- }
- }
-
/** Asks the status bar to startAssist(), usually a full "assistant" interface */
private void launchAssistAction(String hint, int deviceId) {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
@@ -3456,18 +3398,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
- public void applyKeyguardPolicyLw(WindowState win, WindowState imeTarget) {
- if (canBeHiddenByKeyguardLw(win)) {
- if (shouldBeHiddenByKeyguard(win, imeTarget)) {
- win.hideLw(false /* doAnimation */);
- } else {
- win.showLw(false /* doAnimation */);
- }
- }
- }
-
- /** {@inheritDoc} */
- @Override
public void setKeyguardCandidateLw(WindowState win) {
mKeyguardCandidate = win;
setKeyguardOccludedLw(mKeyguardOccluded, true /* force */);
@@ -3958,12 +3888,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
case KeyEvent.KEYCODE_ASSIST: {
final boolean longPressed = event.getRepeatCount() > 0;
- if (down && longPressed) {
- Message msg = mHandler.obtainMessage(MSG_LAUNCH_ASSIST_LONG_PRESS);
- msg.setAsynchronous(true);
- msg.sendToTarget();
- }
- if (!down && !longPressed) {
+ if (down && !longPressed) {
Message msg = mHandler.obtainMessage(MSG_LAUNCH_ASSIST, event.getDeviceId(),
0 /* unused */, null /* hint */);
msg.setAsynchronous(true);
@@ -5215,7 +5140,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final Intent dock = createHomeDockIntent();
if (dock != null) {
int result = ActivityTaskManager.getService()
- .startActivityAsUser(null, mContext.getBasePackageName(),
+ .startActivityAsUser(null, mContext.getOpPackageName(),
mContext.getAttributionTag(), dock,
dock.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
@@ -5227,7 +5152,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
int result = ActivityTaskManager.getService()
- .startActivityAsUser(null, mContext.getBasePackageName(),
+ .startActivityAsUser(null, mContext.getOpPackageName(),
mContext.getAttributionTag(), mHomeIntent,
mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
@@ -5655,15 +5580,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- @Override
- public boolean setAodShowing(boolean aodShowing) {
- if (mAodShowing != aodShowing) {
- mAodShowing = aodShowing;
- return true;
- }
- return false;
- }
-
private class HdmiVideoExtconUEventObserver extends ExtconStateObserver<Boolean> {
private static final String HDMI_EXIST = "HDMI=1";
private static final String NAME = "hdmi";
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 0d8d3470ec65..6934e5c3bcc1 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -207,45 +207,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
public IApplicationToken getAppToken();
/**
- * Is this window visible? It is not visible if there is no
- * surface, or we are in the process of running an exit animation
- * that will remove the surface.
- */
- boolean isVisibleLw();
-
- /**
* Return true if this window (or a window it is attached to, but not
* considering its app token) is currently animating.
*/
boolean isAnimatingLw();
/**
- * Can be called by the policy to force a window to be hidden,
- * regardless of whether the client or window manager would like
- * it shown. Must be called with the window manager lock held.
- * Returns true if {@link #showLw} was last called for the window.
- */
- public boolean hideLw(boolean doAnimation);
-
- /**
- * Can be called to undo the effect of {@link #hideLw}, allowing a
- * window to be shown as long as the window manager and client would
- * also like it to be shown. Must be called with the window manager
- * lock held.
- * Returns true if {@link #hideLw} was last called for the window.
- */
- public boolean showLw(boolean doAnimation);
-
- /**
- * Check whether the window is currently dimming.
- */
- public boolean isDimming();
-
- public boolean isInputMethodWindow();
-
- public int getDisplayId();
-
- /**
* Returns true if the window owner can add internal system windows.
* That is, they have {@link Manifest.permission#INTERNAL_SYSTEM_WINDOW}.
*/
@@ -788,14 +755,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
void setTopFocusedDisplay(int displayId);
/**
- * Apply the keyguard policy to a specific window.
- *
- * @param win The window to apply the keyguard policy.
- * @param imeTarget The current IME target window.
- */
- void applyKeyguardPolicyLw(WindowState win, WindowState imeTarget);
-
- /**
* Called when the state of allow-lockscreen-when-on of the display is changed. See
* {@link WindowManager.LayoutParams#FLAG_ALLOW_LOCK_WHILE_SCREEN_ON}
*
@@ -1210,11 +1169,4 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* A new window on default display has been focused.
*/
default void onDefaultDisplayFocusChangedLw(WindowState newFocus) {}
-
- /**
- * Updates the flag about whether AOD is showing.
- *
- * @return whether the value was changed.
- */
- boolean setAodShowing(boolean aodShowing);
}
diff --git a/services/core/java/com/android/server/power/AmbientDisplaySuppressionController.java b/services/core/java/com/android/server/power/AmbientDisplaySuppressionController.java
index 3bb90ce38a73..aad7b1457b3c 100644
--- a/services/core/java/com/android/server/power/AmbientDisplaySuppressionController.java
+++ b/services/core/java/com/android/server/power/AmbientDisplaySuppressionController.java
@@ -29,7 +29,9 @@ import android.util.Slog;
import com.android.internal.statusbar.IStatusBarService;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.Set;
/**
@@ -73,6 +75,24 @@ public class AmbientDisplaySuppressionController {
}
/**
+ * Returns the tokens used to suppress ambient display through
+ * {@link #suppress(String, int, boolean)}.
+ *
+ * @param callingUid The uid of the calling application.
+ */
+ List<String> getSuppressionTokens(int callingUid) {
+ List<String> result = new ArrayList<>();
+ synchronized (mSuppressionTokens) {
+ for (Pair<String, Integer> token : mSuppressionTokens) {
+ if (token.second == callingUid) {
+ result.add(token.first);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
* Returns whether ambient display is suppressed for the given token.
*
* @param token A persistible identifier for the ambient display suppression.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 60da8e5c7b70..ccd659dcf5a4 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -5500,6 +5500,22 @@ public final class PowerManagerService extends SystemService
Binder.restoreCallingIdentity(ident);
}
}
+
+ /**
+ * Returns the tokens used to suppress ambient display by the calling app.
+ *
+ * <p>The calling app suppressed ambient display by calling
+ * {@link #suppressAmbientDisplay(String, boolean)}.
+ */
+ public List<String> getAmbientDisplaySuppressionTokens() {
+ final int uid = Binder.getCallingUid();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return mAmbientDisplaySuppressionController.getSuppressionTokens(uid);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/power/PowerManagerShellCommand.java b/services/core/java/com/android/server/power/PowerManagerShellCommand.java
index ec5dcfab7f40..a9b33ed58ef7 100644
--- a/services/core/java/com/android/server/power/PowerManagerShellCommand.java
+++ b/services/core/java/com/android/server/power/PowerManagerShellCommand.java
@@ -17,20 +17,20 @@
package com.android.server.power;
import android.content.Intent;
-import android.os.IPowerManager;
import android.os.PowerManagerInternal;
import android.os.RemoteException;
import android.os.ShellCommand;
import java.io.PrintWriter;
+import java.util.List;
class PowerManagerShellCommand extends ShellCommand {
private static final int LOW_POWER_MODE_ON = 1;
- final IPowerManager mInterface;
+ final PowerManagerService.BinderService mService;
- PowerManagerShellCommand(IPowerManager service) {
- mInterface = service;
+ PowerManagerShellCommand(PowerManagerService.BinderService service) {
+ mService = service;
}
@Override
@@ -48,6 +48,10 @@ class PowerManagerShellCommand extends ShellCommand {
return runSetMode();
case "set-fixed-performance-mode-enabled":
return runSetFixedPerformanceModeEnabled();
+ case "suppress-ambient-display":
+ return runSuppressAmbientDisplay();
+ case "list-ambient-display-suppression-tokens":
+ return runListAmbientDisplaySuppressionTokens();
default:
return handleDefaultCommands(cmd);
}
@@ -58,7 +62,7 @@ class PowerManagerShellCommand extends ShellCommand {
}
private int runSetAdaptiveEnabled() throws RemoteException {
- mInterface.setAdaptivePowerSaveEnabled(Boolean.parseBoolean(getNextArgRequired()));
+ mService.setAdaptivePowerSaveEnabled(Boolean.parseBoolean(getNextArgRequired()));
return 0;
}
@@ -71,12 +75,12 @@ class PowerManagerShellCommand extends ShellCommand {
pw.println("Error: " + ex.toString());
return -1;
}
- mInterface.setPowerSaveModeEnabled(mode == LOW_POWER_MODE_ON);
+ mService.setPowerSaveModeEnabled(mode == LOW_POWER_MODE_ON);
return 0;
}
private int runSetFixedPerformanceModeEnabled() throws RemoteException {
- boolean success = mInterface.setPowerModeChecked(
+ boolean success = mService.setPowerModeChecked(
PowerManagerInternal.MODE_FIXED_PERFORMANCE,
Boolean.parseBoolean(getNextArgRequired()));
if (!success) {
@@ -87,6 +91,32 @@ class PowerManagerShellCommand extends ShellCommand {
return success ? 0 : -1;
}
+ private int runSuppressAmbientDisplay() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+
+ try {
+ String token = getNextArgRequired();
+ boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+ mService.suppressAmbientDisplay(token, enabled);
+ } catch (RuntimeException ex) {
+ pw.println("Error: " + ex.toString());
+ return -1;
+ }
+
+ return 0;
+ }
+
+ private int runListAmbientDisplaySuppressionTokens() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ List<String> tokens = mService.getAmbientDisplaySuppressionTokens();
+ if (tokens.isEmpty()) {
+ pw.println("none");
+ } else {
+ pw.println(String.format("[%s]", String.join(", ", tokens)));
+ }
+
+ return 0;
+ }
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -103,6 +133,11 @@ class PowerManagerShellCommand extends ShellCommand {
pw.println(" enables or disables fixed performance mode");
pw.println(" note: this will affect system performance and should only be used");
pw.println(" during development");
+ pw.println(" suppress-ambient-display <token> [true|false]");
+ pw.println(" suppresses the current ambient display configuration and disables");
+ pw.println(" ambient display");
+ pw.println(" list-ambient-display-suppression-tokens");
+ pw.println(" prints the tokens used to suppress ambient display");
pw.println();
Intent.printIntentArgsHelp(pw , "");
}
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index ae0db4419080..db408488deba 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -514,6 +514,9 @@ public class ThermalManagerService extends SystemService {
pw.println("Current cooling devices from HAL:");
dumpItemsLocked(pw, "\t",
mHalWrapper.getCurrentCoolingDevices(false, 0));
+ pw.println("Temperature static thresholds from HAL:");
+ dumpItemsLocked(pw, "\t",
+ mHalWrapper.getTemperatureThresholds(false, 0));
}
}
} finally {
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index 701197e690fc..1883f4e4e86c 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -17,12 +17,8 @@ package com.android.server.power.batterysaver;
import android.annotation.IntDef;
import android.app.UiModeManager;
-import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Configuration;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.BatterySaverPolicyConfig;
@@ -190,12 +186,12 @@ public class BatterySaverPolicy extends ContentObserver {
/**
* Whether accessibility is currently enabled or not.
*/
- @GuardedBy("mLock")
- private boolean mAccessibilityEnabled;
+ @VisibleForTesting
+ final PolicyBoolean mAccessibilityEnabled = new PolicyBoolean("accessibility");
- /** Whether the phone is projecting in car mode or not. */
- @GuardedBy("mLock")
- private boolean mCarModeEnabled;
+ /** Whether the phone has set automotive projection or not. */
+ @VisibleForTesting
+ final PolicyBoolean mAutomotiveProjectionActive = new PolicyBoolean("automotiveProjection");
/** The current default adaptive policy. */
@GuardedBy("mLock")
@@ -235,19 +231,8 @@ public class BatterySaverPolicy extends ContentObserver {
private final ContentResolver mContentResolver;
private final BatterySavingStats mBatterySavingStats;
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- switch (intent.getAction()) {
- case UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED:
- setCarModeEnabled(true);
- break;
- case UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED:
- setCarModeEnabled(false);
- break;
- }
- }
- };
+ private final UiModeManager.OnProjectionStateChangeListener mOnProjectionStateChangeListener =
+ (t, pkgs) -> mAutomotiveProjectionActive.update(!pkgs.isEmpty());
@GuardedBy("mLock")
private final List<BatterySaverPolicyListener> mListeners = new ArrayList<>();
@@ -282,24 +267,14 @@ public class BatterySaverPolicy extends ContentObserver {
final AccessibilityManager acm = mContext.getSystemService(AccessibilityManager.class);
- acm.addAccessibilityStateChangeListener((enabled) -> setAccessibilityEnabled(enabled));
- final boolean accessibilityEnabled = acm.isEnabled();
- synchronized (mLock) {
- mAccessibilityEnabled = accessibilityEnabled;
- }
+ acm.addAccessibilityStateChangeListener(enabled -> mAccessibilityEnabled.update(enabled));
+ mAccessibilityEnabled.initialize(acm.isEnabled());
- final IntentFilter filter = new IntentFilter(
- UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
- filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
- // The ENTER/EXIT_CAR_MODE_PRIORITIZED intents are sent to UserHandle.ALL, so no need to
- // register as all users here.
- mContext.registerReceiver(mBroadcastReceiver, filter);
- final boolean carModeEnabled =
- mContext.getSystemService(UiModeManager.class).getCurrentModeType()
- == Configuration.UI_MODE_TYPE_CAR;
- synchronized (mLock) {
- mCarModeEnabled = carModeEnabled;
- }
+ UiModeManager uiModeManager = mContext.getSystemService(UiModeManager.class);
+ uiModeManager.addOnProjectionStateChangeListener(UiModeManager.PROJECTION_TYPE_AUTOMOTIVE,
+ mContext.getMainExecutor(), mOnProjectionStateChangeListener);
+ mAutomotiveProjectionActive.initialize(
+ uiModeManager.getActiveProjectionTypes() != UiModeManager.PROJECTION_TYPE_NONE);
onChange(true, null);
}
@@ -450,7 +425,7 @@ public class BatterySaverPolicy extends ContentObserver {
final int locationMode;
invalidatePowerSaveModeCaches();
- if (mCarModeEnabled
+ if (mAutomotiveProjectionActive.get()
&& rawPolicy.locationMode != PowerManager.LOCATION_MODE_NO_CHANGE
&& rawPolicy.locationMode != PowerManager.LOCATION_MODE_FOREGROUND_ONLY) {
// If car projection is enabled, ensure that navigation works.
@@ -470,12 +445,12 @@ public class BatterySaverPolicy extends ContentObserver {
rawPolicy.disableOptionalSensors,
rawPolicy.disableSoundTrigger,
// Don't disable vibration when accessibility is on.
- rawPolicy.disableVibration && !mAccessibilityEnabled,
+ rawPolicy.disableVibration && !mAccessibilityEnabled.get(),
rawPolicy.enableAdjustBrightness,
rawPolicy.enableDataSaver,
rawPolicy.enableFirewall,
// Don't force night mode when car projection is enabled.
- rawPolicy.enableNightMode && !mCarModeEnabled,
+ rawPolicy.enableNightMode && !mAutomotiveProjectionActive.get(),
rawPolicy.enableQuickDoze,
rawPolicy.filesForInteractive,
rawPolicy.filesForNoninteractive,
@@ -1073,8 +1048,8 @@ public class BatterySaverPolicy extends ContentObserver {
+ Settings.Global.BATTERY_SAVER_ADAPTIVE_DEVICE_SPECIFIC_CONSTANTS);
pw.println(" value: " + mAdaptiveDeviceSpecificSettings);
- pw.println(" mAccessibilityEnabled=" + mAccessibilityEnabled);
- pw.println(" mCarModeEnabled=" + mCarModeEnabled);
+ pw.println(" mAccessibilityEnabled=" + mAccessibilityEnabled.get());
+ pw.println(" mAutomotiveProjectionActive=" + mAutomotiveProjectionActive.get());
pw.println(" mPolicyLevel=" + mPolicyLevel);
dumpPolicyLocked(pw, " ", "full", mFullPolicy);
@@ -1147,24 +1122,42 @@ public class BatterySaverPolicy extends ContentObserver {
}
}
+ /**
+ * A boolean value which should trigger a policy update when it changes.
+ */
@VisibleForTesting
- void setAccessibilityEnabled(boolean enabled) {
- synchronized (mLock) {
- if (mAccessibilityEnabled != enabled) {
- mAccessibilityEnabled = enabled;
- updatePolicyDependenciesLocked();
- maybeNotifyListenersOfPolicyChange();
+ class PolicyBoolean {
+ private final String mDebugName;
+ @GuardedBy("mLock")
+ private boolean mValue;
+
+ private PolicyBoolean(String debugName) {
+ mDebugName = debugName;
+ }
+
+ /** Sets the initial value without triggering a policy update. */
+ private void initialize(boolean initialValue) {
+ synchronized (mLock) {
+ mValue = initialValue;
}
}
- }
- @VisibleForTesting
- void setCarModeEnabled(boolean enabled) {
- synchronized (mLock) {
- if (mCarModeEnabled != enabled) {
- mCarModeEnabled = enabled;
- updatePolicyDependenciesLocked();
- maybeNotifyListenersOfPolicyChange();
+ private boolean get() {
+ synchronized (mLock) {
+ return mValue;
+ }
+ }
+
+ /** Sets a value, which if different from the current value, triggers a policy update. */
+ @VisibleForTesting
+ void update(boolean newValue) {
+ synchronized (mLock) {
+ if (mValue != newValue) {
+ Slog.d(TAG, mDebugName + " changed to " + newValue + ", updating policy.");
+ mValue = newValue;
+ updatePolicyDependenciesLocked();
+ maybeNotifyListenersOfPolicyChange();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index ba1401d7469e..1295b7008e67 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -92,7 +92,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
@Override
public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
- @FailureReasons int failureReason) {
+ @FailureReasons int failureReason, int mitigationCount) {
// For native crashes, we will roll back any available rollbacks
if (failureReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH
&& !mContext.getSystemService(RollbackManager.class)
@@ -110,7 +110,7 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver {
@Override
public boolean execute(@Nullable VersionedPackage failedPackage,
- @FailureReasons int rollbackReason) {
+ @FailureReasons int rollbackReason, int mitigationCount) {
if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
mHandler.post(() -> rollbackAll());
return true;
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 51b00faa28d2..d5ab574b5617 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -149,11 +149,8 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware
private static void enforcePermissionForDataDelivery(@NonNull Context context,
@NonNull Identity identity,
@NonNull String permission, @NonNull String reason) {
- // TODO(ytai): We're temporarily ignoring proc state until we have a proper permission that
- // represents being able to use the microphone in the background. Otherwise, some of our
- // existing use-cases would break.
- final int status = PermissionUtil.checkPermissionForDataDeliveryIgnoreProcState(context,
- identity, permission, reason);
+ final int status = PermissionUtil.checkPermissionForDataDelivery(context, identity,
+ permission, reason);
if (status != PermissionChecker.PERMISSION_GRANTED) {
throw new SecurityException(
String.format("Failed to obtain permission %s for identity %s", permission,
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index fb47ebbcaa07..bd2d382c8010 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -24,15 +24,18 @@ import android.app.ActivityThread;
import android.app.ITransientNotificationCallback;
import android.app.Notification;
import android.app.StatusBarManager;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -84,6 +87,18 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
private static final String TAG = "StatusBarManagerService";
private static final boolean SPEW = false;
+ /**
+ * Apps targeting {@code Build.VERSION_CODES.S} or higher need {@link
+ * android.Manifest.permission#STATUS_BAR} permission to collapse the status bar panels due to
+ * security reasons.
+ *
+ * This was being exploited by malware to prevent the user from accessing critical
+ * notifications.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ private static final long LOCK_DOWN_COLLAPSE_STATUS_BAR = 173031413L;
+
private final Context mContext;
private Handler mHandler = new Handler();
@@ -605,7 +620,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void collapsePanels() {
- enforceExpandStatusBar();
+ if (CompatChanges.isChangeEnabled(LOCK_DOWN_COLLAPSE_STATUS_BAR, Binder.getCallingUid())) {
+ enforceStatusBar();
+ } else {
+ enforceExpandStatusBar();
+ }
if (mBar != null) {
try {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 149dbd00b0a8..afbe5527a5cb 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -134,12 +134,15 @@ public final class TvInputManagerService extends SystemService {
private final Object mLock = new Object();
// ID of the current user.
+ @GuardedBy("mLock")
private int mCurrentUserId = UserHandle.USER_SYSTEM;
// A map from user id to UserState.
+ @GuardedBy("mLock")
private final SparseArray<UserState> mUserStates = new SparseArray<>();
// A map from session id to session state saved in userstate
+ @GuardedBy("mLock")
private final Map<String, SessionState> mSessionIdToSessionStateMap = new HashMap<>();
private final WatchLogHandler mWatchLogHandler;
@@ -280,7 +283,7 @@ public final class TvInputManagerService extends SystemService {
return pm.checkPermission(android.Manifest.permission.TV_INPUT_HARDWARE,
component.getPackageName()) == PackageManager.PERMISSION_GRANTED;
}
-
+ @GuardedBy("mLock")
private void buildTvInputListLocked(int userId, String[] updatedPackages) {
UserState userState = getOrCreateUserStateLocked(userId);
userState.packageSet.clear();
@@ -368,6 +371,7 @@ public final class TvInputManagerService extends SystemService {
userState.inputMap = inputMap;
}
+ @GuardedBy("mLock")
private void buildTvContentRatingSystemListLocked(int userId) {
UserState userState = getOrCreateUserStateLocked(userId);
userState.contentRatingSystemList.clear();
@@ -444,6 +448,7 @@ public final class TvInputManagerService extends SystemService {
}
}
+ @GuardedBy("mLock")
private void clearSessionAndNotifyClientLocked(SessionState state) {
if (state.client != null) {
try {
@@ -528,6 +533,7 @@ public final class TvInputManagerService extends SystemService {
return context.getContentResolver();
}
+ @GuardedBy("mLock")
private UserState getOrCreateUserStateLocked(int userId) {
UserState userState = mUserStates.get(userId);
if (userState == null) {
@@ -537,6 +543,7 @@ public final class TvInputManagerService extends SystemService {
return userState;
}
+ @GuardedBy("mLock")
private ServiceState getServiceStateLocked(ComponentName component, int userId) {
UserState userState = getOrCreateUserStateLocked(userId);
ServiceState serviceState = userState.serviceStateMap.get(component);
@@ -546,9 +553,15 @@ public final class TvInputManagerService extends SystemService {
}
return serviceState;
}
-
+ @GuardedBy("mLock")
private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
UserState userState = getOrCreateUserStateLocked(userId);
+ return getSessionStateLocked(sessionToken, callingUid, userState);
+ }
+
+ @GuardedBy("mLock")
+ private SessionState getSessionStateLocked(IBinder sessionToken,
+ int callingUid, UserState userState) {
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
if (sessionState == null) {
throw new SessionNotFoundException("Session state not found for token " + sessionToken);
@@ -561,10 +574,12 @@ public final class TvInputManagerService extends SystemService {
return sessionState;
}
+ @GuardedBy("mLock")
private ITvInputSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
return getSessionLocked(getSessionStateLocked(sessionToken, callingUid, userId));
}
+ @GuardedBy("mLock")
private ITvInputSession getSessionLocked(SessionState sessionState) {
ITvInputSession session = sessionState.session;
if (session == null) {
@@ -580,6 +595,7 @@ public final class TvInputManagerService extends SystemService {
false, methodName, null);
}
+ @GuardedBy("mLock")
private void updateServiceConnectionLocked(ComponentName component, int userId) {
UserState userState = getOrCreateUserStateLocked(userId);
ServiceState serviceState = userState.serviceStateMap.get(component);
@@ -633,6 +649,7 @@ public final class TvInputManagerService extends SystemService {
}
}
+ @GuardedBy("mLock")
private void abortPendingCreateSessionRequestsLocked(ServiceState serviceState,
String inputId, int userId) {
// Let clients know the create session requests are failed.
@@ -653,6 +670,7 @@ public final class TvInputManagerService extends SystemService {
updateServiceConnectionLocked(serviceState.component, userId);
}
+ @GuardedBy("mLock")
private boolean createSessionInternalLocked(ITvInputService service, IBinder sessionToken,
int userId) {
UserState userState = getOrCreateUserStateLocked(userId);
@@ -686,6 +704,7 @@ public final class TvInputManagerService extends SystemService {
return created;
}
+ @GuardedBy("mLock")
private void sendSessionTokenToClientLocked(ITvInputClient client, String inputId,
IBinder sessionToken, InputChannel channel, int seq) {
try {
@@ -695,6 +714,7 @@ public final class TvInputManagerService extends SystemService {
}
}
+ @GuardedBy("mLock")
private void releaseSessionLocked(IBinder sessionToken, int callingUid, int userId) {
SessionState sessionState = null;
try {
@@ -720,6 +740,7 @@ public final class TvInputManagerService extends SystemService {
removeSessionStateLocked(sessionToken, userId);
}
+ @GuardedBy("mLock")
private void removeSessionStateLocked(IBinder sessionToken, int userId) {
UserState userState = getOrCreateUserStateLocked(userId);
if (sessionToken == userState.mainSessionToken) {
@@ -762,6 +783,7 @@ public final class TvInputManagerService extends SystemService {
mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_END, args).sendToTarget();
}
+ @GuardedBy("mLock")
private void setMainLocked(IBinder sessionToken, boolean isMain, int callingUid, int userId) {
try {
SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
@@ -780,6 +802,7 @@ public final class TvInputManagerService extends SystemService {
}
}
+ @GuardedBy("mLock")
private void notifyInputAddedLocked(UserState userState, String inputId) {
if (DEBUG) {
Slog.d(TAG, "notifyInputAddedLocked(inputId=" + inputId + ")");
@@ -795,6 +818,7 @@ public final class TvInputManagerService extends SystemService {
userState.mCallbacks.finishBroadcast();
}
+ @GuardedBy("mLock")
private void notifyInputRemovedLocked(UserState userState, String inputId) {
if (DEBUG) {
Slog.d(TAG, "notifyInputRemovedLocked(inputId=" + inputId + ")");
@@ -810,6 +834,7 @@ public final class TvInputManagerService extends SystemService {
userState.mCallbacks.finishBroadcast();
}
+ @GuardedBy("mLock")
private void notifyInputUpdatedLocked(UserState userState, String inputId) {
if (DEBUG) {
Slog.d(TAG, "notifyInputUpdatedLocked(inputId=" + inputId + ")");
@@ -825,6 +850,7 @@ public final class TvInputManagerService extends SystemService {
userState.mCallbacks.finishBroadcast();
}
+ @GuardedBy("mLock")
private void notifyInputStateChangedLocked(UserState userState, String inputId,
int state, ITvInputManagerCallback targetCallback) {
if (DEBUG) {
@@ -850,6 +876,7 @@ public final class TvInputManagerService extends SystemService {
}
}
+ @GuardedBy("mLock")
private void notifyCurrentChannelInfosUpdatedLocked(UserState userState) {
if (DEBUG) {
Slog.d(TAG, "notifyCurrentChannelInfosUpdatedLocked");
@@ -869,6 +896,7 @@ public final class TvInputManagerService extends SystemService {
userState.mCallbacks.finishBroadcast();
}
+ @GuardedBy("mLock")
private void updateTvInputInfoLocked(UserState userState, TvInputInfo inputInfo) {
if (DEBUG) {
Slog.d(TAG, "updateTvInputInfoLocked(inputInfo=" + inputInfo + ")");
@@ -892,6 +920,7 @@ public final class TvInputManagerService extends SystemService {
userState.mCallbacks.finishBroadcast();
}
+ @GuardedBy("mLock")
private void setStateLocked(String inputId, int state, int userId) {
UserState userState = getOrCreateUserStateLocked(userId);
TvInputState inputState = userState.inputMap.get(inputId);
@@ -1224,7 +1253,7 @@ public final class TvInputManagerService extends SystemService {
try {
synchronized (mLock) {
if (userId != mCurrentUserId && !isRecordingSession) {
- // A non-recording session of a backgroud (non-current) user
+ // A non-recording session of a background (non-current) user
// should not be created.
// Let the client get onConnectionFailed callback for this case.
sendSessionTokenToClientLocked(client, inputId, null, null, seq);
@@ -1436,12 +1465,11 @@ public final class TvInputManagerService extends SystemService {
getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(
channelUri, params);
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
- SessionState sessionState = userState.sessionStateMap.get(sessionToken);
- if (sessionState != null) {
- sessionState.isCurrent = true;
- sessionState.currentChannel = channelUri;
- notifyCurrentChannelInfosUpdatedLocked(userState);
- }
+ SessionState sessionState = getSessionStateLocked(sessionToken, callingUid,
+ userState);
+ sessionState.isCurrent = true;
+ sessionState.currentChannel = channelUri;
+ notifyCurrentChannelInfosUpdatedLocked(userState);
if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
// Do not log the watch history for passthrough inputs.
return;
@@ -2028,10 +2056,8 @@ public final class TvInputManagerService extends SystemService {
SessionState[] sessionStates = userState.sessionStateMap.values().toArray(
new SessionState[2]);
// Check if there is a wrapper input.
- if (sessionStates[0].hardwareSessionToken != null
- || sessionStates[1].hardwareSessionToken != null) {
- return true;
- }
+ return sessionStates[0].hardwareSessionToken != null
+ || sessionStates[1].hardwareSessionToken != null;
}
return false;
}
@@ -2111,7 +2137,7 @@ public final class TvInputManagerService extends SystemService {
* Add a hardware device in the TvInputHardwareManager for CTS testing
* purpose.
*
- * @param device id of the adding hardware device.
+ * @param deviceId the id of the adding hardware device.
*/
@Override
public void addHardwareDevice(int deviceId) {
@@ -2123,20 +2149,20 @@ public final class TvInputManagerService extends SystemService {
.hdmiPortId(0)
.build();
mTvInputHardwareManager.onDeviceAvailable(info, null);
- return;
}
/**
* Remove a hardware device in the TvInputHardwareManager for CTS testing
* purpose.
*
- * @param device id of the removing hardware device.
+ * @param deviceId the id of the removing hardware device.
*/
@Override
public void removeHardwareDevice(int deviceId) {
mTvInputHardwareManager.onDeviceUnavailable(deviceId);
}
+ @GuardedBy("mLock")
private int getClientPidLocked(String sessionId)
throws IllegalStateException {
if (mSessionIdToSessionStateMap.get(sessionId) == null) {
@@ -2254,7 +2280,6 @@ public final class TvInputManagerService extends SystemService {
pw.println("userId: " + session.userId);
pw.println("sessionToken: " + session.sessionToken);
pw.println("session: " + session.session);
- pw.println("logUri: " + session.logUri);
pw.println("hardwareSessionToken: " + session.hardwareSessionToken);
pw.decreaseIndent();
}
@@ -2264,7 +2289,7 @@ public final class TvInputManagerService extends SystemService {
pw.increaseIndent();
int n = userState.mCallbacks.beginBroadcast();
for (int j = 0; j < n; ++j) {
- pw.println(userState.mCallbacks.getRegisteredCallbackItem(j).toString());
+ pw.println(userState.mCallbacks.getRegisteredCallbackItem(j));
}
userState.mCallbacks.finishBroadcast();
pw.decreaseIndent();
@@ -2277,6 +2302,7 @@ public final class TvInputManagerService extends SystemService {
}
}
+ @GuardedBy("mLock")
private List<TunedInfo> getCurrentTunedInfosInternalLocked(
UserState userState, int callingPid, int callingUid) {
List<TunedInfo> channelInfos = new ArrayList<>();
@@ -2363,7 +2389,7 @@ public final class TvInputManagerService extends SystemService {
// A list of callbacks.
private final RemoteCallbackList<ITvInputManagerCallback> mCallbacks =
- new RemoteCallbackList<ITvInputManagerCallback>();
+ new RemoteCallbackList<>();
private final Map<ITvInputManagerCallback, Pair<Integer, Integer>> callbackPidUidMap =
new HashMap<>();
@@ -2375,9 +2401,9 @@ public final class TvInputManagerService extends SystemService {
// service.
private final PersistentDataStore persistentDataStore;
- @GuardedBy("mLock")
+ @GuardedBy("TvInputManagerService.this.mLock")
private final Map<Integer, Integer> mAppTagMap = new HashMap<>();
- @GuardedBy("mLock")
+ @GuardedBy("TvInputManagerService.this.mLock")
private int mNextAppTag = 1;
private UserState(Context context, int userId) {
@@ -2457,12 +2483,23 @@ public final class TvInputManagerService extends SystemService {
private final boolean isRecordingSession;
private final ITvInputClient client;
private final int seq;
+ /**
+ * The {code UID} of the application that created the session.
+ *
+ * <p>
+ * The application is usually the TIF Player.
+ */
private final int callingUid;
+ /**
+ * The {@code PID} of the application that created the session.
+ *
+ * <p>
+ * The application is usually the TIF Player.
+ */
private final int callingPid;
private final int userId;
private final IBinder sessionToken;
private ITvInputSession session;
- private Uri logUri;
// Not null if this session represents an external device connected to a hardware TV input.
private IBinder hardwareSessionToken;
@@ -2614,6 +2651,7 @@ public final class TvInputManagerService extends SystemService {
}
}
+ @GuardedBy("mLock")
private void addHardwareInputLocked(TvInputInfo inputInfo) {
ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
serviceState.hardwareInputMap.put(inputInfo.getId(), inputInfo);
@@ -2683,6 +2721,7 @@ public final class TvInputManagerService extends SystemService {
}
}
+ @GuardedBy("mLock")
private boolean addSessionTokenToClientStateLocked(ITvInputSession session) {
try {
session.asBinder().linkToDeath(mSessionState, 0);
@@ -3012,7 +3051,7 @@ public final class TvInputManagerService extends SystemService {
IBinder sessionToken = (IBinder) args.arg5;
ContentValues values = new ContentValues();
- values.put(TvContract.WatchedPrograms.COLUMN_PACKAGE_NAME, packageName);
+ values.put(TvContract.BaseTvColumns.COLUMN_PACKAGE_NAME, packageName);
values.put(TvContract.WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS,
watchStartTime);
values.put(TvContract.WatchedPrograms.COLUMN_CHANNEL_ID, channelId);
diff --git a/services/core/java/com/android/server/utils/Watchable.java b/services/core/java/com/android/server/utils/Watchable.java
new file mode 100644
index 000000000000..7c99274f3df2
--- /dev/null
+++ b/services/core/java/com/android/server/utils/Watchable.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.server.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+/**
+ * Notify registered {@link Watcher}s when the content changes.
+ */
+public interface Watchable {
+
+ /**
+ * Ensures an observer is in the list, exactly once. The observer cannot be null. The
+ * function quietly returns if the observer is already in the list.
+ *
+ * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
+ */
+ public void registerObserver(@NonNull Watcher observer);
+
+ /**
+ * Ensures an observer is not in the list. The observer must not be null. The function
+ * quietly returns if the objserver is not in the list.
+ *
+ * @param observer The {@link Watcher} that should not be in the notification list.
+ */
+ public void unregisterObserver(@NonNull Watcher observer);
+
+ /**
+ * Invokes {@link Watcher#onChange} on each registered observer. The method can be called
+ * with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this
+ * is generally the first (deepest) {@link Watchable} to detect a change.
+ *
+ * @param what The {@link Watchable} that generated the event.
+ */
+ public void dispatchChange(@Nullable Watchable what);
+}
diff --git a/services/core/java/com/android/server/utils/WatchableImpl.java b/services/core/java/com/android/server/utils/WatchableImpl.java
new file mode 100644
index 000000000000..94ab1d49807f
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchableImpl.java
@@ -0,0 +1,87 @@
+/*
+ * 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * A concrete implementation of {@link Watchable}
+ */
+public class WatchableImpl implements Watchable {
+ /**
+ * The list of observers.
+ */
+ protected final ArrayList<Watcher> mObservers = new ArrayList<>();
+
+ /**
+ * Ensure the observer is the list. The observer cannot be null but it is okay if it
+ * is already in the list.
+ *
+ * @param observer The {@link} Watcher to be added to the notification list.
+ */
+ @Override
+ public void registerObserver(@NonNull Watcher observer) {
+ Objects.requireNonNull(observer, "observer may not be null");
+ synchronized (mObservers) {
+ if (!mObservers.contains(observer)) {
+ mObservers.add(observer);
+ }
+ }
+ }
+
+ /**
+ * Removes a previously registered observer. The observer must not be null and it
+ * must already have been registered.
+ *
+ * @param observer The {@link} Watcher to be removed from the notification list.
+ */
+ @Override
+ public void unregisterObserver(@NonNull Watcher observer) {
+ Objects.requireNonNull(observer, "observer may not be null");
+ synchronized (mObservers) {
+ mObservers.remove(observer);
+ }
+ }
+
+ /**
+ * Return the number of registered observers.
+ *
+ * @return The number of registered observers.
+ */
+ public int registeredObserverCount() {
+ return mObservers.size();
+ }
+
+ /**
+ * Invokes {@link Watcher#onChange} on each observer.
+ *
+ * @param what The {@link Watchable} that generated the event
+ */
+ @Override
+ public void dispatchChange(@Nullable Watchable what) {
+ synchronized (mObservers) {
+ final int end = mObservers.size();
+ for (int i = 0; i < end; i++) {
+ mObservers.get(i).onChange(what);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/utils/WatchedArrayMap.java b/services/core/java/com/android/server/utils/WatchedArrayMap.java
new file mode 100644
index 000000000000..7b3298086aba
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedArrayMap.java
@@ -0,0 +1,389 @@
+/*
+ * 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * WatchedArrayMap is an {@link android.util.ArrayMap} that can report changes to itself. If its
+ * values are {@link Watchable} then the WatchedArrayMap will also report changes to the values.
+ * A {@link Watchable} is notified only once, no matter how many times it is stored in the array.
+ */
+public class WatchedArrayMap<K, V> extends WatchableImpl implements Map<K, V> {
+
+ // The storage
+ private final ArrayMap<K, V> mStorage;
+
+ // If true, the array is watching its children
+ private boolean mWatching = false;
+
+ // The local observer
+ private final Watcher mObserver = new Watcher() {
+ @Override
+ public void onChange(@Nullable Watchable what) {
+ WatchedArrayMap.this.dispatchChange(what);
+ }
+ };
+
+ /**
+ * A convenience function called when the elements are added to or removed from the storage.
+ * The watchable is always {@link this}.
+ */
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
+ /**
+ * A convenience function. Register the object if it is {@link Watchable} and if the
+ * array is currently watching. Note that the watching flag must be true if this
+ * function is to succeed. Also note that if this is called with the same object
+ * twice, <this> is only registered once.
+ */
+ private void registerChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).registerObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable} and if the
+ * array is currently watching. This unconditionally removes the object from the
+ * registered list.
+ */
+ private void unregisterChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable}, if the
+ * array is currently watching, and if there are no other instances of this object in
+ * the storage. Note that the watching flag must be true if this function is to
+ * succeed. The object must already have been removed from the storage before this
+ * method is called.
+ */
+ private void unregisterChildIf(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ if (!mStorage.containsValue(o)) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+ }
+
+ /**
+ * Register a {@link Watcher} with the array. If this is the first Watcher than any
+ * array values that are {@link Watchable} are registered to the array itself.
+ */
+ @Override
+ public void registerObserver(@NonNull Watcher observer) {
+ super.registerObserver(observer);
+ if (registeredObserverCount() == 1) {
+ // The watching flag must be set true before any children are registered.
+ mWatching = true;
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ registerChild(mStorage.valueAt(i));
+ }
+ }
+ }
+
+ /**
+ * Unregister a {@link Watcher} from the array. If this is the last Watcher than any
+ * array values that are {@link Watchable} are unregistered to the array itself.
+ */
+ @Override
+ public void unregisterObserver(@NonNull Watcher observer) {
+ super.unregisterObserver(observer);
+ if (registeredObserverCount() == 0) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.valueAt(i));
+ }
+ // The watching flag must be true while children are unregistered.
+ mWatching = false;
+ }
+ }
+
+ /**
+ * Create a new empty {@link WatchedArrayMap}. The default capacity of an array map
+ * is 0, and will grow once items are added to it.
+ */
+ public WatchedArrayMap() {
+ this(0, false);
+ }
+
+ /**
+ * Create a new {@link WatchedArrayMap} with a given initial capacity.
+ */
+ public WatchedArrayMap(int capacity) {
+ this(capacity, false);
+ }
+
+ /** {@hide} */
+ public WatchedArrayMap(int capacity, boolean identityHashCode) {
+ mStorage = new ArrayMap<K, V>(capacity, identityHashCode);
+ }
+
+ /**
+ * Create a new {@link WatchedArrayMap} with the mappings from the given {@link Map}.
+ */
+ public WatchedArrayMap(@Nullable Map<? extends K, ? extends V> map) {
+ mStorage = new ArrayMap<K, V>();
+ if (map != null) {
+ putAll(map);
+ }
+ }
+
+ /**
+ * Return the underlying storage. This breaks the wrapper but is necessary when
+ * passing the array to distant methods.
+ */
+ public ArrayMap untrackedMap() {
+ return mStorage;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void clear() {
+ // The storage cannot be simply cleared. Each element in the storage must be
+ // unregistered. Deregistration is only needed if the array is actually
+ // watching.
+ if (mWatching) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.valueAt(i));
+ }
+ }
+ mStorage.clear();
+ onChanged();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean containsKey(Object key) {
+ return mStorage.containsKey(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean containsValue(Object value) {
+ return mStorage.containsValue(value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<Map.Entry<K, V>> entrySet() {
+ return Collections.unmodifiableSet(mStorage.entrySet());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof WatchedArrayMap) {
+ WatchedArrayMap w = (WatchedArrayMap) o;
+ return mStorage.equals(w.mStorage);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public V get(Object key) {
+ return mStorage.get(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return mStorage.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isEmpty() {
+ return mStorage.isEmpty();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<K> keySet() {
+ return Collections.unmodifiableSet(mStorage.keySet());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public V put(K key, V value) {
+ final V result = mStorage.put(key, value);
+ registerChild(value);
+ onChanged();
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void putAll(@NonNull Map<? extends K, ? extends V> map) {
+ for (Map.Entry<? extends K, ? extends V> element : map.entrySet()) {
+ put(element.getKey(), element.getValue());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public V remove(@NonNull Object key) {
+ final V result = mStorage.remove(key);
+ unregisterChildIf(result);
+ onChanged();
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int size() {
+ return mStorage.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<V> values() {
+ return Collections.unmodifiableCollection(mStorage.values());
+ }
+
+ // Methods supported by ArrayMap that are not part of Map
+
+ /**
+ * Return the key at the given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ *
+ * @param index The desired index, must be between 0 and {@link #size()}-1.
+ * @return Returns the key stored at the given index.
+ */
+ public K keyAt(int index) {
+ return mStorage.keyAt(index);
+ }
+
+ /**
+ * Return the value at the given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ *
+ * @param index The desired index, must be between 0 and {@link #size()}-1.
+ * @return Returns the value stored at the given index.
+ */
+ public V valueAt(int index) {
+ return mStorage.valueAt(index);
+ }
+
+ /**
+ * Remove an existing key from the array map.
+ * @param key The key of the mapping to remove.
+ * @return Returns the value that was stored under the key, or null if there
+ * was no such key.
+ */
+ public int indexOfKey(K key) {
+ return mStorage.indexOfKey(key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified value, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(V value) {
+ return mStorage.indexOfValue(value);
+ }
+
+ /**
+ * Set the value at a given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ *
+ * @param index The desired index, must be between 0 and {@link #size()}-1.
+ * @param value The new value to store at this index.
+ * @return Returns the previous value at the given index.
+ */
+ public V setValueAt(int index, V value) {
+ final V result = mStorage.setValueAt(index, value);
+ if (value != result) {
+ unregisterChildIf(result);
+ registerChild(value);
+ onChanged();
+ }
+ return result;
+ }
+
+ /**
+ * Remove the key/value mapping at the given index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ *
+ * @param index The desired index, must be between 0 and {@link #size()}-1.
+ * @return Returns the value that was stored at this index.
+ */
+ public V removeAt(int index) {
+ final V result = mStorage.removeAt(index);
+ unregisterChildIf(result);
+ onChanged();
+ return result;
+ }
+}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseArray.java b/services/core/java/com/android/server/utils/WatchedSparseArray.java
new file mode 100644
index 000000000000..4d43b682e113
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedSparseArray.java
@@ -0,0 +1,401 @@
+/*
+ * 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+
+/**
+ * A watched variant of SparseArray. If a {@link Watchable} is stored in the array, the
+ * array registers with the {@link Watchable}. The array registers only once with each
+ * {@link Watchable} no matter how many times the {@link Watchable} is stored in the
+ * array.
+ */
+public class WatchedSparseArray<E> extends WatchableImpl {
+
+ // The storage
+ private final SparseArray<E> mStorage;
+
+ // If true, the array is watching its children
+ private boolean mWatching = false;
+
+ // The local observer
+ private final Watcher mObserver = new Watcher() {
+ @Override
+ public void onChange(@Nullable Watchable o) {
+ WatchedSparseArray.this.dispatchChange(o);
+ }
+ };
+
+ /**
+ * A private convenience function that notifies registered listeners that an element
+ * has been added to or removed from the array. The what parameter is the array itself.
+ */
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
+ /**
+ * A convenience function. Register the object if it is {@link Watchable} and if the
+ * array is currently watching. Note that the watching flag must be true if this
+ * function is to succeed.
+ */
+ private void registerChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).registerObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable} and if
+ * the array is currently watching. Note that the watching flag must be true if this
+ * function is to succeed.
+ */
+ private void unregisterChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable}, if the array is
+ * currently watching, and if the storage does not contain the object. Note that the watching
+ * flag must be true if this function is to succeed. This must be called after an object has
+ * been removed from the storage.
+ */
+ private void unregisterChildIf(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ if (mStorage.indexOfValue((E) o) == -1) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+ }
+
+ /**
+ * Register a {@link Watcher} with the array. If this is the first Watcher than any
+ * array values that are {@link Watchable} are registered to the array itself.
+ */
+ @Override
+ public void registerObserver(@NonNull Watcher observer) {
+ super.registerObserver(observer);
+ if (registeredObserverCount() == 1) {
+ // The watching flag must be set true before any children are registered.
+ mWatching = true;
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ registerChild(mStorage.valueAt(i));
+ }
+ }
+ }
+
+ /**
+ * Unregister a {@link Watcher} from the array. If this is the last Watcher than any
+ * array values that are {@link Watchable} are unregistered to the array itself.
+ */
+ @Override
+ public void unregisterObserver(@NonNull Watcher observer) {
+ super.unregisterObserver(observer);
+ if (registeredObserverCount() == 0) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.valueAt(i));
+ }
+ // The watching flag must be true while children are unregistered.
+ mWatching = false;
+ }
+ }
+
+ /**
+ * Creates a new WatchedSparseArray containing no mappings.
+ */
+ public WatchedSparseArray() {
+ mStorage = new SparseArray();
+ }
+
+ /**
+ * Creates a new WatchedSparseArray containing no mappings that
+ * will not require any additional memory allocation to store the
+ * specified number of mappings. If you supply an initial capacity of
+ * 0, the sparse array will be initialized with a light-weight
+ * representation not requiring any additional array allocations.
+ */
+ public WatchedSparseArray(int initialCapacity) {
+ mStorage = new SparseArray(initialCapacity);
+ }
+
+ /**
+ * The copy constructor does not copy the watcher data.
+ */
+ public WatchedSparseArray(@NonNull WatchedSparseArray<E> r) {
+ mStorage = r.mStorage.clone();
+ }
+
+ /**
+ * Returns true if the key exists in the array. This is equivalent to
+ * {@link #indexOfKey(int)} >= 0.
+ *
+ * @param key Potential key in the mapping
+ * @return true if the key is defined in the mapping
+ */
+ public boolean contains(int key) {
+ return mStorage.contains(key);
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or <code>null</code>
+ * if no such mapping has been made.
+ */
+ public E get(int key) {
+ return mStorage.get(key);
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or the specified Object
+ * if no such mapping has been made.
+ */
+ public E get(int key, E valueIfKeyNotFound) {
+ return mStorage.get(key, valueIfKeyNotFound);
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key) {
+ final E child = mStorage.get(key);
+ mStorage.delete(key);
+ unregisterChildIf(child);
+ onChanged();
+ }
+
+ /**
+ * @hide
+ * Removes the mapping from the specified key, if there was any, returning the old value.
+ */
+ public E removeReturnOld(int key) {
+ final E result = mStorage.removeReturnOld(key);
+ unregisterChildIf(result);
+ return result;
+ }
+
+ /**
+ * Alias for {@link #delete(int)}.
+ */
+ public void remove(int key) {
+ delete(key);
+ }
+
+ /**
+ * Removes the mapping at the specified index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ */
+ public void removeAt(int index) {
+ final E child = mStorage.valueAt(index);
+ mStorage.removeAt(index);
+ unregisterChildIf(child);
+ onChanged();
+ }
+
+ /**
+ * Remove a range of mappings as a batch.
+ *
+ * @param index Index to begin at
+ * @param size Number of mappings to remove
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>,
+ * the behavior is undefined.</p>
+ */
+ public void removeAtRange(int index, int size) {
+ final ArrayList<E> children = new ArrayList<>();
+ try {
+ for (int i = 0; i < size; i++) {
+ children.add(mStorage.valueAt(i + index));
+ }
+ } catch (Exception e) {
+ // Ignore any exception and proceed with removal.
+ }
+ try {
+ mStorage.removeAtRange(index, size);
+ } finally {
+ // Even on exception, make sure to deregister children that have been
+ // removed.
+ for (int i = 0; i < size; i++) {
+ unregisterChildIf(children.get(i));
+ }
+ }
+ onChanged();
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(int key, E value) {
+ final E old = mStorage.get(key);
+ mStorage.put(key, value);
+ unregisterChildIf(old);
+ registerChild(value);
+ onChanged();
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseArray
+ * currently stores.
+ */
+ public int size() {
+ return mStorage.size();
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>,
+ * the behavior is undefined for apps targeting {@link android.os.Build.VERSION_CODES#P} and
+ * earlier, and an {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public int keyAt(int index) {
+ return mStorage.keyAt(index);
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>,
+ * the behavior is undefined for apps targeting {@link android.os.Build.VERSION_CODES#P} and
+ * earlier, and an {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public E valueAt(int index) {
+ return mStorage.valueAt(index);
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, sets a new
+ * value for the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public void setValueAt(int index, E value) {
+ final E old = mStorage.valueAt(index);
+ mStorage.setValueAt(index, value);
+ if (value != old) {
+ unregisterChildIf(old);
+ registerChild(value);
+ onChanged();
+ }
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(int key) {
+ return mStorage.indexOfKey(key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified value, or a negative number if no keys map to the
+ * specified value.
+ * <p>Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ * <p>Note also that unlike most collections' {@code indexOf} methods,
+ * this method compares values using {@code ==} rather than {@code equals}.
+ */
+ public int indexOfValue(E value) {
+ return mStorage.indexOfValue(value);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified value, or a negative number if no keys map to the
+ * specified value.
+ * <p>Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ * <p>Note also that this method uses {@code equals} unlike {@code indexOfValue}.
+ * @hide
+ */
+ public int indexOfValueByValue(E value) {
+ return mStorage.indexOfValueByValue(value);
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseArray.
+ */
+ public void clear() {
+ // The storage cannot be simply cleared. Each element in the storage must be
+ // unregistered. Deregistration is only needed if the array is actually
+ // watching.
+ if (mWatching) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.valueAt(i));
+ }
+ }
+ mStorage.clear();
+ onChanged();
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(int key, E value) {
+ mStorage.append(key, value);
+ registerChild(value);
+ onChanged();
+ }
+
+ /**
+ * <p>This implementation composes a string by iterating over its mappings. If
+ * this map contains itself as a value, the string "(this Map)"
+ * will appear in its place.
+ */
+ @Override
+ public String toString() {
+ return mStorage.toString();
+ }
+}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
new file mode 100644
index 000000000000..edf7d27b61dd
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
@@ -0,0 +1,236 @@
+/*
+ * 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import android.util.SparseBooleanArray;
+
+/**
+ * A watched variant of SparseBooleanArray. Changes to the array are notified to
+ * registered {@link Watcher}s.
+ */
+public class WatchedSparseBooleanArray extends WatchableImpl {
+
+ // The storage
+ private final SparseBooleanArray mStorage;
+
+ // A private convenience function
+ private void dispatchChange() {
+ dispatchChange(this);
+ }
+
+ /**
+ * Creates a new WatchedSparseBooleanArray containing no mappings.
+ */
+ public WatchedSparseBooleanArray() {
+ mStorage = new SparseBooleanArray();
+ }
+
+ /**
+ * Creates a new WatchedSparseBooleanArray containing no mappings that
+ * will not require any additional memory allocation to store the
+ * specified number of mappings. If you supply an initial capacity of
+ * 0, the sparse array will be initialized with a light-weight
+ * representation not requiring any additional array allocations.
+ */
+ public WatchedSparseBooleanArray(int initialCapacity) {
+ mStorage = new SparseBooleanArray(initialCapacity);
+ }
+
+ /**
+ * The copy constructor does not copy the watcher data.
+ */
+ public WatchedSparseBooleanArray(@NonNull WatchedSparseBooleanArray r) {
+ mStorage = r.mStorage.clone();
+ }
+
+ /**
+ * Gets the boolean mapped from the specified key, or <code>false</code>
+ * if no such mapping has been made.
+ */
+ public boolean get(int key) {
+ return mStorage.get(key);
+ }
+
+ /**
+ * Gets the boolean mapped from the specified key, or the specified value
+ * if no such mapping has been made.
+ */
+ public boolean get(int key, boolean valueIfKeyNotFound) {
+ return mStorage.get(key, valueIfKeyNotFound);
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key) {
+ mStorage.delete(key);
+ dispatchChange();
+ }
+
+ /**
+ * Removes the mapping at the specified index.
+ * <p>
+ * For indices outside of the range {@code 0...size()-1}, the behavior is undefined.
+ */
+ public void removeAt(int index) {
+ mStorage.removeAt(index);
+ dispatchChange();
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(int key, boolean value) {
+ if (mStorage.get(key) != value) {
+ mStorage.put(key, value);
+ dispatchChange();
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseBooleanArray
+ * currently stores.
+ */
+ public int size() {
+ return mStorage.size();
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseBooleanArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public int keyAt(int index) {
+ return mStorage.keyAt(index);
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseBooleanArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public boolean valueAt(int index) {
+ return mStorage.valueAt(index);
+ }
+
+ /**
+ * Directly set the value at a particular index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public void setValueAt(int index, boolean value) {
+ if (mStorage.valueAt(index) != value) {
+ mStorage.setValueAt(index, value);
+ dispatchChange();
+ }
+ }
+
+ /** @hide */
+ public void setKeyAt(int index, int key) {
+ if (mStorage.keyAt(index) != key) {
+ mStorage.setKeyAt(index, key);
+ dispatchChange();
+ }
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(int key) {
+ return mStorage.indexOfKey(key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified key, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(boolean value) {
+ return mStorage.indexOfValue(value);
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseBooleanArray.
+ */
+ public void clear() {
+ mStorage.clear();
+ dispatchChange();
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(int key, boolean value) {
+ mStorage.append(key, value);
+ dispatchChange();
+ }
+
+ @Override
+ public int hashCode() {
+ return mStorage.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object that) {
+ return this == that || mStorage.equals(that);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation composes a string by iterating over its mappings.
+ */
+ @Override
+ public String toString() {
+ return mStorage.toString();
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java b/services/core/java/com/android/server/utils/Watcher.java
index 3e7b4a2665ee..a9bfbfa0c7dc 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewMediator.java
+++ b/services/core/java/com/android/server/utils/Watcher.java
@@ -14,24 +14,22 @@
* limitations under the License.
*/
-package com.android.systemui.car.window;
+package com.android.server.utils;
+
+import android.annotation.Nullable;
/**
- * Controls when to show and hide {@link OverlayViewController}(s).
+ * This class receives notifications when watched objects detect changes.
+ * Must be implemented by objects which are registered to a {@link Watchable}.
*/
-public interface OverlayViewMediator {
+public abstract class Watcher {
/**
- * Register listeners that could use ContentVisibilityAdjuster to show/hide content.
+ * This method is called when {@link Watchable} detects a change. The <what>
+ * parameter indicates what changed, but it may be null. The parameter is intended
+ * for debugging.
*
- * Note that we do not unregister listeners because SystemUI components are expected to live
- * for the lifecycle of the device.
- */
- void registerListeners();
-
- /**
- * Allows for post-inflation callbacks and listeners to be set inside required {@link
- * OverlayViewController}(s).
+ * @param what The {@link Watchable} that changed.
*/
- void setupOverlayContentViewControllers();
+ public abstract void onChange(@Nullable Watchable what);
}
diff --git a/services/core/java/com/android/server/utils/quota/QuotaTracker.java b/services/core/java/com/android/server/utils/quota/QuotaTracker.java
index c1dfcf772f84..7f446185f63f 100644
--- a/services/core/java/com/android/server/utils/quota/QuotaTracker.java
+++ b/services/core/java/com/android/server/utils/quota/QuotaTracker.java
@@ -149,9 +149,13 @@ abstract class QuotaTracker {
@VisibleForTesting
static final long MAX_WINDOW_SIZE_MS = 30 * 24 * 60 * MINUTE_IN_MILLIS; // 1 month
- /** The minimum time any window size can be. */
+ /**
+ * The minimum time any window size can be. A minimum window size helps to avoid CPU
+ * churn/looping in cases where there are registered listeners for when UPTCs go in and out of
+ * quota.
+ */
@VisibleForTesting
- static final long MIN_WINDOW_SIZE_MS = 30_000; // 30 seconds
+ static final long MIN_WINDOW_SIZE_MS = 20_000;
QuotaTracker(@NonNull Context context, @NonNull Categorizer categorizer,
@NonNull Injector injector) {
@@ -622,6 +626,9 @@ abstract class QuotaTracker {
/** Dump state in text format. */
public void dump(final IndentingPrintWriter pw) {
+ pw.println("QuotaTracker:");
+ pw.increaseIndent();
+
synchronized (mLock) {
pw.println("Is enabled: " + mIsEnabled);
pw.println("Is global quota free: " + mIsQuotaFree);
@@ -646,6 +653,8 @@ abstract class QuotaTracker {
}
pw.decreaseIndent();
}
+
+ pw.decreaseIndent();
}
/**
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index 4d670f1eb59c..dd0ec948aa3a 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -163,6 +163,7 @@ class WebViewUpdateServiceImpl {
}
void prepareWebViewInSystemServer() {
+ mSystemInterface.notifyZygote(isMultiProcessEnabled());
try {
synchronized (mLock) {
mCurrentWebViewPackage = findPreferredWebViewPackage();
@@ -199,12 +200,6 @@ class WebViewUpdateServiceImpl {
Slog.e(TAG, "No valid provider and no fallback available.");
}
}
-
- boolean multiProcessEnabled = isMultiProcessEnabled();
- mSystemInterface.notifyZygote(multiProcessEnabled);
- if (multiProcessEnabled) {
- AsyncTask.THREAD_POOL_EXECUTOR.execute(this::startZygoteWhenReady);
- }
}
private void startZygoteWhenReady() {
@@ -358,6 +353,12 @@ class WebViewUpdateServiceImpl {
mWebViewPackageDirty = true;
}
}
+
+ // Once we've notified the system that the provider has changed and started RELRO creation,
+ // try to restart the zygote so that it will be ready when apps use it.
+ if (isMultiProcessEnabled()) {
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(this::startZygoteWhenReady);
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 9e211672539c..f4e0fb16ed3f 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -857,7 +857,7 @@ final class AccessibilityController {
private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
mTempLayer = 0;
mDisplayContent.forAllWindows((w) -> {
- if (w.isOnScreen() && w.isVisibleLw()
+ if (w.isOnScreen() && w.isVisible()
&& (w.mAttrs.alpha != 0)) {
mTempLayer++;
outWindows.put(mTempLayer, w);
@@ -1517,7 +1517,7 @@ final class AccessibilityController {
}
dc.forAllWindows(w -> {
- if (w.isVisibleLw()) {
+ if (w.isVisible()) {
tempWindowStatesList.add(w);
}
}, false /* traverseTopToBottom */);
@@ -1529,7 +1529,7 @@ final class AccessibilityController {
return;
}
- if (w.isVisibleLw() && tempWindowStatesList.contains(parentWindow)) {
+ if (w.isVisible() && tempWindowStatesList.contains(parentWindow)) {
tempWindowStatesList.add(tempWindowStatesList.lastIndexOf(parentWindow), w);
}
}, false /* traverseTopToBottom */);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f65a5024bdea..107690614f82 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -194,7 +194,7 @@ import static com.android.server.wm.Task.ActivityState.RESUMED;
import static com.android.server.wm.Task.ActivityState.STARTED;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
import static com.android.server.wm.TaskPersister.DEBUG;
import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
@@ -417,7 +417,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// mOccludesParent field.
final boolean hasWallpaper;
// Input application handle used by the input dispatcher.
- final InputApplicationHandle mInputApplicationHandle;
+ private InputApplicationHandle mInputApplicationHandle;
final int launchedFromPid; // always the pid who started the activity.
final int launchedFromUid; // always the uid who started the activity.
@@ -445,7 +445,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private Task task; // the task this is in.
private long createTime = System.currentTimeMillis();
long lastVisibleTime; // last time this activity became visible
- long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity
long pauseTime; // last time we started pausing the activity
long launchTickTime; // base time for launch tick messages
long topResumedStateLossTime; // last time we reported top resumed state loss to an activity
@@ -652,8 +651,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Information about an application starting window if displayed.
// Note: these are de-referenced before the starting window animates away.
StartingData mStartingData;
- WindowState startingWindow;
- WindowManagerPolicy.StartingSurface startingSurface;
+ WindowState mStartingWindow;
+ WindowManagerPolicy.StartingSurface mStartingSurface;
boolean startingDisplayed;
boolean startingMoved;
@@ -951,10 +950,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
pw.print(" mIsExiting="); pw.println(mIsExiting);
}
- if (startingWindow != null || startingSurface != null
+ if (mStartingWindow != null || mStartingSurface != null
|| startingDisplayed || startingMoved || mVisibleSetFromTransferredStartingWindow) {
- pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
- pw.print(" startingSurface="); pw.print(startingSurface);
+ pw.print(prefix); pw.print("startingWindow="); pw.print(mStartingWindow);
+ pw.print(" startingSurface="); pw.print(mStartingSurface);
pw.print(" startingDisplayed="); pw.print(startingDisplayed);
pw.print(" startingMoved="); pw.print(startingMoved);
pw.println(" mVisibleSetFromTransferredStartingWindow="
@@ -1506,7 +1505,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
info = aInfo;
mUserId = UserHandle.getUserId(info.applicationInfo.uid);
packageName = info.applicationInfo.packageName;
- mInputApplicationHandle = new InputApplicationHandle(appToken);
intent = _intent;
// If the class name in the intent doesn't match that of the target, this is probably an
@@ -1693,6 +1691,21 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return lockTaskLaunchMode;
}
+ @NonNull InputApplicationHandle getInputApplicationHandle(boolean update) {
+ if (mInputApplicationHandle == null) {
+ mInputApplicationHandle = new InputApplicationHandle(appToken, toString(),
+ mInputDispatchingTimeoutMillis);
+ } else if (update) {
+ final String name = toString();
+ if (mInputDispatchingTimeoutMillis != mInputApplicationHandle.dispatchingTimeoutMillis
+ || !name.equals(mInputApplicationHandle.name)) {
+ mInputApplicationHandle = new InputApplicationHandle(appToken, name,
+ mInputDispatchingTimeoutMillis);
+ }
+ }
+ return mInputApplicationHandle;
+ }
+
@Override
ActivityRecord asActivityRecord() {
// I am an activity record!
@@ -1883,16 +1896,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Aborted starting %s: startingData=%s",
ActivityRecord.this, mStartingData);
- startingWindow = null;
+ mStartingWindow = null;
mStartingData = null;
abort = true;
} else {
- startingSurface = surface;
+ mStartingSurface = surface;
}
if (!abort) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
"Added starting %s: startingWindow=%s startingView=%s",
- ActivityRecord.this, startingWindow, startingSurface);
+ ActivityRecord.this, mStartingWindow, mStartingSurface);
}
}
if (abort) {
@@ -1944,7 +1957,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
void removeStartingWindow() {
- if (startingWindow == null) {
+ if (mStartingWindow == null) {
if (mStartingData != null) {
// Starting window has not been added yet, but it is scheduled to be added.
// Go ahead and cancel the request.
@@ -1956,10 +1969,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final WindowManagerPolicy.StartingSurface surface;
if (mStartingData != null) {
- surface = startingSurface;
+ surface = mStartingSurface;
mStartingData = null;
- startingSurface = null;
- startingWindow = null;
+ mStartingSurface = null;
+ mStartingWindow = null;
startingDisplayed = false;
if (surface == null) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "startingWindow was set but "
@@ -1975,7 +1988,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s"
- + " startingView=%s Callers=%s", this, startingWindow, startingSurface,
+ + " startingView=%s Callers=%s", this, mStartingWindow, mStartingSurface,
Debug.getCallers(5));
@@ -2725,7 +2738,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (ensureVisibility) {
mDisplayContent.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
- false /* preserveWindows */, true /* notifyClients */);
+ false /* preserveWindows */, true /* notifyClients */,
+ mStackSupervisor.mUserLeaving);
}
}
@@ -3430,8 +3444,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
- final WindowState tStartingWindow = fromActivity.startingWindow;
- if (tStartingWindow != null && fromActivity.startingSurface != null) {
+ final WindowState tStartingWindow = fromActivity.mStartingWindow;
+ if (tStartingWindow != null && fromActivity.mStartingSurface != null) {
// In this case, the starting icon has already been displayed, so start
// letting windows get shown immediately without any more transitions.
getDisplayContent().mSkipAppTransitionAnimation = true;
@@ -3450,14 +3464,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Transfer the starting window over to the new token.
mStartingData = fromActivity.mStartingData;
- startingSurface = fromActivity.startingSurface;
+ mStartingSurface = fromActivity.mStartingSurface;
startingDisplayed = fromActivity.startingDisplayed;
fromActivity.startingDisplayed = false;
- startingWindow = tStartingWindow;
+ mStartingWindow = tStartingWindow;
reportedVisible = fromActivity.reportedVisible;
fromActivity.mStartingData = null;
- fromActivity.startingSurface = null;
- fromActivity.startingWindow = null;
+ fromActivity.mStartingSurface = null;
+ fromActivity.mStartingWindow = null;
fromActivity.startingMoved = true;
tStartingWindow.mToken = this;
tStartingWindow.mActivityRecord = this;
@@ -4307,9 +4321,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else {
// If we are being set visible, and the starting window is not yet displayed,
// then make sure it doesn't get displayed.
- if (startingWindow != null && !startingWindow.isDrawn()) {
- startingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
- startingWindow.mLegacyPolicyVisibilityAfterAnim = false;
+ if (mStartingWindow != null && !mStartingWindow.isDrawn()) {
+ mStartingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
+ mStartingWindow.mLegacyPolicyVisibilityAfterAnim = false;
}
// We are becoming visible, so better freeze the screen with the windows that are
// getting visible so we also wait for them.
@@ -4739,7 +4753,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
handleAlreadyVisible();
}
- void makeInvisible() {
+ void makeInvisible(boolean userLeaving) {
if (!mVisibleRequested) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this);
return;
@@ -4780,9 +4794,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// If the app is capable of entering PIP, we should try pausing it now
// so it can PIP correctly.
if (deferHidingClient) {
- getRootTask().startPausingLocked(
- mStackSupervisor.mUserLeaving /* userLeaving */,
- false /* uiSleeping */, null /* resuming */, "makeInvisible");
+ getRootTask().startPausingLocked(userLeaving, false /* uiSleeping */,
+ null /* resuming */, "makeInvisible");
break;
}
case INITIALIZING:
@@ -4881,7 +4894,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
private boolean shouldBeResumed(ActivityRecord activeActivity) {
return shouldMakeActive(activeActivity) && isFocusable()
- && getTask().getVisibility(activeActivity) == STACK_VISIBILITY_VISIBLE
+ && getTask().getVisibility(activeActivity) == TASK_VISIBILITY_VISIBLE
&& canResumeByCompat();
}
@@ -4996,16 +5009,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
resumeKeyDispatchingLocked();
final Task stack = getRootTask();
mStackSupervisor.mNoAnimActivities.clear();
-
- // Mark the point when the activity is resuming
- // TODO: To be more accurate, the mark should be before the onCreate,
- // not after the onResume. But for subsequent starts, onResume is fine.
- if (hasProcess()) {
- cpuTimeAtResume = app.getCpuTime();
- } else {
- cpuTimeAtResume = 0; // Couldn't get the cpu time of process
- }
-
returningOptions = null;
if (canTurnScreenOn()) {
@@ -5392,7 +5395,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// We now have a good window to show, remove dead placeholders
removeDeadWindows();
- if (startingWindow != null) {
+ if (mStartingWindow != null) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s"
+ ": first real window is shown, no animation", win.mToken);
// If this initial window is animating, stop it -- we will do an animation to reveal
@@ -5567,7 +5570,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean updateDrawnWindowStates(WindowState w) {
w.setDrawnStateEvaluated(true /*evaluated*/);
- if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) {
+ if (DEBUG_STARTING_WINDOW_VERBOSE && w == mStartingWindow) {
Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
+ " allDrawn=" + allDrawn + " freezingScreen=" + mFreezingScreen);
}
@@ -5604,7 +5607,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- if (w != startingWindow) {
+ if (w != mStartingWindow) {
if (w.isInteresting()) {
// Add non-main window as interesting since the main app has already been added
if (findMainWindow(false /* includeStartingApp */) != w) {
@@ -5844,7 +5847,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
void postWindowRemoveStartingWindowCleanup(WindowState win) {
// TODO: Something smells about the code below...Is there a better way?
- if (startingWindow == win) {
+ if (mStartingWindow == win) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Notify removed startingWindow %s", win);
removeStartingWindow();
} else if (mChildren.size() == 0) {
@@ -5858,7 +5861,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// window in the token.
setVisible(false);
}
- } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) {
+ } else if (mChildren.size() == 1 && mStartingSurface != null && !isRelaunching()) {
// If this is the last window except for a starting transition window,
// we need to get rid of the starting transition.
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Last window, removing starting window %s", win);
@@ -6358,7 +6361,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
final IBinder freezeToken = mayFreezeScreenLocked() ? appToken : null;
- onDescendantOrientationChanged(freezeToken, this);
+ if (onDescendantOrientationChanged(freezeToken, this)) {
+ // The app is just becoming visible, and the parent Task has updated with the
+ // orientation request. Update the size compat mode.
+ updateSizeCompatMode();
+ }
}
/**
@@ -6524,6 +6531,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
+ if (task == null || (!handlesOrientationChangeFromDescendant()
+ && task.getLastTaskBoundsComputeActivity() != this)) {
+ // Don't compute when Task hasn't computed its bounds for this app, because the Task can
+ // be letterboxed, and its bounds may not be accurate until then.
+ return;
+ }
+
Configuration overrideConfig = getRequestedOverrideConfiguration();
final Configuration fullConfig = getConfiguration();
@@ -6548,20 +6562,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mCompatDisplayInsets = new CompatDisplayInsets(mDisplayContent, this);
}
- void clearSizeCompatMode(boolean recomputeTask) {
+ @VisibleForTesting
+ void clearSizeCompatMode() {
mSizeCompatScale = 1f;
mSizeCompatBounds = null;
mCompatDisplayInsets = null;
- if (recomputeTask) {
- // Recompute from Task because letterbox can also happen on Task level.
- task.onRequestedOverrideConfigurationChanged(task.getRequestedOverrideConfiguration());
- }
- }
-
- @VisibleForTesting
- void clearSizeCompatMode() {
- clearSizeCompatMode(true /* recomputeTask */);
+ // Recompute from Task because letterbox can also happen on Task level.
+ task.onRequestedOverrideConfigurationChanged(task.getRequestedOverrideConfiguration());
}
@Override
@@ -7685,8 +7693,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows);
proto.write(ALL_DRAWN, allDrawn);
proto.write(LAST_ALL_DRAWN, mLastAllDrawn);
- if (startingWindow != null) {
- startingWindow.writeIdentifierToProto(proto, STARTING_WINDOW);
+ if (mStartingWindow != null) {
+ mStartingWindow.writeIdentifierToProto(proto, STARTING_WINDOW);
}
proto.write(STARTING_DISPLAYED, startingDisplayed);
proto.write(STARTING_MOVED, startingMoved);
@@ -7774,15 +7782,23 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
- if (container.getTask().isTaskLetterboxed()) {
+ final Task task = container.getTask();
+ if (task != null && task.isTaskLetterboxed()) {
// For apps in Task letterbox, it should fill the task bounds.
- final Rect taskBounds = container.getTask().getBounds();
- mWidth = taskBounds.width();
- mHeight = taskBounds.height();
+ final Point dimensions = getRotationZeroDimensions(task);
+ mWidth = dimensions.x;
+ mHeight = dimensions.y;
} else {
- // If the activity is not floating nor letterboxed, assume it fills the display.
- mWidth = display.mBaseDisplayWidth;
- mHeight = display.mBaseDisplayHeight;
+ // If the activity is not floating nor letterboxed, assume it fills the root.
+ final RootDisplayArea root = container.getRootDisplayArea();
+ if (root == null || root == display) {
+ mWidth = display.mBaseDisplayWidth;
+ mHeight = display.mBaseDisplayHeight;
+ } else {
+ final Point dimensions = getRotationZeroDimensions(root);
+ mWidth = dimensions.x;
+ mHeight = dimensions.y;
+ }
}
final DisplayPolicy policy = display.getDisplayPolicy();
for (int rotation = 0; rotation < 4; rotation++) {
@@ -7799,6 +7815,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
+ /**
+ * Gets the width and height of the {@code container} when it is not rotated, so that after
+ * the display is rotated, we can calculate the bounds by rotating the dimensions.
+ * @see #getBoundsByRotation
+ */
+ private static Point getRotationZeroDimensions(WindowContainer container) {
+ final Rect bounds = container.getBounds();
+ final int rotation = container.getConfiguration().windowConfiguration.getRotation();
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ final int width = bounds.width();
+ final int height = bounds.height();
+ return rotated ? new Point(height, width) : new Point(width, height);
+ }
+
void getBoundsByRotation(Rect outBounds, int rotation) {
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
final int dw = rotated ? mHeight : mWidth;
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a068d2b7c823..e2a7afb64fca 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -50,12 +50,12 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_IDLE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
@@ -63,17 +63,17 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_STACK_MSG;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.Task.ActivityState.PAUSED;
import static com.android.server.wm.Task.ActivityState.PAUSING;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_ALLOWLISTED;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
+import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
import static com.android.server.wm.Task.TAG_CLEANUP;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -158,7 +158,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
private static final String TAG_IDLE = TAG + POSTFIX_IDLE;
private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
- private static final String TAG_STACK = TAG + POSTFIX_STACK;
+ private static final String TAG_ROOT_TASK = TAG + POSTFIX_ROOT_TASK;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
static final String TAG_TASKS = TAG + POSTFIX_TASKS;
@@ -526,7 +526,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
int candidateTaskId = nextTaskIdForUser(currentTaskId, userId);
while (mRecentTasks.containsTaskId(candidateTaskId, userId)
|| mRootWindowContainer.anyTaskForId(
- candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) {
+ candidateTaskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS) != null) {
candidateTaskId = nextTaskIdForUser(candidateTaskId, userId);
if (candidateTaskId == currentTaskId) {
// Something wrong!
@@ -1360,8 +1360,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
if (stack != currentStack) {
moveHomeStackToFrontIfNeeded(flags, stack.getDisplayArea(), reason);
- task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME,
- reason);
+ task.reparent(stack, ON_TOP, REPARENT_KEEP_ROOT_TASK_AT_FRONT, !ANIMATE,
+ DEFER_RESUME, reason);
currentStack = stack;
reparented = true;
// task.reparent() should already placed the task on top,
@@ -1385,7 +1385,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
currentStack.moveTaskToFront(task, false /* noAnimation */, options,
r == null ? null : r.appTimeTracker, reason);
- if (DEBUG_STACK) Slog.d(TAG_STACK,
+ if (DEBUG_ROOT_TASK) Slog.d(TAG_ROOT_TASK,
"findTaskToMoveToFront: moved to front of stack=" + currentStack);
handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
@@ -1502,7 +1502,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
boolean removeTaskById(int taskId, boolean killProcess, boolean removeFromRecents,
String reason) {
final Task task =
- mRootWindowContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ mRootWindowContainer.anyTaskForId(taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task != null) {
removeTask(task, killProcess, removeFromRecents, reason);
return true;
@@ -2189,7 +2189,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
.notifyActivityDismissingDockedStack();
taskDisplayArea.onSplitScreenModeDismissed(task);
taskDisplayArea.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
- true /* notifyClients */);
+ true /* notifyClients */, mUserLeaving);
}
return;
}
@@ -2478,7 +2478,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
mService.deferWindowLayout();
try {
task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
if (task == null) {
mWindowManager.executeAppTransition();
throw new IllegalArgumentException(
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 910a1a2c69b2..6f979363e3bd 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -75,7 +75,7 @@ import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
import static com.android.server.wm.Task.ActivityState.RESUMED;
-import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import android.annotation.NonNull;
@@ -1195,7 +1195,23 @@ class ActivityStarter {
}
}
- mService.onStartActivitySetDidAppSwitch();
+ if (mService.getBalAppSwitchesProtectionEnabled()) {
+ // Only allow app switching to be resumed if activity is not a restricted background
+ // activity and target app is not home process, otherwise any background activity
+ // started in background task can stop home button protection mode.
+ // As the targeted app is not a home process and we don't need to wait for the 2nd
+ // activity to be started to resume app switching, we can just enable app switching
+ // directly.
+ WindowProcessController homeProcess = mService.mHomeProcess;
+ boolean isHomeProcess = homeProcess != null
+ && aInfo.applicationInfo.uid == homeProcess.mUid;
+ if (!restrictedBgActivity && !isHomeProcess) {
+ mService.resumeAppSwitches();
+ }
+ } else {
+ mService.onStartActivitySetDidAppSwitch();
+ }
+
mController.doPendingActivityLaunches(false);
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
@@ -1260,6 +1276,20 @@ class ActivityStarter {
return false;
}
+ // Always allow home application to start activities.
+ if (mService.mHomeProcess != null && callingUid == mService.mHomeProcess.mUid) {
+ if (DEBUG_ACTIVITY_STARTS) {
+ Slog.d(TAG, "Activity start allowed for home app callingUid (" + callingUid + ")");
+ }
+ return false;
+ }
+
+ // App switching will be allowed if BAL app switching flag is not enabled, or if
+ // its app switching rule allows it.
+ // This is used to block background activity launch even if the app is still
+ // visible to user after user clicking home button.
+ final boolean appSwitchAllowed = mService.getBalAppSwitchesAllowed();
+
// don't abort if the callingUid has a visible window or is a persistent system process
final int callingUidProcState = mService.getUidState(callingUid);
final boolean callingUidHasAnyVisibleWindow =
@@ -1269,7 +1299,8 @@ class ActivityStarter {
|| callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
final boolean isCallingUidPersistentSystemProcess =
callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
- if (callingUidHasAnyVisibleWindow || isCallingUidPersistentSystemProcess) {
+ if ((appSwitchAllowed && callingUidHasAnyVisibleWindow)
+ || isCallingUidPersistentSystemProcess) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Activity start allowed: callingUidHasAnyVisibleWindow = " + callingUid
+ ", isCallingUidPersistentSystemProcess = "
@@ -1295,6 +1326,7 @@ class ActivityStarter {
|| realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
if (realCallingUid != callingUid) {
// don't abort if the realCallingUid has a visible window
+ // TODO(b/171459802): We should check appSwitchAllowed also
if (realCallingUidHasAnyVisibleWindow) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
@@ -1376,7 +1408,7 @@ class ActivityStarter {
// don't abort if the callerApp or other processes of that uid are allowed in any way
if (callerApp != null) {
// first check the original calling process
- if (callerApp.areBackgroundActivityStartsAllowed()) {
+ if (callerApp.areBackgroundActivityStartsAllowed(appSwitchAllowed)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "Background activity start allowed: callerApp process (pid = "
+ callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed");
@@ -1389,7 +1421,8 @@ class ActivityStarter {
if (uidProcesses != null) {
for (int i = uidProcesses.size() - 1; i >= 0; i--) {
final WindowProcessController proc = uidProcesses.valueAt(i);
- if (proc != callerApp && proc.areBackgroundActivityStartsAllowed()) {
+ if (proc != callerApp
+ && proc.areBackgroundActivityStartsAllowed(appSwitchAllowed)) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG,
"Background activity start allowed: process " + proc.getPid()
@@ -1403,6 +1436,8 @@ class ActivityStarter {
// anything that has fallen through would currently be aborted
Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
+ "; callingUid: " + callingUid
+ + "; appSwitchAllowed: " + appSwitchAllowed
+ + "; balAppSwitchEnabled: " + mService.getBalAppSwitchesProtectionEnabled()
+ "; isCallingUidForeground: " + isCallingUidForeground
+ "; callingUidHasAnyVisibleWindow: " + callingUidHasAnyVisibleWindow
+ "; callingUidProcState: " + DebugUtils.valueToString(ActivityManager.class,
@@ -1665,11 +1700,6 @@ class ActivityStarter {
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
setNewTask(taskToAffiliate);
- if (mService.getLockTaskController().isLockTaskModeViolation(
- mStartActivity.getTask())) {
- Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
- return START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
} else if (mAddingToTask) {
addOrReparentStartingActivity(targetTask, "adding to task");
}
@@ -1836,7 +1866,14 @@ class ActivityStarter {
}
}
- if (mRestrictedBgActivity && (newTask || !targetTask.isUidPresent(mCallingUid))
+ // Do not allow background activity start in new task or in a task that uid is not present.
+ // Also do not allow pinned window to start single instance activity in background,
+ // as it will recreate the window and makes it to foreground.
+ boolean blockBalInTask = (newTask
+ || !targetTask.isUidPresent(mCallingUid)
+ || (LAUNCH_SINGLE_INSTANCE == mLaunchMode && targetTask.inPinnedWindowingMode()));
+
+ if (mRestrictedBgActivity && blockBalInTask
&& handleBackgroundActivityAbort(mStartActivity)) {
Slog.e(TAG, "Abort background activity starts from " + mCallingUid);
return START_ABORTED;
@@ -1848,10 +1885,17 @@ class ActivityStarter {
final boolean isNewClearTask =
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
- if (!newTask && mService.getLockTaskController().isLockTaskModeViolation(targetTask,
- isNewClearTask)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
- return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ if (!newTask) {
+ if (mService.getLockTaskController().isLockTaskModeViolation(targetTask,
+ isNewClearTask)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+ } else {
+ if (mService.getLockTaskController().isNewTaskLockTaskModeViolation(mStartActivity)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
}
return START_SUCCESS;
@@ -2530,8 +2574,8 @@ class ActivityStarter {
"bringingFoundTaskToFront");
mMovedToFront = !isSplitScreenTopStack;
} else {
- intentTask.reparent(launchStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE,
- DEFER_RESUME, "reparentToTargetStack");
+ intentTask.reparent(launchStack, ON_TOP, REPARENT_MOVE_ROOT_TASK_TO_FRONT,
+ ANIMATE, DEFER_RESUME, "reparentToTargetStack");
mMovedToFront = true;
}
mOptions = null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
index b5675a903144..33d1b44b9743 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerDebugConfig.java
@@ -45,7 +45,7 @@ public class ActivityTaskManagerDebugConfig {
static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
static final boolean DEBUG_RECENTS_TRIM_TASKS = DEBUG_RECENTS || false;
- static final boolean DEBUG_STACK = DEBUG_ALL || false;
+ static final boolean DEBUG_ROOT_TASK = DEBUG_ALL || false;
public static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
@@ -73,7 +73,7 @@ public class ActivityTaskManagerDebugConfig {
static final String POSTFIX_PAUSE = APPEND_CATEGORY_NAME ? "_Pause" : "";
static final String POSTFIX_RECENTS = APPEND_CATEGORY_NAME ? "_Recents" : "";
static final String POSTFIX_SAVED_STATE = APPEND_CATEGORY_NAME ? "_SavedState" : "";
- static final String POSTFIX_STACK = APPEND_CATEGORY_NAME ? "_Stack" : "";
+ static final String POSTFIX_ROOT_TASK = APPEND_CATEGORY_NAME ? "_RootTask" : "";
static final String POSTFIX_STATES = APPEND_CATEGORY_NAME ? "_States" : "";
public static final String POSTFIX_SWITCH = APPEND_CATEGORY_NAME ? "_Switch" : "";
static final String POSTFIX_TASKS = APPEND_CATEGORY_NAME ? "_Tasks" : "";
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 581b367aab32..2cbc5148a4e1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -106,7 +106,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFI
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_IMMERSIVE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
@@ -117,14 +117,14 @@ import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEI
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
import static com.android.server.wm.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG;
import static com.android.server.wm.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_ONLY;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_ONLY;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.Task.ActivityState.DESTROYED;
import static com.android.server.wm.Task.ActivityState.DESTROYING;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
+import static com.android.server.wm.Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
@@ -161,9 +161,11 @@ import android.app.WindowConfiguration;
import android.app.admin.DevicePolicyCache;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
+import android.app.compat.CompatChanges;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.EnterPipRequestedItem;
import android.app.usage.UsageStatsManagerInternal;
+import android.compat.annotation.ChangeId;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -214,6 +216,7 @@ import android.os.UserManager;
import android.os.WorkSource;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.dreams.DreamActivity;
import android.service.voice.IVoiceInteractionSession;
@@ -306,7 +309,7 @@ import java.util.Set;
*/
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityTaskManagerService" : TAG_ATM;
- static final String TAG_STACK = TAG + POSTFIX_STACK;
+ static final String TAG_ROOT_TASK = TAG + POSTFIX_ROOT_TASK;
static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
@@ -342,6 +345,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/** This activity is being relaunched due to a free-resize operation. */
public static final int RELAUNCH_REASON_FREE_RESIZE = 2;
+ /**
+ * Apps are blocked from starting activities in the foreground after the user presses home.
+ */
+ public static final String BLOCK_ACTIVITY_STARTS_AFTER_HOME_FLAG =
+ "am_block_activity_starts_after_home";
+
Context mContext;
/**
@@ -366,6 +375,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
PendingIntentController mPendingIntentController;
IntentFirewall mIntentFirewall;
+ final VisibleActivityProcessTracker mVisibleActivityProcessTracker;
+
/* Global service lock used by the package the owns this service. */
final WindowManagerGlobalLock mGlobalLock = new WindowManagerGlobalLock();
/**
@@ -394,6 +405,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
volatile WindowProcessController mHeavyWeightProcess;
boolean mHasHeavyWeightFeature;
boolean mHasLeanbackFeature;
+ boolean mBlockActivityAfterHomeEnabled;
/** The process of the top most activity. */
volatile WindowProcessController mTopApp;
/**
@@ -741,6 +753,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mSystemThread = ActivityThread.currentActivityThread();
mUiContext = mSystemThread.getSystemUiContext();
mLifecycleManager = new ClientLifecycleManager();
+ mVisibleActivityProcessTracker = new VisibleActivityProcessTracker(this);
mInternal = new LocalService();
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED);
mWindowOrganizerController = new WindowOrganizerController(this);
@@ -756,6 +769,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mVrController.onSystemReady();
mRecentTasks.onSystemReadyLocked();
mStackSupervisor.onSystemReady();
+ mBlockActivityAfterHomeEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ BLOCK_ACTIVITY_STARTS_AFTER_HOME_FLAG, false);
}
}
@@ -2228,7 +2244,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
return;
}
@@ -2266,7 +2282,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final long ident = Binder.clearCallingIdentity();
try {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "removeTask: No task remove with id=" + taskId);
return false;
@@ -2374,7 +2390,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found");
return rect;
@@ -2397,7 +2413,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
enforceCallerIsRecentsOrHasPermission(
MANAGE_ACTIVITY_TASKS, "getTaskDescription()");
final Task tr = mRootWindowContainer.anyTaskForId(id,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (tr != null) {
return tr.getTaskDescription();
}
@@ -2418,7 +2434,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return setTaskWindowingModeSplitScreen(taskId, windowingMode, toTop);
}
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
Slog.w(TAG, "setTaskWindowingMode: No task for id=" + taskId);
return false;
@@ -2444,7 +2460,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
} else {
stack.setWindowingMode(windowingMode);
stack.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
- true /* notifyClients */);
+ true /* notifyClients */, mStackSupervisor.mUserLeaving);
}
return true;
} finally {
@@ -2627,8 +2643,35 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
throw new SecurityException(msg);
}
+ /**
+ * Return true if app switch protection will be handled by background activity launch logic.
+ */
+ boolean getBalAppSwitchesProtectionEnabled() {
+ return mBlockActivityAfterHomeEnabled;
+ }
+
+ /**
+ * Return true if app switching is allowed.
+ */
+ boolean getBalAppSwitchesAllowed() {
+ if (getBalAppSwitchesProtectionEnabled()) {
+ // Apps no longer able to start BAL again until app switching is resumed.
+ return mAppSwitchesAllowedTime == 0;
+ } else {
+ // Legacy behavior, BAL logic won't block app switching.
+ return true;
+ }
+ }
+
boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid,
int callingPid, int callingUid, String name) {
+
+ // Background activity launch logic replaces app switching protection, so allow
+ // apps to start activity here now.
+ if (getBalAppSwitchesProtectionEnabled()) {
+ return true;
+ }
+
if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
return true;
}
@@ -2789,8 +2832,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
throw new IllegalArgumentException("moveTaskToRootTask: Attempt to move task "
+ taskId + " to rootTask " + rootTaskId);
}
- task.reparent(rootTask, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME,
- "moveTaskToRootTask");
+ task.reparent(rootTask, toTop, REPARENT_KEEP_ROOT_TASK_AT_FRONT, ANIMATE,
+ !DEFER_RESUME, "moveTaskToRootTask");
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2834,7 +2877,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
Slog.w(TAG, "setTaskWindowingModeSplitScreenPrimary: No task for id=" + taskId);
return false;
@@ -3013,7 +3056,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
return;
}
@@ -3361,7 +3404,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public void setTaskResizeable(int taskId, int resizeableMode) {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(
- taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ taskId, MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
return;
@@ -3377,7 +3420,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
return false;
@@ -4395,7 +4438,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_ONLY);
+ MATCH_ATTACHED_TASK_ONLY);
if (task == null) {
Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found");
return;
@@ -4423,7 +4466,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final Task task;
synchronized (mGlobalLock) {
task = mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found");
return null;
@@ -4663,7 +4706,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mAppSwitchesAllowedTime = SystemClock.uptimeMillis() + APP_SWITCH_DELAY_TIME;
mLastStopAppSwitchesTime = SystemClock.uptimeMillis();
mDidAppSwitch = false;
- getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
+ // If BAL app switching enabled, app switches are blocked not delayed.
+ if (!getBalAppSwitchesProtectionEnabled()) {
+ getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME);
+ }
}
}
@@ -6103,16 +6149,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public boolean hasResumedActivity(int uid) {
- synchronized (mGlobalLock) {
- final ArraySet<WindowProcessController> processes = mProcessMap.getProcesses(uid);
- for (int i = 0, n = processes.size(); i < n; i++) {
- final WindowProcessController process = processes.valueAt(i);
- if (process.hasResumedActivity()) {
- return true;
- }
- }
- }
- return false;
+ return mVisibleActivityProcessTracker.hasResumedActivity(uid);
}
public void setBackgroundActivityStartCallback(
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 3e798790f45e..fbbda59d6ce3 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -17,7 +17,7 @@
package com.android.server.wm;
import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import android.app.ActivityManager;
import android.app.IAppTask;
@@ -79,7 +79,7 @@ class AppTaskImpl extends IAppTask.Stub {
final long origId = Binder.clearCallingIdentity();
try {
Task task = mService.mRootWindowContainer.anyTaskForId(mTaskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
@@ -136,7 +136,7 @@ class AppTaskImpl extends IAppTask.Stub {
IApplicationThread appThread;
synchronized (mService.mGlobalLock) {
task = mService.mRootWindowContainer.anyTaskForId(mTaskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
@@ -165,7 +165,7 @@ class AppTaskImpl extends IAppTask.Stub {
final long origId = Binder.clearCallingIdentity();
try {
Task task = mService.mRootWindowContainer.anyTaskForId(mTaskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
if (task == null) {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 97912c1965ac..c87f3da7a4a5 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -575,7 +575,7 @@ public class AppTransitionController {
app.allDrawn = true;
// Ensure that apps that are mid-starting are also scheduled to have their
// starting windows removed after the animation is complete
- if (app.startingWindow != null && !app.startingWindow.mAnimatingExit) {
+ if (app.mStartingWindow != null && !app.mStartingWindow.mAnimatingExit) {
app.removeStartingWindow();
}
@@ -651,7 +651,7 @@ public class AppTransitionController {
+ "startingMoved=%b isRelaunching()=%b startingWindow=%s",
activity, activity.allDrawn, activity.startingDisplayed,
activity.startingMoved, activity.isRelaunching(),
- activity.startingWindow);
+ activity.mStartingWindow);
final boolean allDrawn = activity.allDrawn && !activity.isRelaunching();
@@ -760,7 +760,7 @@ public class AppTransitionController {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"New transit away from wallpaper: %s",
AppTransition.appTransitionOldToString(transit));
- } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
+ } else if (wallpaperTarget != null && wallpaperTarget.isVisible()
&& openingApps.contains(wallpaperTarget.mActivityRecord)
&& topOpeningApp == wallpaperTarget.mActivityRecord
&& transit != TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE) {
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index ce20dbdb2997..8ad2958f9a76 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -33,6 +33,7 @@ import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA;
import android.annotation.Nullable;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.IBinder;
import android.util.proto.ProtoOutputStream;
import android.window.DisplayAreaInfo;
import android.window.IDisplayAreaOrganizer;
@@ -149,6 +150,15 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
return !mIgnoreOrientationRequest && super.handlesOrientationChangeFromDescendant();
}
+ @Override
+ boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
+ WindowContainer requestingContainer) {
+ // If this is set to ignore the orientation request, we don't propagate descendant
+ // orientation request.
+ return !mIgnoreOrientationRequest
+ && super.onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
+ }
+
/**
* Sets whether this {@link DisplayArea} should ignore fixed-orientation request from apps and
* windows below it.
diff --git a/services/core/java/com/android/server/wm/DisplayAreaGroup.java b/services/core/java/com/android/server/wm/DisplayAreaGroup.java
index bcf8c7c901af..8488314d8da5 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaGroup.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaGroup.java
@@ -17,8 +17,12 @@
package com.android.server.wm;
import static android.content.pm.ActivityInfo.reverseOrientation;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.graphics.Rect;
/** The root of a partition of the logical display. */
@@ -30,13 +34,19 @@ class DisplayAreaGroup extends RootDisplayArea {
@Override
boolean isOrientationDifferentFromDisplay() {
+ return isOrientationDifferentFromDisplay(getBounds());
+ }
+
+ /**
+ * Whether the orientation should be different from the {@link DisplayContent}.
+ * @param bounds the bounds of this DAG.
+ */
+ private boolean isOrientationDifferentFromDisplay(Rect bounds) {
if (mDisplayContent == null) {
return false;
}
- final Rect bounds = getBounds();
final Rect displayBounds = mDisplayContent.getBounds();
-
return (bounds.width() < bounds.height())
!= (displayBounds.width() < displayBounds.height());
}
@@ -54,4 +64,34 @@ class DisplayAreaGroup extends RootDisplayArea {
// display to be portrait, so that the DAG and the app will be in landscape.
return isOrientationDifferentFromDisplay() ? reverseOrientation(orientation) : orientation;
}
+
+ @Override
+ void resolveOverrideConfiguration(Configuration newParentConfiguration) {
+ super.resolveOverrideConfiguration(newParentConfiguration);
+ final Configuration resolvedConfig = getResolvedOverrideConfiguration();
+ if (resolvedConfig.orientation != ORIENTATION_UNDEFINED) {
+ // Don't change the orientation if it is requested on this window.
+ return;
+ }
+
+ // Use the override bounds because getBounds() may not be merged yet.
+ Rect overrideBounds = resolvedConfig.windowConfiguration.getBounds();
+ // It should fill parent if there is no override bounds.
+ overrideBounds = overrideBounds.isEmpty()
+ ? newParentConfiguration.windowConfiguration.getBounds()
+ : overrideBounds;
+ // Resolve the DAG orientation:
+ // If the orientation of this DAG should always be different from the display based on their
+ // dimensions, we need to reverse the config orientation.
+ // For example, if the display is 1200x900 (landscape), and this DAG is 600x900 (portrait).
+ // The orientation from the Display will be landscape, but we want to reverse it to be
+ // portrait for the DAG and its children.
+ if (isOrientationDifferentFromDisplay(overrideBounds)) {
+ if (newParentConfiguration.orientation == ORIENTATION_PORTRAIT) {
+ resolvedConfig.orientation = ORIENTATION_LANDSCAPE;
+ } else if (newParentConfiguration.orientation == ORIENTATION_LANDSCAPE) {
+ resolvedConfig.orientation = ORIENTATION_PORTRAIT;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index be18d0a9a6df..76a5cda9299e 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -22,8 +22,11 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import static android.window.DisplayAreaOrganizer.FEATURE_FULLSCREEN_MAGNIFICATION;
+import static android.window.DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT;
import static android.window.DisplayAreaOrganizer.FEATURE_ONE_HANDED;
import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
@@ -99,6 +102,12 @@ public abstract class DisplayAreaPolicy {
// layer
.setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
.build())
+ .addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",
+ FEATURE_HIDE_DISPLAY_CUTOUT)
+ .all()
+ .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,
+ TYPE_NOTIFICATION_SHADE)
+ .build())
.addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
FEATURE_ONE_HANDED)
.all()
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6453ddf80faa..07c61d3dcea5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -88,7 +88,6 @@ import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_A
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
import static com.android.server.wm.DisplayContentProto.CAN_SHOW_IME;
import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
@@ -238,7 +237,6 @@ import java.util.function.Predicate;
*/
class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;
- private static final String TAG_STACK = TAG + POSTFIX_STACK;
/** The default scaling mode that scales content automatically. */
static final int FORCE_SCALING_MODE_AUTO = 0;
@@ -864,7 +862,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- if (obscuredChanged && w.isVisibleLw() && mWallpaperController.isWallpaperTarget(w)) {
+ if (obscuredChanged && w.isVisible() && mWallpaperController.isWallpaperTarget(w)) {
// This is the wallpaper target and its obscured state changed... make sure the
// current wallpaper's visibility has been updated accordingly.
mWallpaperController.updateWallpaperVisibility();
@@ -1430,8 +1428,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM) {
return ROTATION_UNDEFINED;
}
- if (r.inMultiWindowMode()
- || r.getRequestedConfigurationOrientation() == getConfiguration().orientation) {
+ if (r.inMultiWindowMode() || r.getRequestedConfigurationOrientation(true /* forDisplay */)
+ == getConfiguration().orientation) {
return ROTATION_UNDEFINED;
}
final int currentRotation = getRotation();
@@ -2586,7 +2584,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return;
}
- if (w.isOnScreen() && w.isVisibleLw() && w.getFrame().contains(x, y)) {
+ if (w.isOnScreen() && w.isVisible() && w.getFrame().contains(x, y)) {
targetWindowType[0] = w.mAttrs.type;
return;
}
@@ -2631,7 +2629,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION);
}
}
- if (mInputMethodWindow != null && mInputMethodWindow.isVisibleLw()) {
+ if (mInputMethodWindow != null && mInputMethodWindow.isVisible()) {
// If the input method is visible and the user is typing, we don't want these touch
// events to be intercepted and used to change focus. This would likely cause a
// disappearance of the input method.
@@ -2640,7 +2638,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) {
final WindowState win = mTapExcludedWindows.get(i);
- if (!win.isVisibleLw()) {
+ if (!win.isVisible()) {
continue;
}
win.getTouchableRegion(mTmpRegion);
@@ -2783,7 +2781,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void adjustForImeIfNeeded() {
final WindowState imeWin = mInputMethodWindow;
- final boolean imeVisible = imeWin != null && imeWin.isVisibleLw()
+ final boolean imeVisible = imeWin != null && imeWin.isVisible()
&& imeWin.isDisplayed();
final int imeHeight = mDisplayFrames.getInputMethodWindowVisibleHeight();
mPinnedStackControllerLocked.setAdjustedForIme(imeVisible, imeHeight);
@@ -3070,7 +3068,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final int y = (int) yf;
final WindowState touchedWin = getWindow(w -> {
final int flags = w.mAttrs.flags;
- if (!w.isVisibleLw()) {
+ if (!w.isVisible()) {
return false;
}
if ((flags & FLAG_NOT_TOUCHABLE) != 0) {
@@ -5310,7 +5308,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients) {
+ boolean preserveWindows, boolean notifyClients, boolean userLeaving) {
if (mInEnsureActivitiesVisible) {
// Don't do recursive work.
return;
@@ -5319,7 +5317,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
try {
forAllTaskDisplayAreas(taskDisplayArea -> {
taskDisplayArea.ensureActivitiesVisible(starting, configChanges,
- preserveWindows, notifyClients);
+ preserveWindows, notifyClients, userLeaving);
});
} finally {
mInEnsureActivitiesVisible = false;
@@ -5496,7 +5494,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
boolean isTopFixedOrientationRecentsAnimating() {
return mAnimatingRecents != null
- && mAnimatingRecents.getRequestedConfigurationOrientation()
+ && mAnimatingRecents.getRequestedConfigurationOrientation(true /* forDisplay */)
!= ORIENTATION_UNDEFINED && !hasTopFixedRotationLaunchingApp();
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 7a42b0db0c52..61cc4306409d 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1153,15 +1153,19 @@ public class DisplayPolicy {
});
mDisplayContent.setInsetProvider(ITYPE_LEFT_GESTURES, win,
(displayFrames, windowState, inOutFrame) -> {
+ final int leftSafeInset =
+ Math.max(displayFrames.mDisplayCutoutSafe.left, 0);
inOutFrame.left = 0;
inOutFrame.top = 0;
inOutFrame.bottom = displayFrames.mDisplayHeight;
- inOutFrame.right = displayFrames.mUnrestricted.left + mLeftGestureInset;
+ inOutFrame.right = leftSafeInset + mLeftGestureInset;
});
mDisplayContent.setInsetProvider(ITYPE_RIGHT_GESTURES, win,
(displayFrames, windowState, inOutFrame) -> {
- inOutFrame.left = displayFrames.mUnrestricted.right
- - mRightGestureInset;
+ final int rightSafeInset =
+ Math.min(displayFrames.mDisplayCutoutSafe.right,
+ displayFrames.mUnrestricted.right);
+ inOutFrame.left = rightSafeInset - mRightGestureInset;
inOutFrame.top = 0;
inOutFrame.bottom = displayFrames.mDisplayHeight;
inOutFrame.right = displayFrames.mDisplayWidth;
@@ -1718,7 +1722,7 @@ public class DisplayPolicy {
for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
final WindowState w = mScreenDecorWindows.valueAt(i);
- if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
+ if (w.getDisplayId() != displayId || !w.isVisible()) {
// Skip if not on the same display or not visible.
continue;
}
@@ -1824,7 +1828,7 @@ public class DisplayPolicy {
boolean statusBarTranslucent = (appearance & APPEARANCE_OPAQUE_STATUS_BARS) == 0;
// If the status bar is hidden, we don't want to cause windows behind it to scroll.
- if (mStatusBar.isVisibleLw() && !statusBarTransient) {
+ if (mStatusBar.isVisible() && !statusBarTransient) {
// Status bar may go away, so the screen area it occupies is available to apps but just
// covering them when the status bar is visible.
final Rect dockFrame = displayFrames.mDock;
@@ -2143,10 +2147,10 @@ public class DisplayPolicy {
win.computeFrame(displayFrames);
// Dock windows carve out the bottom of the screen, so normal windows
// can't appear underneath them.
- if (type == TYPE_INPUT_METHOD && win.isVisibleLw() && !win.mGivenInsetsPending) {
+ if (type == TYPE_INPUT_METHOD && win.isVisible() && !win.mGivenInsetsPending) {
offsetInputMethodWindowLw(win, displayFrames);
}
- if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw() && !win.mGivenInsetsPending) {
+ if (type == TYPE_VOICE_INTERACTION && win.isVisible() && !win.mGivenInsetsPending) {
offsetVoiceInputWindowLw(win, displayFrames);
}
}
@@ -2219,7 +2223,7 @@ public class DisplayPolicy {
WindowState attached, WindowState imeTarget) {
final boolean affectsSystemUi = win.canAffectSystemUiFlags();
if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
- mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
+ applyKeyguardPolicy(win, imeTarget);
final int fl = attrs.flags;
if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
&& attrs.type == TYPE_INPUT_METHOD) {
@@ -2240,7 +2244,7 @@ public class DisplayPolicy {
if (win.isDreamWindow()) {
// If the lockscreen was showing when the dream started then wait
// for the dream to draw before hiding the lockscreen.
- if (!mDreamingLockscreen || (win.isVisibleLw() && win.hasDrawn())) {
+ if (!mDreamingLockscreen || (win.isVisible() && win.hasDrawn())) {
mShowingDream = true;
appWindow = true;
}
@@ -2387,6 +2391,55 @@ public class DisplayPolicy {
}
/**
+ * Applies the keyguard policy to a specific window.
+ *
+ * @param win The window to apply the keyguard policy.
+ * @param imeTarget The current IME target window.
+ */
+ private void applyKeyguardPolicy(WindowState win, WindowState imeTarget) {
+ if (mService.mPolicy.canBeHiddenByKeyguardLw(win)) {
+ if (shouldBeHiddenByKeyguard(win, imeTarget)) {
+ win.hide(false /* doAnimation */, true /* requestAnim */);
+ } else {
+ win.show(false /* doAnimation */, true /* requestAnim */);
+ }
+ }
+ }
+
+ private boolean shouldBeHiddenByKeyguard(WindowState win, WindowState imeTarget) {
+ // If AOD is showing, the IME should be hidden. However, sometimes the AOD is considered
+ // hidden because it's in the process of hiding, but it's still being shown on screen.
+ // In that case, we want to continue hiding the IME until the windows have completed
+ // drawing. This way, we know that the IME can be safely shown since the other windows are
+ // now shown.
+ final boolean hideIme = win.mIsImWindow
+ && (mService.mAtmService.mKeyguardController.isAodShowing()
+ || (mDisplayContent.isDefaultDisplay && !mWindowManagerDrawComplete));
+ if (hideIme) {
+ return true;
+ }
+
+ if (!mDisplayContent.isDefaultDisplay || !isKeyguardShowing()) {
+ return false;
+ }
+
+ // Show IME over the keyguard if the target allows it.
+ final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisible()
+ && win.mIsImWindow && (imeTarget.canShowWhenLocked()
+ || !mService.mPolicy.canBeHiddenByKeyguardLw(imeTarget));
+ if (showImeOverKeyguard) {
+ return false;
+ }
+
+ // Show SHOW_WHEN_LOCKED windows if keyguard is occluded.
+ final boolean allowShowWhenLocked = isKeyguardOccluded()
+ // Show error dialogs over apps that are shown on keyguard.
+ && (win.canShowWhenLocked()
+ || (win.mAttrs.privateFlags & LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR) != 0);
+ return !allowShowWhenLocked;
+ }
+
+ /**
* @return Whether the top app should hide the statusbar based on the top fullscreen opaque
* window.
*/
@@ -2916,10 +2969,6 @@ public class DisplayPolicy {
mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
- final int fullscreenAppearance = updateLightStatusBarLw(0 /* appearance */,
- mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
- final int dockedAppearance = updateLightStatusBarLw(0 /* appearance */,
- mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
final boolean inSplitScreen =
mService.mRoot.getDefaultTaskDisplayArea().isSplitScreenModeActivated();
if (inSplitScreen) {
@@ -2931,6 +2980,12 @@ public class DisplayPolicy {
mService.getStackBounds(inSplitScreen ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
: WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_UNDEFINED, mNonDockedStackBounds);
+ final int fullscreenAppearance = updateLightStatusBarLw(0 /* appearance */,
+ mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
+ mNonDockedStackBounds);
+ final int dockedAppearance = updateLightStatusBarLw(0 /* appearance */,
+ mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState,
+ mDockedStackBounds);
final int disableFlags = win.getSystemUiVisibility() & StatusBarManager.DISABLE_MASK;
final int opaqueAppearance = updateSystemBarsLw(win, disableFlags);
final WindowState navColorWin = chooseNavigationColorWindowLw(
@@ -2996,10 +3051,14 @@ public class DisplayPolicy {
}
private int updateLightStatusBarLw(@Appearance int appearance, WindowState opaque,
- WindowState opaqueOrDimming) {
+ WindowState opaqueOrDimming, Rect stackBounds) {
+ final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
+ final int statusBarHeight = mStatusBarHeightForRotation[displayRotation.getRotation()];
+ final boolean stackBoundsContainStatusBar =
+ stackBounds.isEmpty() ? false : stackBounds.top < statusBarHeight;
final boolean onKeyguard = isKeyguardShowing() && !isKeyguardOccluded();
final WindowState statusColorWin = onKeyguard ? mNotificationShade : opaqueOrDimming;
- if (statusColorWin != null) {
+ if (stackBoundsContainStatusBar && statusColorWin != null) {
if (statusColorWin == opaque || onKeyguard) {
// If the top fullscreen-or-dimming window is also the top fullscreen, respect
// its light flag.
@@ -3025,7 +3084,7 @@ public class DisplayPolicy {
// If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
// window can be navigation color window.
final boolean imeWindowCanNavColorWindow = imeWindow != null
- && imeWindow.isVisibleLw()
+ && imeWindow.isVisible()
&& navBarPosition == NAV_BAR_BOTTOM
&& (imeWindow.mAttrs.flags
& WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
@@ -3294,8 +3353,8 @@ public class DisplayPolicy {
public void takeScreenshot(int screenshotType, int source) {
if (mScreenshotHelper != null) {
mScreenshotHelper.takeScreenshot(screenshotType,
- getStatusBar() != null && getStatusBar().isVisibleLw(),
- getNavigationBar() != null && getNavigationBar().isVisibleLw(),
+ getStatusBar() != null && getStatusBar().isVisible(),
+ getNavigationBar() != null && getNavigationBar().isVisible(),
source, mHandler, null /* completionConsumer */);
}
}
@@ -3464,8 +3523,8 @@ public class DisplayPolicy {
@VisibleForTesting
static boolean isOverlappingWithNavBar(WindowState targetWindow, WindowState navBarWindow) {
- if (navBarWindow == null || !navBarWindow.isVisibleLw()
- || targetWindow.mActivityRecord == null || !targetWindow.isVisibleLw()) {
+ if (navBarWindow == null || !navBarWindow.isVisible()
+ || targetWindow.mActivityRecord == null || !targetWindow.isVisible()) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index f647bea950f2..472678cf8e37 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -22,184 +22,41 @@ import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_AUTO;
import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_DISABLED;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
-import android.os.Environment;
-import android.os.FileUtils;
import android.provider.Settings;
-import android.util.AtomicFile;
-import android.util.Slog;
-import android.util.Xml;
import android.view.Display;
-import android.view.DisplayAddress;
import android.view.DisplayInfo;
import android.view.IWindowManager;
import android.view.Surface;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.XmlUtils;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.DisplayContent.ForceScalingMode;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
+import java.util.Objects;
/**
- * Current persistent settings about a display
+ * Current persistent settings about a display. Provides policies for display settings and
+ * delegates the persistence and lookup of settings values to the supplied {@link SettingsProvider}.
*/
class DisplayWindowSettings {
- private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayWindowSettings" : TAG_WM;
-
- private static final String SYSTEM_DIRECTORY = "system";
- private static final String DISPLAY_SETTINGS_FILE_NAME = "display_settings.xml";
- private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/" + DISPLAY_SETTINGS_FILE_NAME;
- private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays";
-
- private static final int IDENTIFIER_UNIQUE_ID = 0;
- private static final int IDENTIFIER_PORT = 1;
- @IntDef(prefix = { "IDENTIFIER_" }, value = {
- IDENTIFIER_UNIQUE_ID,
- IDENTIFIER_PORT,
- })
- @interface DisplayIdentifierType {}
-
private final WindowManagerService mService;
- private final HashMap<String, Entry> mEntries = new HashMap<>();
- private final SettingPersister mStorage;
-
- /**
- * The preferred type of a display identifier to use when storing and retrieving entries.
- * {@link #getIdentifier(DisplayInfo)} must be used to get current preferred identifier for each
- * display. It will fall back to using {@link #IDENTIFIER_UNIQUE_ID} if the currently selected
- * one is not applicable to a particular display.
- */
- @DisplayIdentifierType
- private int mIdentifier = IDENTIFIER_UNIQUE_ID;
-
- /** Interface for persisting the display window settings. */
- interface SettingPersister {
- InputStream openRead() throws IOException;
- OutputStream startWrite() throws IOException;
- void finishWrite(OutputStream os, boolean success);
- }
-
- private static class Entry {
- private final String mName;
- private int mWindowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
- private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
- private int mUserRotation = Surface.ROTATION_0;
- private int mForcedWidth;
- private int mForcedHeight;
- private int mForcedDensity;
- private int mForcedScalingMode = FORCE_SCALING_MODE_AUTO;
- private int mRemoveContentMode = REMOVE_CONTENT_MODE_UNDEFINED;
- private boolean mShouldShowWithInsecureKeyguard = false;
- private boolean mShouldShowSystemDecors = false;
- private boolean mShouldShowIme = false;
- private int mFixedToUserRotation = IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
- private boolean mIgnoreOrientationRequest = false;
-
- private Entry(String name) {
- mName = name;
- }
-
- private Entry(String name, Entry copyFrom) {
- this(name);
- mWindowingMode = copyFrom.mWindowingMode;
- mUserRotationMode = copyFrom.mUserRotationMode;
- mUserRotation = copyFrom.mUserRotation;
- mForcedWidth = copyFrom.mForcedWidth;
- mForcedHeight = copyFrom.mForcedHeight;
- mForcedDensity = copyFrom.mForcedDensity;
- mForcedScalingMode = copyFrom.mForcedScalingMode;
- mRemoveContentMode = copyFrom.mRemoveContentMode;
- mShouldShowWithInsecureKeyguard = copyFrom.mShouldShowWithInsecureKeyguard;
- mShouldShowSystemDecors = copyFrom.mShouldShowSystemDecors;
- mShouldShowIme = copyFrom.mShouldShowIme;
- mFixedToUserRotation = copyFrom.mFixedToUserRotation;
- mIgnoreOrientationRequest = copyFrom.mIgnoreOrientationRequest;
- }
-
- /** @return {@code true} if all values are default. */
- private boolean isEmpty() {
- return mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
- && mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
- && mUserRotation == Surface.ROTATION_0
- && mForcedWidth == 0 && mForcedHeight == 0 && mForcedDensity == 0
- && mForcedScalingMode == FORCE_SCALING_MODE_AUTO
- && mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED
- && !mShouldShowWithInsecureKeyguard
- && !mShouldShowSystemDecors
- && !mShouldShowIme
- && mFixedToUserRotation == IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT
- && !mIgnoreOrientationRequest;
- }
- }
-
- DisplayWindowSettings(WindowManagerService service) {
- this(service, new AtomicFileStorage());
- }
+ private final SettingsProvider mSettingsProvider;
- @VisibleForTesting
- DisplayWindowSettings(WindowManagerService service, SettingPersister storageImpl) {
+ DisplayWindowSettings(WindowManagerService service, SettingsProvider settingsProvider) {
mService = service;
- mStorage = storageImpl;
- readSettings();
- }
-
- private @Nullable Entry getEntry(DisplayInfo displayInfo) {
- final String identifier = getIdentifier(displayInfo);
- Entry entry;
- // Try to get corresponding entry using preferred identifier for the current config.
- if ((entry = mEntries.get(identifier)) != null) {
- return entry;
- }
- // Else, fall back to the display name.
- if ((entry = mEntries.get(displayInfo.name)) != null) {
- // Found an entry stored with old identifier - upgrade to the new type now.
- return updateIdentifierForEntry(entry, displayInfo);
- }
- return null;
- }
-
- private Entry getOrCreateEntry(DisplayInfo displayInfo) {
- final Entry entry = getEntry(displayInfo);
- return entry != null ? entry : new Entry(getIdentifier(displayInfo));
- }
-
- /**
- * Upgrades the identifier of a legacy entry. Does it by copying the data from the old record
- * and clearing the old key in memory. The entry will be written to storage next time when a
- * setting changes.
- */
- private Entry updateIdentifierForEntry(Entry entry, DisplayInfo displayInfo) {
- final Entry newEntry = new Entry(getIdentifier(displayInfo), entry);
- removeEntry(displayInfo);
- mEntries.put(newEntry.mName, newEntry);
- return newEntry;
+ mSettingsProvider = settingsProvider;
}
void setUserRotation(DisplayContent displayContent, int rotationMode, int rotation) {
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mUserRotationMode = rotationMode;
- entry.mUserRotation = rotation;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mUserRotationMode = rotationMode;
+ overrideSettings.mUserRotation = rotation;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void setForcedSize(DisplayContent displayContent, int width, int height) {
@@ -207,14 +64,14 @@ class DisplayWindowSettings {
final String sizeString = (width == 0 || height == 0) ? "" : (width + "," + height);
Settings.Global.putString(mService.mContext.getContentResolver(),
Settings.Global.DISPLAY_SIZE_FORCED, sizeString);
- return;
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mForcedWidth = width;
- entry.mForcedHeight = height;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mForcedWidth = width;
+ overrideSettings.mForcedHeight = height;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void setForcedDensity(DisplayContent displayContent, int density, int userId) {
@@ -222,47 +79,47 @@ class DisplayWindowSettings {
final String densityString = density == 0 ? "" : Integer.toString(density);
Settings.Secure.putStringForUser(mService.mContext.getContentResolver(),
Settings.Secure.DISPLAY_DENSITY_FORCED, densityString, userId);
- return;
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mForcedDensity = density;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mForcedDensity = density;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void setForcedScalingMode(DisplayContent displayContent, @ForceScalingMode int mode) {
if (displayContent.isDefaultDisplay) {
Settings.Global.putInt(mService.mContext.getContentResolver(),
Settings.Global.DISPLAY_SCALING_FORCE, mode);
- return;
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mForcedScalingMode = mode;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mForcedScalingMode = mode;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void setFixedToUserRotation(DisplayContent displayContent, int fixedToUserRotation) {
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mFixedToUserRotation = fixedToUserRotation;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mFixedToUserRotation = fixedToUserRotation;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void setIgnoreOrientationRequest(
DisplayContent displayContent, boolean ignoreOrientationRequest) {
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- if (entry.mIgnoreOrientationRequest == ignoreOrientationRequest) return;
- entry.mIgnoreOrientationRequest = ignoreOrientationRequest;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mIgnoreOrientationRequest = ignoreOrientationRequest;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
- private int getWindowingModeLocked(Entry entry, DisplayContent dc) {
- int windowingMode = entry != null ? entry.mWindowingMode
- : WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+ private int getWindowingModeLocked(SettingsProvider.SettingsEntry settings, DisplayContent dc) {
+ int windowingMode = settings.mWindowingMode;
// This display used to be in freeform, but we don't support freeform anymore, so fall
// back to fullscreen.
if (windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
@@ -281,22 +138,23 @@ class DisplayWindowSettings {
int getWindowingModeLocked(DisplayContent dc) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getEntry(displayInfo);
- return getWindowingModeLocked(entry, dc);
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+ return getWindowingModeLocked(settings, dc);
}
void setWindowingModeLocked(DisplayContent dc, int mode) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mWindowingMode = mode;
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mWindowingMode = mode;
dc.setWindowingMode(mode);
- writeSettingsIfNeeded(entry, displayInfo);
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
int getRemoveContentModeLocked(DisplayContent dc) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getEntry(displayInfo);
- if (entry == null || entry.mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED) {
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+ if (settings.mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED) {
if (dc.isPrivate()) {
// For private displays by default content is destroyed on removal.
return REMOVE_CONTENT_MODE_DESTROY;
@@ -304,111 +162,110 @@ class DisplayWindowSettings {
// For other displays by default content is moved to primary on removal.
return REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
}
- return entry.mRemoveContentMode;
+ return settings.mRemoveContentMode;
}
void setRemoveContentModeLocked(DisplayContent dc, int mode) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mRemoveContentMode = mode;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mRemoveContentMode = mode;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
boolean shouldShowWithInsecureKeyguardLocked(DisplayContent dc) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getEntry(displayInfo);
- if (entry == null) {
- return false;
- }
- return entry.mShouldShowWithInsecureKeyguard;
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+ return settings.mShouldShowWithInsecureKeyguard != null
+ ? settings.mShouldShowWithInsecureKeyguard : false;
}
void setShouldShowWithInsecureKeyguardLocked(DisplayContent dc, boolean shouldShow) {
if (!dc.isPrivate() && shouldShow) {
- Slog.e(TAG, "Public display can't be allowed to show content when locked");
- return;
+ throw new IllegalArgumentException("Public display can't be allowed to show content"
+ + " when locked");
}
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mShouldShowWithInsecureKeyguard = shouldShow;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mShouldShowWithInsecureKeyguard = shouldShow;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
boolean shouldShowSystemDecorsLocked(DisplayContent dc) {
if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
- // For default display should show system decors.
+ // Default display should show system decors.
return true;
}
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getEntry(displayInfo);
- if (entry == null) {
- return false;
- }
- return entry.mShouldShowSystemDecors;
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+ return settings.mShouldShowSystemDecors != null ? settings.mShouldShowSystemDecors : false;
}
void setShouldShowSystemDecorsLocked(DisplayContent dc, boolean shouldShow) {
- if (dc.getDisplayId() == Display.DEFAULT_DISPLAY && !shouldShow) {
- Slog.e(TAG, "Default display should show system decors");
- return;
- }
-
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mShouldShowSystemDecors = shouldShow;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mShouldShowSystemDecors = shouldShow;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
boolean shouldShowImeLocked(DisplayContent dc) {
if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
- // For default display should shows IME.
+ // Default display should show IME.
return true;
}
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getEntry(displayInfo);
- if (entry == null) {
- return false;
- }
- return entry.mShouldShowIme;
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
+ return settings.mShouldShowIme != null ? settings.mShouldShowIme : false;
}
void setShouldShowImeLocked(DisplayContent dc, boolean shouldShow) {
- if (dc.getDisplayId() == Display.DEFAULT_DISPLAY && !shouldShow) {
- Slog.e(TAG, "Default display should show IME");
- return;
- }
-
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
- entry.mShouldShowIme = shouldShow;
- writeSettingsIfNeeded(entry, displayInfo);
+ final SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getOverrideSettings(displayInfo);
+ overrideSettings.mShouldShowIme = shouldShow;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
void applySettingsToDisplayLocked(DisplayContent dc) {
final DisplayInfo displayInfo = dc.getDisplayInfo();
- final Entry entry = getOrCreateEntry(displayInfo);
+ final SettingsProvider.SettingsEntry settings = mSettingsProvider.getSettings(displayInfo);
// Setting windowing mode first, because it may override overscan values later.
- dc.setWindowingMode(getWindowingModeLocked(entry, dc));
-
- dc.getDisplayRotation().restoreSettings(entry.mUserRotationMode,
- entry.mUserRotation, entry.mFixedToUserRotation);
-
- final boolean hasDensityOverride = entry.mForcedDensity != 0;
- final boolean hasSizeOverride = entry.mForcedWidth != 0 && entry.mForcedHeight != 0;
+ final int windowingMode = getWindowingModeLocked(settings, dc);
+ dc.setWindowingMode(windowingMode);
+
+ final int userRotationMode = settings.mUserRotationMode != null
+ ? settings.mUserRotationMode : WindowManagerPolicy.USER_ROTATION_FREE;
+ final int userRotation = settings.mUserRotation != null
+ ? settings.mUserRotation : Surface.ROTATION_0;
+ final int mFixedToUserRotation = settings.mFixedToUserRotation != null
+ ? settings.mFixedToUserRotation : IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
+ dc.getDisplayRotation().restoreSettings(userRotationMode, userRotation,
+ mFixedToUserRotation);
+
+ final boolean hasDensityOverride = settings.mForcedDensity != 0;
+ final boolean hasSizeOverride = settings.mForcedWidth != 0 && settings.mForcedHeight != 0;
dc.mIsDensityForced = hasDensityOverride;
dc.mIsSizeForced = hasSizeOverride;
- dc.setIgnoreOrientationRequest(entry.mIgnoreOrientationRequest);
- final int width = hasSizeOverride ? entry.mForcedWidth : dc.mBaseDisplayWidth;
- final int height = hasSizeOverride ? entry.mForcedHeight : dc.mBaseDisplayHeight;
- final int density = hasDensityOverride ? entry.mForcedDensity : dc.mBaseDisplayDensity;
+ final boolean ignoreOrientationRequest = settings.mIgnoreOrientationRequest != null
+ ? settings.mIgnoreOrientationRequest : false;
+ dc.setIgnoreOrientationRequest(ignoreOrientationRequest);
+
+ final int width = hasSizeOverride ? settings.mForcedWidth : dc.mInitialDisplayWidth;
+ final int height = hasSizeOverride ? settings.mForcedHeight : dc.mInitialDisplayHeight;
+ final int density = hasDensityOverride ? settings.mForcedDensity
+ : dc.mInitialDisplayDensity;
dc.updateBaseDisplayMetrics(width, height, density);
- dc.mDisplayScalingDisabled = entry.mForcedScalingMode == FORCE_SCALING_MODE_DISABLED;
+ final int forcedScalingMode = settings.mForcedScalingMode != null
+ ? settings.mForcedScalingMode : FORCE_SCALING_MODE_AUTO;
+ dc.mDisplayScalingDisabled = forcedScalingMode == FORCE_SCALING_MODE_DISABLED;
}
/**
@@ -429,291 +286,281 @@ class DisplayWindowSettings {
return false;
}
- private void readSettings() {
- InputStream stream;
- try {
- stream = mStorage.openRead();
- } catch (IOException e) {
- Slog.i(TAG, "No existing display settings, starting empty");
- return;
- }
- boolean success = false;
- try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- // Do nothing.
- }
-
- if (type != XmlPullParser.START_TAG) {
- throw new IllegalStateException("no start tag found");
+ /**
+ * Provides the functionality to lookup the {@link SettingsEntry settings} for a given
+ * {@link DisplayInfo}.
+ * <p>
+ * NOTE: All interactions with implementations of this provider <b>must</b> be thread-safe
+ * externally.
+ */
+ interface SettingsProvider {
+ /**
+ * Returns the {@link SettingsEntry} for a given {@link DisplayInfo}. The values for the
+ * returned settings are guaranteed to match those previously set with
+ * {@link #updateOverrideSettings(DisplayInfo, SettingsEntry)} with all other values left
+ * to the implementation to determine.
+ */
+ @NonNull
+ SettingsEntry getSettings(@NonNull DisplayInfo info);
+
+ /**
+ * Returns the existing override settings for the given {@link DisplayInfo}. All calls to
+ * {@link #getSettings(DisplayInfo)} for the provided {@code info} are required to have
+ * their values overridden with all set values from the returned {@link SettingsEntry}.
+ *
+ * @see #getSettings(DisplayInfo)
+ * @see #updateOverrideSettings(DisplayInfo, SettingsEntry)
+ */
+ @NonNull
+ SettingsEntry getOverrideSettings(@NonNull DisplayInfo info);
+
+ /**
+ * Updates the override settings for a given {@link DisplayInfo}. All subsequent calls to
+ * {@link #getSettings(DisplayInfo)} for the provided {@link DisplayInfo} are required to
+ * have their values match all set values in {@code overrides}.
+ *
+ * @see #getSettings(DisplayInfo)
+ */
+ void updateOverrideSettings(@NonNull DisplayInfo info, @NonNull SettingsEntry overrides);
+
+ /**
+ * Settings for a display.
+ */
+ class SettingsEntry {
+ int mWindowingMode = WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+ @Nullable
+ Integer mUserRotationMode;
+ @Nullable
+ Integer mUserRotation;
+ int mForcedWidth;
+ int mForcedHeight;
+ int mForcedDensity;
+ @Nullable
+ Integer mForcedScalingMode;
+ int mRemoveContentMode = REMOVE_CONTENT_MODE_UNDEFINED;
+ @Nullable
+ Boolean mShouldShowWithInsecureKeyguard;
+ @Nullable
+ Boolean mShouldShowSystemDecors;
+ @Nullable
+ Boolean mShouldShowIme;
+ @Nullable
+ Integer mFixedToUserRotation;
+ @Nullable
+ Boolean mIgnoreOrientationRequest;
+
+ SettingsEntry() {}
+
+ SettingsEntry(SettingsEntry copyFrom) {
+ setTo(copyFrom);
}
- int outerDepth = parser.getDepth();
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
+ /**
+ * Copies all fields from {@code delta} into this {@link SettingsEntry} object, keeping
+ * track of whether a change has occurred.
+ *
+ * @return {@code true} if this settings have changed as a result of the copy,
+ * {@code false} otherwise.
+ *
+ * @see #updateFrom(SettingsEntry)
+ */
+ boolean setTo(@NonNull SettingsEntry other) {
+ boolean changed = false;
+ if (other.mWindowingMode != mWindowingMode) {
+ mWindowingMode = other.mWindowingMode;
+ changed = true;
}
-
- String tagName = parser.getName();
- if (tagName.equals("display")) {
- readDisplay(parser);
- } else if (tagName.equals("config")) {
- readConfig(parser);
- } else {
- Slog.w(TAG, "Unknown element under <display-settings>: "
- + parser.getName());
- XmlUtils.skipCurrentTag(parser);
+ if (!Objects.equals(other.mUserRotationMode, mUserRotationMode)) {
+ mUserRotationMode = other.mUserRotationMode;
+ changed = true;
}
+ if (!Objects.equals(other.mUserRotation, mUserRotation)) {
+ mUserRotation = other.mUserRotation;
+ changed = true;
+ }
+ if (other.mForcedWidth != mForcedWidth) {
+ mForcedWidth = other.mForcedWidth;
+ changed = true;
+ }
+ if (other.mForcedHeight != mForcedHeight) {
+ mForcedHeight = other.mForcedHeight;
+ changed = true;
+ }
+ if (other.mForcedDensity != mForcedDensity) {
+ mForcedDensity = other.mForcedDensity;
+ changed = true;
+ }
+ if (!Objects.equals(other.mForcedScalingMode, mForcedScalingMode)) {
+ mForcedScalingMode = other.mForcedScalingMode;
+ changed = true;
+ }
+ if (other.mRemoveContentMode != mRemoveContentMode) {
+ mRemoveContentMode = other.mRemoveContentMode;
+ changed = true;
+ }
+ if (other.mShouldShowWithInsecureKeyguard != mShouldShowWithInsecureKeyguard) {
+ mShouldShowWithInsecureKeyguard = other.mShouldShowWithInsecureKeyguard;
+ changed = true;
+ }
+ if (other.mShouldShowSystemDecors != mShouldShowSystemDecors) {
+ mShouldShowSystemDecors = other.mShouldShowSystemDecors;
+ changed = true;
+ }
+ if (other.mShouldShowIme != mShouldShowIme) {
+ mShouldShowIme = other.mShouldShowIme;
+ changed = true;
+ }
+ if (!Objects.equals(other.mFixedToUserRotation, mFixedToUserRotation)) {
+ mFixedToUserRotation = other.mFixedToUserRotation;
+ changed = true;
+ }
+ if (other.mIgnoreOrientationRequest != mIgnoreOrientationRequest) {
+ mIgnoreOrientationRequest = other.mIgnoreOrientationRequest;
+ changed = true;
+ }
+ return changed;
}
- success = true;
- } catch (IllegalStateException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } catch (NullPointerException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } catch (NumberFormatException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } catch (XmlPullParserException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } catch (IOException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } catch (IndexOutOfBoundsException e) {
- Slog.w(TAG, "Failed parsing " + e);
- } finally {
- if (!success) {
- mEntries.clear();
- }
- try {
- stream.close();
- } catch (IOException e) {
- }
- }
- }
-
- private int getIntAttribute(XmlPullParser parser, String name) {
- return getIntAttribute(parser, name, 0 /* defaultValue */);
- }
-
- private int getIntAttribute(XmlPullParser parser, String name, int defaultValue) {
- try {
- final String str = parser.getAttributeValue(null, name);
- return str != null ? Integer.parseInt(str) : defaultValue;
- } catch (NumberFormatException e) {
- return defaultValue;
- }
- }
-
- private boolean getBooleanAttribute(XmlPullParser parser, String name) {
- return getBooleanAttribute(parser, name, false /* defaultValue */);
- }
-
- private boolean getBooleanAttribute(XmlPullParser parser, String name, boolean defaultValue) {
- try {
- final String str = parser.getAttributeValue(null, name);
- return str != null ? Boolean.parseBoolean(str) : defaultValue;
- } catch (NumberFormatException e) {
- return defaultValue;
- }
- }
-
- private void readDisplay(XmlPullParser parser) throws NumberFormatException,
- XmlPullParserException, IOException {
- String name = parser.getAttributeValue(null, "name");
- if (name != null) {
- Entry entry = new Entry(name);
- entry.mWindowingMode = getIntAttribute(parser, "windowingMode",
- WindowConfiguration.WINDOWING_MODE_UNDEFINED);
- entry.mUserRotationMode = getIntAttribute(parser, "userRotationMode",
- WindowManagerPolicy.USER_ROTATION_FREE);
- entry.mUserRotation = getIntAttribute(parser, "userRotation",
- Surface.ROTATION_0);
- entry.mForcedWidth = getIntAttribute(parser, "forcedWidth");
- entry.mForcedHeight = getIntAttribute(parser, "forcedHeight");
- entry.mForcedDensity = getIntAttribute(parser, "forcedDensity");
- entry.mForcedScalingMode = getIntAttribute(parser, "forcedScalingMode",
- FORCE_SCALING_MODE_AUTO);
- entry.mRemoveContentMode = getIntAttribute(parser, "removeContentMode",
- REMOVE_CONTENT_MODE_UNDEFINED);
- entry.mShouldShowWithInsecureKeyguard = getBooleanAttribute(parser,
- "shouldShowWithInsecureKeyguard");
- entry.mShouldShowSystemDecors = getBooleanAttribute(parser, "shouldShowSystemDecors");
- entry.mShouldShowIme = getBooleanAttribute(parser, "shouldShowIme");
- entry.mFixedToUserRotation = getIntAttribute(parser, "fixedToUserRotation");
- entry.mIgnoreOrientationRequest
- = getBooleanAttribute(parser, "ignoreOrientationRequest");
- mEntries.put(name, entry);
- }
- XmlUtils.skipCurrentTag(parser);
- }
-
- private void readConfig(XmlPullParser parser) throws NumberFormatException,
- XmlPullParserException, IOException {
- mIdentifier = getIntAttribute(parser, "identifier");
- XmlUtils.skipCurrentTag(parser);
- }
-
- private void writeSettingsIfNeeded(Entry changedEntry, DisplayInfo displayInfo) {
- if (changedEntry.isEmpty() && !removeEntry(displayInfo)) {
- // The entry didn't exist so nothing is changed and no need to update the file.
- return;
- }
-
- mEntries.put(getIdentifier(displayInfo), changedEntry);
- writeSettings();
- }
-
- private void writeSettings() {
- OutputStream stream;
- try {
- stream = mStorage.startWrite();
- } catch (IOException e) {
- Slog.w(TAG, "Failed to write display settings: " + e);
- return;
- }
-
- try {
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(stream, StandardCharsets.UTF_8.name());
- out.startDocument(null, true);
- out.startTag(null, "display-settings");
-
- out.startTag(null, "config");
- out.attribute(null, "identifier", Integer.toString(mIdentifier));
- out.endTag(null, "config");
-
- for (Entry entry : mEntries.values()) {
- out.startTag(null, "display");
- out.attribute(null, "name", entry.mName);
- if (entry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
- out.attribute(null, "windowingMode", Integer.toString(entry.mWindowingMode));
+ /**
+ * Copies the fields from {@code delta} into this {@link SettingsEntry} object, keeping
+ * track of whether a change has occurred. Any undefined fields in {@code delta} are
+ * ignored and not copied into the current {@link SettingsEntry}.
+ *
+ * @return {@code true} if this settings have changed as a result of the copy,
+ * {@code false} otherwise.
+ *
+ * @see #setTo(SettingsEntry)
+ */
+ boolean updateFrom(@NonNull SettingsEntry delta) {
+ boolean changed = false;
+ if (delta.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED
+ && delta.mWindowingMode != mWindowingMode) {
+ mWindowingMode = delta.mWindowingMode;
+ changed = true;
+ }
+ if (delta.mUserRotationMode != null
+ && !Objects.equals(delta.mUserRotationMode, mUserRotationMode)) {
+ mUserRotationMode = delta.mUserRotationMode;
+ changed = true;
}
- if (entry.mUserRotationMode != WindowManagerPolicy.USER_ROTATION_FREE) {
- out.attribute(null, "userRotationMode",
- Integer.toString(entry.mUserRotationMode));
+ if (delta.mUserRotation != null
+ && !Objects.equals(delta.mUserRotation, mUserRotation)) {
+ mUserRotation = delta.mUserRotation;
+ changed = true;
}
- if (entry.mUserRotation != Surface.ROTATION_0) {
- out.attribute(null, "userRotation", Integer.toString(entry.mUserRotation));
+ if (delta.mForcedWidth != 0 && delta.mForcedWidth != mForcedWidth) {
+ mForcedWidth = delta.mForcedWidth;
+ changed = true;
}
- if (entry.mForcedWidth != 0 && entry.mForcedHeight != 0) {
- out.attribute(null, "forcedWidth", Integer.toString(entry.mForcedWidth));
- out.attribute(null, "forcedHeight", Integer.toString(entry.mForcedHeight));
+ if (delta.mForcedHeight != 0 && delta.mForcedHeight != mForcedHeight) {
+ mForcedHeight = delta.mForcedHeight;
+ changed = true;
}
- if (entry.mForcedDensity != 0) {
- out.attribute(null, "forcedDensity", Integer.toString(entry.mForcedDensity));
+ if (delta.mForcedDensity != 0 && delta.mForcedDensity != mForcedDensity) {
+ mForcedDensity = delta.mForcedDensity;
+ changed = true;
}
- if (entry.mForcedScalingMode != FORCE_SCALING_MODE_AUTO) {
- out.attribute(null, "forcedScalingMode",
- Integer.toString(entry.mForcedScalingMode));
+ if (delta.mForcedScalingMode != null
+ && !Objects.equals(delta.mForcedScalingMode, mForcedScalingMode)) {
+ mForcedScalingMode = delta.mForcedScalingMode;
+ changed = true;
}
- if (entry.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED) {
- out.attribute(null, "removeContentMode",
- Integer.toString(entry.mRemoveContentMode));
+ if (delta.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED
+ && delta.mRemoveContentMode != mRemoveContentMode) {
+ mRemoveContentMode = delta.mRemoveContentMode;
+ changed = true;
}
- if (entry.mShouldShowWithInsecureKeyguard) {
- out.attribute(null, "shouldShowWithInsecureKeyguard",
- Boolean.toString(entry.mShouldShowWithInsecureKeyguard));
+ if (delta.mShouldShowWithInsecureKeyguard != null
+ && delta.mShouldShowWithInsecureKeyguard
+ != mShouldShowWithInsecureKeyguard) {
+ mShouldShowWithInsecureKeyguard = delta.mShouldShowWithInsecureKeyguard;
+ changed = true;
}
- if (entry.mShouldShowSystemDecors) {
- out.attribute(null, "shouldShowSystemDecors",
- Boolean.toString(entry.mShouldShowSystemDecors));
+ if (delta.mShouldShowSystemDecors != null
+ && delta.mShouldShowSystemDecors != mShouldShowSystemDecors) {
+ mShouldShowSystemDecors = delta.mShouldShowSystemDecors;
+ changed = true;
}
- if (entry.mShouldShowIme) {
- out.attribute(null, "shouldShowIme", Boolean.toString(entry.mShouldShowIme));
+ if (delta.mShouldShowIme != null
+ && delta.mShouldShowIme != mShouldShowIme) {
+ mShouldShowIme = delta.mShouldShowIme;
+ changed = true;
}
- if (entry.mFixedToUserRotation != IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT) {
- out.attribute(null, "fixedToUserRotation",
- Integer.toString(entry.mFixedToUserRotation));
+ if (delta.mFixedToUserRotation != null
+ && !Objects.equals(delta.mFixedToUserRotation, mFixedToUserRotation)) {
+ mFixedToUserRotation = delta.mFixedToUserRotation;
+ changed = true;
}
- if (entry.mIgnoreOrientationRequest) {
- out.attribute(null, "ignoreOrientationRequest",
- Boolean.toString(entry.mIgnoreOrientationRequest));
+ if (delta.mIgnoreOrientationRequest != null
+ && delta.mIgnoreOrientationRequest != mIgnoreOrientationRequest) {
+ mIgnoreOrientationRequest = delta.mIgnoreOrientationRequest;
+ changed = true;
}
- out.endTag(null, "display");
+ return changed;
}
- out.endTag(null, "display-settings");
- out.endDocument();
- mStorage.finishWrite(stream, true /* success */);
- } catch (IOException e) {
- Slog.w(TAG, "Failed to write display window settings.", e);
- mStorage.finishWrite(stream, false /* success */);
- }
- }
-
- /**
- * Removes an entry from {@link #mEntries} cache. Looks up by new and previously used
- * identifiers.
- */
- private boolean removeEntry(DisplayInfo displayInfo) {
- // Remove entry based on primary identifier.
- boolean removed = mEntries.remove(getIdentifier(displayInfo)) != null;
- // Ensure that legacy entries are cleared as well.
- removed |= mEntries.remove(displayInfo.uniqueId) != null;
- removed |= mEntries.remove(displayInfo.name) != null;
- return removed;
- }
-
- /** Gets the identifier of choice for the current config. */
- private String getIdentifier(DisplayInfo displayInfo) {
- if (mIdentifier == IDENTIFIER_PORT && displayInfo.address != null) {
- // Config suggests using port as identifier for physical displays.
- if (displayInfo.address instanceof DisplayAddress.Physical) {
- return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort();
+ /** @return {@code true} if all values are unset. */
+ boolean isEmpty() {
+ return mWindowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
+ && mUserRotationMode == null
+ && mUserRotation == null
+ && mForcedWidth == 0 && mForcedHeight == 0 && mForcedDensity == 0
+ && mForcedScalingMode == null
+ && mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED
+ && mShouldShowWithInsecureKeyguard == null
+ && mShouldShowSystemDecors == null
+ && mShouldShowIme == null
+ && mFixedToUserRotation == null
+ && mIgnoreOrientationRequest == null;
}
- }
- return displayInfo.uniqueId;
- }
- private static class AtomicFileStorage implements SettingPersister {
- private final AtomicFile mAtomicFile;
-
- AtomicFileStorage() {
- final File folder = new File(Environment.getDataDirectory(), SYSTEM_DIRECTORY);
- final File settingsFile = new File(folder, DISPLAY_SETTINGS_FILE_NAME);
- // If display_settings.xml doesn't exist, try to copy the vendor's one instead
- // in order to provide the vendor specific initialization.
- if (!settingsFile.exists()) {
- copyVendorSettings(settingsFile);
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SettingsEntry that = (SettingsEntry) o;
+ return mWindowingMode == that.mWindowingMode
+ && mForcedWidth == that.mForcedWidth
+ && mForcedHeight == that.mForcedHeight
+ && mForcedDensity == that.mForcedDensity
+ && mRemoveContentMode == that.mRemoveContentMode
+ && Objects.equals(mUserRotationMode, that.mUserRotationMode)
+ && Objects.equals(mUserRotation, that.mUserRotation)
+ && Objects.equals(mForcedScalingMode, that.mForcedScalingMode)
+ && Objects.equals(mShouldShowWithInsecureKeyguard,
+ that.mShouldShowWithInsecureKeyguard)
+ && Objects.equals(mShouldShowSystemDecors, that.mShouldShowSystemDecors)
+ && Objects.equals(mShouldShowIme, that.mShouldShowIme)
+ && Objects.equals(mFixedToUserRotation, that.mFixedToUserRotation)
+ && Objects.equals(mIgnoreOrientationRequest,
+ that.mIgnoreOrientationRequest);
}
- mAtomicFile = new AtomicFile(settingsFile, WM_DISPLAY_COMMIT_TAG);
- }
- private static void copyVendorSettings(File target) {
- final File vendorFile = new File(Environment.getVendorDirectory(),
- VENDOR_DISPLAY_SETTINGS_PATH);
- if (vendorFile.canRead()) {
- try {
- FileUtils.copy(vendorFile, target);
- } catch (IOException e) {
- Slog.e(TAG, "Failed to copy vendor display_settings.xml");
- }
+ @Override
+ public int hashCode() {
+ return Objects.hash(mWindowingMode, mUserRotationMode, mUserRotation, mForcedWidth,
+ mForcedHeight, mForcedDensity, mForcedScalingMode, mRemoveContentMode,
+ mShouldShowWithInsecureKeyguard, mShouldShowSystemDecors, mShouldShowIme,
+ mFixedToUserRotation, mIgnoreOrientationRequest);
}
- }
-
- @Override
- public InputStream openRead() throws FileNotFoundException {
- return mAtomicFile.openRead();
- }
- @Override
- public OutputStream startWrite() throws IOException {
- return mAtomicFile.startWrite();
- }
-
- @Override
- public void finishWrite(OutputStream os, boolean success) {
- if (!(os instanceof FileOutputStream)) {
- throw new IllegalArgumentException("Unexpected OutputStream as argument: " + os);
- }
- FileOutputStream fos = (FileOutputStream) os;
- if (success) {
- mAtomicFile.finishWrite(fos);
- } else {
- mAtomicFile.failWrite(fos);
+ @Override
+ public String toString() {
+ return "SettingsEntry{"
+ + "mWindowingMode=" + mWindowingMode
+ + ", mUserRotationMode=" + mUserRotationMode
+ + ", mUserRotation=" + mUserRotation
+ + ", mForcedWidth=" + mForcedWidth
+ + ", mForcedHeight=" + mForcedHeight
+ + ", mForcedDensity=" + mForcedDensity
+ + ", mForcedScalingMode=" + mForcedScalingMode
+ + ", mRemoveContentMode=" + mRemoveContentMode
+ + ", mShouldShowWithInsecureKeyguard=" + mShouldShowWithInsecureKeyguard
+ + ", mShouldShowSystemDecors=" + mShouldShowSystemDecors
+ + ", mShouldShowIme=" + mShouldShowIme
+ + ", mFixedToUserRotation=" + mFixedToUserRotation
+ + ", mIgnoreOrientationRequest=" + mIgnoreOrientationRequest
+ + '}';
}
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
new file mode 100644
index 000000000000..a7f7c480f78f
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
+
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.WindowConfiguration;
+import android.os.Environment;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+import android.view.DisplayAddress;
+import android.view.DisplayInfo;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Implementation of {@link SettingsProvider} that reads the base settings provided in a display
+ * settings file stored in /vendor/etc and then overlays those values with the settings provided in
+ * /data/system.
+ *
+ * @see DisplayWindowSettings
+ */
+class DisplayWindowSettingsProvider implements SettingsProvider {
+ private static final String TAG = TAG_WITH_CLASS_NAME
+ ? "DisplayWindowSettingsProvider" : TAG_WM;
+
+ private static final String DATA_DISPLAY_SETTINGS_FILE_PATH = "system/display_settings.xml";
+ private static final String VENDOR_DISPLAY_SETTINGS_PATH = "etc/display_settings.xml";
+ private static final String WM_DISPLAY_COMMIT_TAG = "wm-displays";
+
+ private static final int IDENTIFIER_UNIQUE_ID = 0;
+ private static final int IDENTIFIER_PORT = 1;
+ @IntDef(prefix = { "IDENTIFIER_" }, value = {
+ IDENTIFIER_UNIQUE_ID,
+ IDENTIFIER_PORT,
+ })
+ @interface DisplayIdentifierType {}
+
+ /** Interface that allows reading the display window settings. */
+ interface ReadableSettingsStorage {
+ InputStream openRead() throws IOException;
+ }
+
+ /** Interface that allows reading and writing the display window settings. */
+ interface WritableSettingsStorage extends ReadableSettingsStorage {
+ OutputStream startWrite() throws IOException;
+ void finishWrite(OutputStream os, boolean success);
+ }
+
+ private final ReadableSettingsStorage mVendorSettingsStorage;
+ /**
+ * The preferred type of a display identifier to use when storing and retrieving entries from
+ * the base (vendor) settings file.
+ *
+ * @see #getIdentifier(DisplayInfo, int)
+ */
+ @DisplayIdentifierType
+ private int mVendorIdentifierType;
+ private final Map<String, SettingsEntry> mVendorSettings = new HashMap<>();
+
+ private final WritableSettingsStorage mOverrideSettingsStorage;
+ /**
+ * The preferred type of a display identifier to use when storing and retrieving entries from
+ * the data (override) settings file.
+ *
+ * @see #getIdentifier(DisplayInfo, int)
+ */
+ @DisplayIdentifierType
+ private int mOverrideIdentifierType;
+ private final Map<String, SettingsEntry> mOverrideSettings = new HashMap<>();
+
+ /**
+ * Enables or disables settings provided from the vendor settings storage.
+ *
+ * @see #setVendorSettingsIgnored(boolean)
+ */
+ private boolean mIgnoreVendorSettings = true;
+
+ DisplayWindowSettingsProvider() {
+ this(new AtomicFileStorage(getVendorSettingsFile()),
+ new AtomicFileStorage(getOverrideSettingsFile()));
+ }
+
+ @VisibleForTesting
+ DisplayWindowSettingsProvider(@NonNull ReadableSettingsStorage vendorSettingsStorage,
+ @NonNull WritableSettingsStorage overrideSettingsStorage) {
+ mVendorSettingsStorage = vendorSettingsStorage;
+ mOverrideSettingsStorage = overrideSettingsStorage;
+ readSettings();
+ }
+
+ /**
+ * Enables or disables settings provided from the vendor settings storage. If {@code true}, the
+ * vendor settings will be ignored and only the override settings will be returned from
+ * {@link #getSettings(DisplayInfo)}. If {@code false}, settings returned from
+ * {@link #getSettings(DisplayInfo)} will be a merged result of the vendor settings and the
+ * override settings.
+ */
+ void setVendorSettingsIgnored(boolean ignored) {
+ mIgnoreVendorSettings = ignored;
+ }
+
+ /**
+ * Returns whether or not the vendor settings are being ignored.
+ *
+ * @see #setVendorSettingsIgnored(boolean)
+ */
+ @VisibleForTesting
+ boolean getVendorSettingsIgnored() {
+ return mIgnoreVendorSettings;
+ }
+
+ @Override
+ @NonNull
+ public SettingsEntry getSettings(@NonNull DisplayInfo info) {
+ SettingsEntry vendorSettings = getVendorSettingsEntry(info);
+ SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
+ if (vendorSettings == null) {
+ return new SettingsEntry(overrideSettings);
+ } else {
+ SettingsEntry mergedSettings = new SettingsEntry(vendorSettings);
+ mergedSettings.updateFrom(overrideSettings);
+ return mergedSettings;
+ }
+ }
+
+ @Override
+ @NonNull
+ public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) {
+ return new SettingsEntry(getOrCreateOverrideSettingsEntry(info));
+ }
+
+ @Override
+ public void updateOverrideSettings(@NonNull DisplayInfo info,
+ @NonNull SettingsEntry overrides) {
+ final SettingsEntry overrideSettings = getOrCreateOverrideSettingsEntry(info);
+ boolean changed = overrideSettings.setTo(overrides);
+ if (changed) {
+ writeOverrideSettings();
+ }
+ }
+
+ @Nullable
+ private SettingsEntry getVendorSettingsEntry(DisplayInfo info) {
+ if (mIgnoreVendorSettings) {
+ return null;
+ }
+
+ final String identifier = getIdentifier(info, mVendorIdentifierType);
+ SettingsEntry settings;
+ // Try to get corresponding settings using preferred identifier for the current config.
+ if ((settings = mVendorSettings.get(identifier)) != null) {
+ return settings;
+ }
+ // Else, fall back to the display name.
+ if ((settings = mVendorSettings.get(info.name)) != null) {
+ // Found an entry stored with old identifier.
+ mVendorSettings.remove(info.name);
+ mVendorSettings.put(identifier, settings);
+ return settings;
+ }
+ return null;
+ }
+
+ @NonNull
+ private SettingsEntry getOrCreateOverrideSettingsEntry(DisplayInfo info) {
+ final String identifier = getIdentifier(info, mOverrideIdentifierType);
+ SettingsEntry settings;
+ // Try to get corresponding settings using preferred identifier for the current config.
+ if ((settings = mOverrideSettings.get(identifier)) != null) {
+ return settings;
+ }
+ // Else, fall back to the display name.
+ if ((settings = mOverrideSettings.get(info.name)) != null) {
+ // Found an entry stored with old identifier.
+ mOverrideSettings.remove(info.name);
+ mOverrideSettings.put(identifier, settings);
+ writeOverrideSettings();
+ return settings;
+ }
+
+ settings = new SettingsEntry();
+ mOverrideSettings.put(identifier, settings);
+ return settings;
+ }
+
+ private void readSettings() {
+ FileData vendorFileData = readSettings(mVendorSettingsStorage);
+ if (vendorFileData != null) {
+ mVendorIdentifierType = vendorFileData.mIdentifierType;
+ mVendorSettings.putAll(vendorFileData.mSettings);
+ }
+
+ FileData overrideFileData = readSettings(mOverrideSettingsStorage);
+ if (overrideFileData != null) {
+ mOverrideIdentifierType = overrideFileData.mIdentifierType;
+ mOverrideSettings.putAll(overrideFileData.mSettings);
+ }
+ }
+
+ private void writeOverrideSettings() {
+ FileData fileData = new FileData();
+ fileData.mIdentifierType = mOverrideIdentifierType;
+ fileData.mSettings.putAll(mOverrideSettings);
+ writeSettings(mOverrideSettingsStorage, fileData);
+ }
+
+ /** Gets the identifier of choice for the current config. */
+ private static String getIdentifier(DisplayInfo displayInfo, @DisplayIdentifierType int type) {
+ if (type == IDENTIFIER_PORT && displayInfo.address != null) {
+ // Config suggests using port as identifier for physical displays.
+ if (displayInfo.address instanceof DisplayAddress.Physical) {
+ return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort();
+ }
+ }
+ return displayInfo.uniqueId;
+ }
+
+ @NonNull
+ private static AtomicFile getVendorSettingsFile() {
+ final File vendorFile = new File(Environment.getVendorDirectory(),
+ VENDOR_DISPLAY_SETTINGS_PATH);
+ return new AtomicFile(vendorFile, WM_DISPLAY_COMMIT_TAG);
+ }
+
+ @NonNull
+ private static AtomicFile getOverrideSettingsFile() {
+ final File overrideSettingsFile = new File(Environment.getDataDirectory(),
+ DATA_DISPLAY_SETTINGS_FILE_PATH);
+ return new AtomicFile(overrideSettingsFile, WM_DISPLAY_COMMIT_TAG);
+ }
+
+ @Nullable
+ private static FileData readSettings(ReadableSettingsStorage storage) {
+ InputStream stream;
+ try {
+ stream = storage.openRead();
+ } catch (IOException e) {
+ Slog.i(TAG, "No existing display settings, starting empty");
+ return null;
+ }
+ FileData fileData = new FileData();
+ boolean success = false;
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Do nothing.
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("no start tag found");
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("display")) {
+ readDisplay(parser, fileData);
+ } else if (tagName.equals("config")) {
+ readConfig(parser, fileData);
+ } else {
+ Slog.w(TAG, "Unknown element under <display-settings>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ success = true;
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NullPointerException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (XmlPullParserException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } catch (IndexOutOfBoundsException e) {
+ Slog.w(TAG, "Failed parsing " + e);
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException ignored) {
+ }
+ }
+ if (!success) {
+ fileData.mSettings.clear();
+ }
+ return fileData;
+ }
+
+ private static int getIntAttribute(XmlPullParser parser, String name, int defaultValue) {
+ try {
+ final String str = parser.getAttributeValue(null, name);
+ return str != null ? Integer.parseInt(str) : defaultValue;
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed to parse display window settings attribute: " + name, e);
+ return defaultValue;
+ }
+ }
+
+ @Nullable
+ private static Integer getIntegerAttribute(XmlPullParser parser, String name,
+ @Nullable Integer defaultValue) {
+ try {
+ final String str = parser.getAttributeValue(null, name);
+ return str != null ? Integer.valueOf(str) : defaultValue;
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed to parse display window settings attribute: " + name, e);
+ return defaultValue;
+ }
+ }
+
+ @Nullable
+ private static Boolean getBooleanAttribute(XmlPullParser parser, String name,
+ @Nullable Boolean defaultValue) {
+ final String str = parser.getAttributeValue(null, name);
+ return str != null ? Boolean.valueOf(str) : defaultValue;
+ }
+
+ private static void readDisplay(XmlPullParser parser, FileData fileData)
+ throws NumberFormatException, XmlPullParserException, IOException {
+ String name = parser.getAttributeValue(null, "name");
+ if (name != null) {
+ SettingsEntry settingsEntry = new SettingsEntry();
+ settingsEntry.mWindowingMode = getIntAttribute(parser, "windowingMode",
+ WindowConfiguration.WINDOWING_MODE_UNDEFINED /* defaultValue */);
+ settingsEntry.mUserRotationMode = getIntegerAttribute(parser, "userRotationMode",
+ null /* defaultValue */);
+ settingsEntry.mUserRotation = getIntegerAttribute(parser, "userRotation",
+ null /* defaultValue */);
+ settingsEntry.mForcedWidth = getIntAttribute(parser, "forcedWidth",
+ 0 /* defaultValue */);
+ settingsEntry.mForcedHeight = getIntAttribute(parser, "forcedHeight",
+ 0 /* defaultValue */);
+ settingsEntry.mForcedDensity = getIntAttribute(parser, "forcedDensity",
+ 0 /* defaultValue */);
+ settingsEntry.mForcedScalingMode = getIntegerAttribute(parser, "forcedScalingMode",
+ null /* defaultValue */);
+ settingsEntry.mRemoveContentMode = getIntAttribute(parser, "removeContentMode",
+ REMOVE_CONTENT_MODE_UNDEFINED /* defaultValue */);
+ settingsEntry.mShouldShowWithInsecureKeyguard = getBooleanAttribute(parser,
+ "shouldShowWithInsecureKeyguard", null /* defaultValue */);
+ settingsEntry.mShouldShowSystemDecors = getBooleanAttribute(parser,
+ "shouldShowSystemDecors", null /* defaultValue */);
+ settingsEntry.mShouldShowIme = getBooleanAttribute(parser, "shouldShowIme",
+ null /* defaultValue */);
+ settingsEntry.mFixedToUserRotation = getIntegerAttribute(parser, "fixedToUserRotation",
+ null /* defaultValue */);
+ settingsEntry.mIgnoreOrientationRequest = getBooleanAttribute(parser,
+ "ignoreOrientationRequest", null /* defaultValue */);
+ fileData.mSettings.put(name, settingsEntry);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ private static void readConfig(XmlPullParser parser, FileData fileData)
+ throws NumberFormatException,
+ XmlPullParserException, IOException {
+ fileData.mIdentifierType = getIntAttribute(parser, "identifier",
+ IDENTIFIER_UNIQUE_ID);
+ XmlUtils.skipCurrentTag(parser);
+ }
+
+ private static void writeSettings(WritableSettingsStorage storage, FileData data) {
+ OutputStream stream;
+ try {
+ stream = storage.startWrite();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write display settings: " + e);
+ return;
+ }
+
+ boolean success = false;
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+
+ out.startTag(null, "display-settings");
+
+ out.startTag(null, "config");
+ out.attribute(null, "identifier",
+ Integer.toString(data.mIdentifierType));
+ out.endTag(null, "config");
+
+ for (Map.Entry<String, SettingsEntry> entry
+ : data.mSettings.entrySet()) {
+ String displayIdentifier = entry.getKey();
+ SettingsEntry settingsEntry = entry.getValue();
+ if (settingsEntry.isEmpty()) {
+ continue;
+ }
+
+ out.startTag(null, "display");
+ out.attribute(null, "name", displayIdentifier);
+ if (settingsEntry.mWindowingMode != WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
+ out.attribute(null, "windowingMode",
+ Integer.toString(settingsEntry.mWindowingMode));
+ }
+ if (settingsEntry.mUserRotationMode != null) {
+ out.attribute(null, "userRotationMode",
+ settingsEntry.mUserRotationMode.toString());
+ }
+ if (settingsEntry.mUserRotation != null) {
+ out.attribute(null, "userRotation",
+ settingsEntry.mUserRotation.toString());
+ }
+ if (settingsEntry.mForcedWidth != 0 && settingsEntry.mForcedHeight != 0) {
+ out.attribute(null, "forcedWidth",
+ Integer.toString(settingsEntry.mForcedWidth));
+ out.attribute(null, "forcedHeight",
+ Integer.toString(settingsEntry.mForcedHeight));
+ }
+ if (settingsEntry.mForcedDensity != 0) {
+ out.attribute(null, "forcedDensity",
+ Integer.toString(settingsEntry.mForcedDensity));
+ }
+ if (settingsEntry.mForcedScalingMode != null) {
+ out.attribute(null, "forcedScalingMode",
+ settingsEntry.mForcedScalingMode.toString());
+ }
+ if (settingsEntry.mRemoveContentMode != REMOVE_CONTENT_MODE_UNDEFINED) {
+ out.attribute(null, "removeContentMode",
+ Integer.toString(settingsEntry.mRemoveContentMode));
+ }
+ if (settingsEntry.mShouldShowWithInsecureKeyguard != null) {
+ out.attribute(null, "shouldShowWithInsecureKeyguard",
+ settingsEntry.mShouldShowWithInsecureKeyguard.toString());
+ }
+ if (settingsEntry.mShouldShowSystemDecors != null) {
+ out.attribute(null, "shouldShowSystemDecors",
+ settingsEntry.mShouldShowSystemDecors.toString());
+ }
+ if (settingsEntry.mShouldShowIme != null) {
+ out.attribute(null, "shouldShowIme",
+ settingsEntry.mShouldShowIme.toString());
+ }
+ if (settingsEntry.mFixedToUserRotation != null) {
+ out.attribute(null, "fixedToUserRotation",
+ settingsEntry.mFixedToUserRotation.toString());
+ }
+ if (settingsEntry.mIgnoreOrientationRequest != null) {
+ out.attribute(null, "ignoreOrientationRequest",
+ settingsEntry.mIgnoreOrientationRequest.toString());
+ }
+ out.endTag(null, "display");
+ }
+
+ out.endTag(null, "display-settings");
+ out.endDocument();
+ success = true;
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write display window settings.", e);
+ } finally {
+ storage.finishWrite(stream, success);
+ }
+ }
+
+ private static final class FileData {
+ int mIdentifierType;
+ final Map<String, SettingsEntry> mSettings = new HashMap<>();
+
+ @Override
+ public String toString() {
+ return "FileData{"
+ + "mIdentifierType=" + mIdentifierType
+ + ", mSettings=" + mSettings
+ + '}';
+ }
+ }
+
+ private static final class AtomicFileStorage implements WritableSettingsStorage {
+ private final AtomicFile mAtomicFile;
+
+ AtomicFileStorage(@NonNull AtomicFile atomicFile) {
+ mAtomicFile = atomicFile;
+ }
+
+ @Override
+ public InputStream openRead() throws FileNotFoundException {
+ return mAtomicFile.openRead();
+ }
+
+ @Override
+ public OutputStream startWrite() throws IOException {
+ return mAtomicFile.startWrite();
+ }
+
+ @Override
+ public void finishWrite(OutputStream os, boolean success) {
+ if (!(os instanceof FileOutputStream)) {
+ throw new IllegalArgumentException("Unexpected OutputStream as argument: " + os);
+ }
+ FileOutputStream fos = (FileOutputStream) os;
+ if (success) {
+ mAtomicFile.finishWrite(fos);
+ } else {
+ mAtomicFile.failWrite(fos);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 3eac1be3ebee..627af9149fe5 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -49,6 +49,7 @@ class DragDropController {
static final int MSG_DRAG_END_TIMEOUT = 0;
static final int MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT = 1;
static final int MSG_ANIMATION_END = 2;
+ static final int MSG_REMOVE_DRAG_SURFACE_TIMEOUT = 3;
/**
* Drag state per operation.
@@ -384,6 +385,14 @@ class DragDropController {
}
break;
}
+
+ case MSG_REMOVE_DRAG_SURFACE_TIMEOUT: {
+ synchronized (mService.mGlobalLock) {
+ mService.mTransactionFactory.get()
+ .reparent((SurfaceControl) msg.obj, null).apply();
+ }
+ break;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 2ea4b57d9de3..e7d8ad690bc4 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -23,6 +23,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.wm.DragDropController.MSG_ANIMATION_END;
import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT;
+import static com.android.server.wm.DragDropController.MSG_REMOVE_DRAG_SURFACE_TIMEOUT;
import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -59,6 +60,7 @@ import android.view.WindowManager;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
+import com.android.internal.os.SomeArgs;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.view.IDragAndDropPermissions;
import com.android.server.LocalServices;
@@ -248,6 +250,9 @@ class DragState {
if (mSurfaceControl != null) {
if (!mRelinquishDragSurface) {
mTransaction.reparent(mSurfaceControl, null).apply();
+ } else {
+ mDragDropController.sendTimeoutMessage(MSG_REMOVE_DRAG_SURFACE_TIMEOUT,
+ mSurfaceControl);
}
mSurfaceControl = null;
}
@@ -277,9 +282,8 @@ class DragState {
mInputEventReceiver = new DragInputEventReceiver(mClientChannel,
mService.mH.getLooper(), mDragDropController);
- mDragApplicationHandle = new InputApplicationHandle(new Binder());
- mDragApplicationHandle.name = "drag";
- mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+ mDragApplicationHandle = new InputApplicationHandle(new Binder(), "drag",
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
display.getDisplayId());
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 3b89a24184f0..b08d6e1dff9e 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -175,11 +175,11 @@ class EmbeddedWindowController {
InputApplicationHandle getApplicationHandle() {
if (mHostWindowState == null
- || mHostWindowState.mInputWindowHandle.inputApplicationHandle == null) {
+ || mHostWindowState.mInputWindowHandle.getInputApplicationHandle() == null) {
return null;
}
return new InputApplicationHandle(
- mHostWindowState.mInputWindowHandle.inputApplicationHandle);
+ mHostWindowState.mInputWindowHandle.getInputApplicationHandle());
}
InputChannel openInputChannel() {
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 231cc9745ce1..e1d5b1d57197 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -33,6 +33,7 @@ class EnsureActivitiesVisibleHelper {
private int mConfigChanges;
private boolean mPreserveWindows;
private boolean mNotifyClients;
+ private boolean mUserLeaving;
EnsureActivitiesVisibleHelper(Task container) {
mTask = container;
@@ -49,7 +50,7 @@ class EnsureActivitiesVisibleHelper {
* be sent to the clients.
*/
void reset(ActivityRecord starting, int configChanges, boolean preserveWindows,
- boolean notifyClients) {
+ boolean notifyClients, boolean userLeaving) {
mStarting = starting;
mTop = mTask.topRunningActivity();
// If the top activity is not fullscreen, then we need to make sure any activities under it
@@ -60,6 +61,7 @@ class EnsureActivitiesVisibleHelper {
mConfigChanges = configChanges;
mPreserveWindows = preserveWindows;
mNotifyClients = notifyClients;
+ mUserLeaving = userLeaving;
}
/**
@@ -76,10 +78,12 @@ class EnsureActivitiesVisibleHelper {
* @param preserveWindows Flag indicating whether windows should be preserved when updating.
* @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
* be sent to the clients.
+ * @param userLeaving Flag indicating whether a userLeaving callback should be issued in the
+ * case the activity is being set to invisible.
*/
void process(@Nullable ActivityRecord starting, int configChanges, boolean preserveWindows,
- boolean notifyClients) {
- reset(starting, configChanges, preserveWindows, notifyClients);
+ boolean notifyClients, boolean userLeaving) {
+ reset(starting, configChanges, preserveWindows, notifyClients, userLeaving);
if (DEBUG_VISIBILITY) {
Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + mTop
@@ -173,7 +177,7 @@ class EnsureActivitiesVisibleHelper {
+ " behindFullscreenActivity=" + mBehindFullscreenActivity
+ " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
}
- r.makeInvisible();
+ r.makeInvisible(mUserLeaving);
}
if (!mBehindFullscreenActivity && mTask.isActivityTypeHome() && r.isRootOfTask()) {
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 0813b4f9efe0..818d96ceb5a6 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -16,11 +16,14 @@
package com.android.server.wm;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
import static com.android.server.wm.ImeInsetsSourceProviderProto.IME_TARGET_FROM_IME;
import static com.android.server.wm.ImeInsetsSourceProviderProto.INSETS_SOURCE_PROVIDER;
import static com.android.server.wm.ImeInsetsSourceProviderProto.IS_IME_LAYOUT_DRAWN;
+import android.os.Trace;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsSource;
import android.view.WindowInsets;
@@ -79,6 +82,7 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
ProtoLog.i(WM_DEBUG_IME, "call showInsets(ime) on %s",
target.getWindow() != null ? target.getWindow().getName() : "");
target.showInsets(WindowInsets.Type.ime(), true /* fromIme */);
+ Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "WMS.showImePostLayout", 0);
if (target != mImeTargetFromIme && mImeTargetFromIme != null) {
ProtoLog.w(WM_DEBUG_IME,
"showInsets(ime) was requested by different window: %s ",
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index edb5e853af4f..e35621a84b37 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -63,9 +63,8 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
mClientChannel.copyTo(inputChannel);
}
- mApplicationHandle = new InputApplicationHandle(new Binder());
- mApplicationHandle.name = name;
- mApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+ mApplicationHandle = new InputApplicationHandle(new Binder(), name,
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
mWindowHandle.name = name;
@@ -160,9 +159,11 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
public void binderDied() {
synchronized (mService.getWindowManagerLock()) {
// Clean up the input consumer
- final InputMonitor inputMonitor =
- mService.mRoot.getDisplayContent(mWindowHandle.displayId).getInputMonitor();
- inputMonitor.destroyInputConsumer(mName);
+ final DisplayContent dc = mService.mRoot.getDisplayContent(mWindowHandle.displayId);
+ if (dc == null) {
+ return;
+ }
+ dc.getInputMonitor().destroyInputConsumer(mName);
unlinkFromDeathRecipient();
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 4a54196b71de..457df4e47689 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -48,6 +48,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.LOGTAG_INPUT_FOCUS;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -57,12 +58,12 @@ import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Slog;
-import android.view.InputApplicationHandle;
import android.view.InputChannel;
import android.view.InputEventReceiver;
import android.view.InputWindowHandle;
import android.view.SurfaceControl;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import java.io.PrintWriter;
@@ -81,7 +82,7 @@ final class InputMonitor {
private boolean mUpdateInputWindowsImmediately;
private boolean mDisableWallpaperTouchEvents;
- private final Rect mTmpRect = new Rect();
+ private final Region mTmpRegion = new Region();
private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer;
private final int mDisplayId;
@@ -276,66 +277,67 @@ final class InputMonitor {
addInputConsumer(name, consumer);
}
-
- void populateInputWindowHandle(final InputWindowHandle inputWindowHandle,
- final WindowState child, int flags, final int type, final boolean isVisible,
- final boolean focusable, final boolean hasWallpaper) {
+ @VisibleForTesting
+ void populateInputWindowHandle(final InputWindowHandleWrapper inputWindowHandle,
+ final WindowState w) {
// Add a window to our list of input windows.
- inputWindowHandle.name = child.toString();
- flags = child.getSurfaceTouchableRegion(inputWindowHandle, flags);
- inputWindowHandle.layoutParamsFlags = flags;
- inputWindowHandle.layoutParamsType = type;
- inputWindowHandle.dispatchingTimeoutMillis = child.getInputDispatchingTimeoutMillis();
- inputWindowHandle.visible = isVisible;
- inputWindowHandle.focusable = focusable;
- inputWindowHandle.touchOcclusionMode = child.getTouchOcclusionMode();
- inputWindowHandle.hasWallpaper = hasWallpaper;
- inputWindowHandle.paused = child.mActivityRecord != null ? child.mActivityRecord.paused : false;
- inputWindowHandle.ownerPid = child.mSession.mPid;
- inputWindowHandle.ownerUid = child.mSession.mUid;
- inputWindowHandle.packageName = child.getOwningPackage();
- inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
- inputWindowHandle.displayId = child.getDisplayId();
-
- final Rect frame = child.getFrame();
- inputWindowHandle.frameLeft = frame.left;
- inputWindowHandle.frameTop = frame.top;
- inputWindowHandle.frameRight = frame.right;
- inputWindowHandle.frameBottom = frame.bottom;
+ inputWindowHandle.setInputApplicationHandle(w.mActivityRecord != null
+ ? w.mActivityRecord.getInputApplicationHandle(false /* update */) : null);
+ inputWindowHandle.setToken(w.mInputChannelToken);
+ inputWindowHandle.setDispatchingTimeoutMillis(w.getInputDispatchingTimeoutMillis());
+ inputWindowHandle.setTouchOcclusionMode(w.getTouchOcclusionMode());
+ inputWindowHandle.setInputFeatures(w.mAttrs.inputFeatures);
+ inputWindowHandle.setPaused(w.mActivityRecord != null && w.mActivityRecord.paused);
+ inputWindowHandle.setVisible(w.isVisible());
+
+ final boolean focusable = w.canReceiveKeys()
+ && (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
+ inputWindowHandle.setFocusable(focusable);
+
+ final boolean hasWallpaper = mDisplayContent.mWallpaperController.isWallpaperTarget(w)
+ && !mService.mPolicy.isKeyguardShowing()
+ && !mDisableWallpaperTouchEvents;
+ inputWindowHandle.setHasWallpaper(hasWallpaper);
+
+ final Rect frame = w.getFrame();
+ inputWindowHandle.setFrame(frame.left, frame.top, frame.right, frame.bottom);
// Surface insets are hardcoded to be the same in all directions
// and we could probably deprecate the "left/right/top/bottom" concept.
// we avoid reintroducing this concept by just choosing one of them here.
- inputWindowHandle.surfaceInset = child.getAttrs().surfaceInsets.left;
-
- /**
- * If the window is in a TaskManaged by a TaskOrganizer then most cropping
- * will be applied using the SurfaceControl hierarchy from the Organizer.
- * This means we need to make sure that these changes in crop are reflected
- * in the input windows, and so ensure this flag is set so that
- * the input crop always reflects the surface hierarchy.
- *
- * TODO(b/168252846): we have some issues with modal-windows, so we need to
- * cross that bridge now that we organize full-screen Tasks.
- */
- if (child.getTask() != null
- && child.getTask().isOrganized()
- && child.getTask().getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
- inputWindowHandle.replaceTouchableRegionWithCrop(null /* Use this surfaces crop */);
+ inputWindowHandle.setSurfaceInset(w.mAttrs.surfaceInsets.left);
+
+ // If we are scaling the window, input coordinates need to be inversely scaled to map from
+ // what is on screen to what is actually being touched in the UI.
+ inputWindowHandle.setScaleFactor(w.mGlobalScale != 1f ? (1f / w.mGlobalScale) : 1f);
+
+ final int flags = w.getSurfaceTouchableRegion(mTmpRegion, w.mAttrs.flags);
+ inputWindowHandle.setTouchableRegion(mTmpRegion);
+ inputWindowHandle.setLayoutParamsFlags(flags);
+
+ boolean useSurfaceCrop = false;
+ final Task task = w.getTask();
+ if (task != null) {
+ if (task.isOrganized() && task.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
+ // If the window is in a TaskManaged by a TaskOrganizer then most cropping will
+ // be applied using the SurfaceControl hierarchy from the Organizer. This means
+ // we need to make sure that these changes in crop are reflected in the input
+ // windows, and so ensure this flag is set so that the input crop always reflects
+ // the surface hierarchy.
+ // TODO(b/168252846): we have some issues with modal-windows, so we need to cross
+ // that bridge now that we organize full-screen Tasks.
+ inputWindowHandle.setTouchableRegionCrop(null /* Use this surfaces crop */);
+ inputWindowHandle.setReplaceTouchableRegionWithCrop(true);
+ useSurfaceCrop = true;
+ } else if (task.cropWindowsToStackBounds() && !w.inFreeformWindowingMode()) {
+ inputWindowHandle.setTouchableRegionCrop(task.getRootTask().getSurfaceControl());
+ inputWindowHandle.setReplaceTouchableRegionWithCrop(false);
+ useSurfaceCrop = true;
+ }
}
-
- if (child.mGlobalScale != 1) {
- // If we are scaling the window, input coordinates need
- // to be inversely scaled to map from what is on screen
- // to what is actually being touched in the UI.
- inputWindowHandle.scaleFactor = 1.0f/child.mGlobalScale;
- } else {
- inputWindowHandle.scaleFactor = 1;
- }
-
- if (DEBUG_INPUT) {
- Slog.d(TAG_WM, "addInputWindowHandle: "
- + child + ", " + inputWindowHandle);
+ if (!useSurfaceCrop) {
+ inputWindowHandle.setReplaceTouchableRegionWithCrop(false);
+ inputWindowHandle.setTouchableRegionCrop(null);
}
}
@@ -401,15 +403,8 @@ final class InputMonitor {
public void setFocusedAppLw(ActivityRecord newApp) {
// Focused app has changed.
- if (newApp == null) {
- mService.mInputManager.setFocusedApplication(mDisplayId, null);
- } else {
- final InputApplicationHandle handle = newApp.mInputApplicationHandle;
- handle.name = newApp.toString();
- handle.dispatchingTimeoutMillis = newApp.mInputDispatchingTimeoutMillis;
-
- mService.mInputManager.setFocusedApplication(mDisplayId, handle);
- }
+ mService.mInputManager.setFocusedApplication(mDisplayId,
+ newApp != null ? newApp.getInputApplicationHandle(true /* update */) : null);
}
public void pauseDispatchingLw(WindowToken window) {
@@ -456,10 +451,6 @@ final class InputMonitor {
private boolean mAddRecentsAnimationInputConsumerHandle;
boolean mInDrag;
- WallpaperController mWallpaperController;
-
- // An invalid window handle that tells SurfaceFlinger not update the input info.
- final InputWindowHandle mInvalidInputWindow = new InputWindowHandle(null, mDisplayId);
private void updateInputWindows(boolean inDrag) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
@@ -474,10 +465,8 @@ final class InputMonitor {
mAddWallpaperInputConsumerHandle = mWallpaperInputConsumer != null;
mAddRecentsAnimationInputConsumerHandle = mRecentsAnimationInputConsumer != null;
- mTmpRect.setEmpty();
mDisableWallpaperTouchEvents = false;
mInDrag = inDrag;
- mWallpaperController = mDisplayContent.mWallpaperController;
resetInputConsumers(mInputTransaction);
@@ -499,7 +488,7 @@ final class InputMonitor {
}
final WindowState focus = mDisplayContent.mCurrentFocus;
- if (focus == null || focus.mInputWindowHandle.token == null) {
+ if (focus == null || focus.mInputChannelToken == null) {
mDisplayContent.mLastRequestedFocus = focus;
return;
}
@@ -510,7 +499,7 @@ final class InputMonitor {
return;
}
- mInputTransaction.setFocusedWindow(focus.mInputWindowHandle.token, mDisplayId);
+ mInputTransaction.setFocusedWindow(focus.mInputChannelToken, mDisplayId);
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Focus request " + focus, "reason=UpdateInputWindows");
mDisplayContent.mLastRequestedFocus = focus;
@@ -519,33 +508,26 @@ final class InputMonitor {
@Override
public void accept(WindowState w) {
- final InputChannel inputChannel = w.mInputChannel;
- final InputWindowHandle inputWindowHandle = w.mInputWindowHandle;
+ final InputWindowHandleWrapper inputWindowHandle = w.mInputWindowHandle;
final RecentsAnimationController recentsAnimationController =
mService.getRecentsAnimationController();
final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
&& recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord);
- final int type = w.mAttrs.type;
- final boolean isVisible = w.isVisibleLw();
- if (inputChannel == null || inputWindowHandle == null || w.mRemoved
+ if (w.mInputChannelToken == null || w.mRemoved
|| (!w.canReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
if (w.mWinAnimator.hasSurface()) {
// Assign an InputInfo with type to the overlay window which can't receive input
// event. This is used to omit Surfaces from occlusion detection.
- populateOverlayInputInfo(mInvalidInputWindow, w.getName(), type, isVisible);
- mInputTransaction.setInputWindowInfo(
- w.mWinAnimator.mSurfaceController.mSurfaceControl,
- mInvalidInputWindow);
+ populateOverlayInputInfo(inputWindowHandle, w.isVisible());
+ setInputWindowInfoIfNeeded(mInputTransaction,
+ w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
return;
}
// Skip this window because it cannot possibly receive input.
return;
}
- final int flags = w.mAttrs.flags;
final int privateFlags = w.mAttrs.privateFlags;
- final boolean focusable = w.canReceiveKeys()
- && (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
if (recentsAnimationController.updateInputConsumerForApp(
@@ -574,7 +556,7 @@ final class InputMonitor {
}
if (mAddWallpaperInputConsumerHandle) {
- if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisibleLw()) {
+ if (w.mAttrs.type == TYPE_WALLPAPER && w.isVisible()) {
// Add the wallpaper input consumer above the first visible wallpaper.
mWallpaperInputConsumer.show(mInputTransaction, w);
mAddWallpaperInputConsumerHandle = false;
@@ -584,47 +566,53 @@ final class InputMonitor {
if ((privateFlags & PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) {
mDisableWallpaperTouchEvents = true;
}
- final boolean hasWallpaper = mWallpaperController.isWallpaperTarget(w)
- && !mService.mPolicy.isKeyguardShowing()
- && !mDisableWallpaperTouchEvents;
// If there's a drag in progress and 'child' is a potential drop target,
// make sure it's been told about the drag
- if (mInDrag && isVisible && w.getDisplayContent().isDefaultDisplay) {
+ if (mInDrag && w.isVisible() && w.getDisplayContent().isDefaultDisplay) {
mService.mDragDropController.sendDragStartedIfNeededLocked(w);
}
- populateInputWindowHandle(
- inputWindowHandle, w, flags, type, isVisible, focusable, hasWallpaper);
-
// register key interception info
- mService.mKeyInterceptionInfoForToken.put(inputWindowHandle.token,
+ mService.mKeyInterceptionInfoForToken.put(w.mInputChannelToken,
w.getKeyInterceptionInfo());
if (w.mWinAnimator.hasSurface()) {
- mInputTransaction.setInputWindowInfo(
+ populateInputWindowHandle(inputWindowHandle, w);
+ setInputWindowInfoIfNeeded(mInputTransaction,
w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
}
}
}
+ @VisibleForTesting
+ static void setInputWindowInfoIfNeeded(SurfaceControl.Transaction t, SurfaceControl sc,
+ InputWindowHandleWrapper inputWindowHandle) {
+ if (DEBUG_INPUT) {
+ Slog.d(TAG_WM, "Update InputWindowHandle: " + inputWindowHandle);
+ }
+ if (inputWindowHandle.isChanged()) {
+ inputWindowHandle.applyChangesToSurface(t, sc);
+ }
+ }
+
// This would reset InputWindowHandle fields to prevent it could be found by input event.
// We need to check if any new field of InputWindowHandle could impact the result.
- private static void populateOverlayInputInfo(final InputWindowHandle inputWindowHandle,
- final String name, final int type, final boolean isVisible) {
- inputWindowHandle.name = name;
- inputWindowHandle.layoutParamsType = type;
- inputWindowHandle.dispatchingTimeoutMillis = 0; // it should never receive input
- inputWindowHandle.visible = isVisible;
- inputWindowHandle.focusable = false;
- inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
- inputWindowHandle.scaleFactor = 1;
- inputWindowHandle.layoutParamsFlags =
- FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE;
- inputWindowHandle.portalToDisplayId = INVALID_DISPLAY;
- inputWindowHandle.touchableRegion.setEmpty();
+ @VisibleForTesting
+ static void populateOverlayInputInfo(InputWindowHandleWrapper inputWindowHandle,
+ boolean isVisible) {
+ inputWindowHandle.setDispatchingTimeoutMillis(0); // It should never receive input.
+ inputWindowHandle.setVisible(isVisible);
+ inputWindowHandle.setFocusable(false);
+ inputWindowHandle.setInputFeatures(INPUT_FEATURE_NO_INPUT_CHANNEL);
+ // The input window handle without input channel must not have a token.
+ inputWindowHandle.setToken(null);
+ inputWindowHandle.setScaleFactor(1f);
+ inputWindowHandle.setLayoutParamsFlags(
+ FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE);
+ inputWindowHandle.setPortalToDisplayId(INVALID_DISPLAY);
+ inputWindowHandle.clearTouchableRegion();
inputWindowHandle.setTouchableRegionCrop(null);
- inputWindowHandle.trustedOverlay = isTrustedOverlay(type);
}
/**
@@ -635,9 +623,13 @@ final class InputMonitor {
*/
static void setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t,
int displayId, String name) {
- InputWindowHandle inputWindowHandle = new InputWindowHandle(null, displayId);
- populateOverlayInputInfo(inputWindowHandle, name, TYPE_SECURE_SYSTEM_OVERLAY, true);
- t.setInputWindowInfo(sc, inputWindowHandle);
+ final InputWindowHandleWrapper inputWindowHandle = new InputWindowHandleWrapper(
+ new InputWindowHandle(null /* inputApplicationHandle */, displayId));
+ inputWindowHandle.setName(name);
+ inputWindowHandle.setLayoutParamsType(TYPE_SECURE_SYSTEM_OVERLAY);
+ inputWindowHandle.setTrustedOverlay(true);
+ populateOverlayInputInfo(inputWindowHandle, true /* isVisible */);
+ setInputWindowInfoIfNeeded(t, sc, inputWindowHandle);
}
static boolean isTrustedOverlay(int type) {
diff --git a/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
new file mode 100644
index 000000000000..9339f3475684
--- /dev/null
+++ b/services/core/java/com/android/server/wm/InputWindowHandleWrapper.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Region;
+import android.os.IBinder;
+import android.view.InputApplicationHandle;
+import android.view.InputWindowHandle;
+import android.view.SurfaceControl;
+
+import java.util.Objects;
+
+/**
+ * The wrapper of {@link InputWindowHandle} with field change detection to reduce unnecessary
+ * updates to surface, e.g. if there are no changes, then skip invocation of
+ * {@link SurfaceControl.Transaction#setInputWindowInfo(SurfaceControl, InputWindowHandle)}.
+ */
+class InputWindowHandleWrapper {
+ /** The wrapped handle should not be directly exposed to avoid untracked changes. */
+ private final @NonNull InputWindowHandle mHandle;
+
+ /** Whether the {@link #mHandle} is changed. */
+ private boolean mChanged = true;
+
+ InputWindowHandleWrapper(@NonNull InputWindowHandle handle) {
+ mHandle = handle;
+ }
+
+ /**
+ * Returns {@code true} if the input window handle has changed since the last invocation of
+ * {@link #applyChangesToSurface(SurfaceControl.Transaction, SurfaceControl)}}
+ */
+ boolean isChanged() {
+ return mChanged;
+ }
+
+ void forceChange() {
+ mChanged = true;
+ }
+
+ void applyChangesToSurface(@NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl sc) {
+ t.setInputWindowInfo(sc, mHandle);
+ mChanged = false;
+ }
+
+ int getDisplayId() {
+ return mHandle.displayId;
+ }
+
+ InputApplicationHandle getInputApplicationHandle() {
+ return mHandle.inputApplicationHandle;
+ }
+
+ void setInputApplicationHandle(InputApplicationHandle handle) {
+ if (mHandle.inputApplicationHandle == handle) {
+ return;
+ }
+ mHandle.inputApplicationHandle = handle;
+ mChanged = true;
+ }
+
+ void setToken(IBinder token) {
+ if (mHandle.token == token) {
+ return;
+ }
+ mHandle.token = token;
+ mChanged = true;
+ }
+
+ void setName(String name) {
+ if (Objects.equals(mHandle.name, name)) {
+ return;
+ }
+ mHandle.name = name;
+ mChanged = true;
+ }
+
+ void setLayoutParamsFlags(int flags) {
+ if (mHandle.layoutParamsFlags == flags) {
+ return;
+ }
+ mHandle.layoutParamsFlags = flags;
+ mChanged = true;
+ }
+
+ void setLayoutParamsType(int type) {
+ if (mHandle.layoutParamsType == type) {
+ return;
+ }
+ mHandle.layoutParamsType = type;
+ mChanged = true;
+ }
+
+ void setDispatchingTimeoutMillis(long timeout) {
+ if (mHandle.dispatchingTimeoutMillis == timeout) {
+ return;
+ }
+ mHandle.dispatchingTimeoutMillis = timeout;
+ mChanged = true;
+ }
+
+ void setTouchableRegion(Region region) {
+ if (mHandle.touchableRegion.equals(region)) {
+ return;
+ }
+ mHandle.touchableRegion.set(region);
+ mChanged = true;
+ }
+
+ void clearTouchableRegion() {
+ if (mHandle.touchableRegion.isEmpty()) {
+ return;
+ }
+ mHandle.touchableRegion.setEmpty();
+ mChanged = true;
+ }
+
+ void setVisible(boolean visible) {
+ if (mHandle.visible == visible) {
+ return;
+ }
+ mHandle.visible = visible;
+ mChanged = true;
+ }
+
+ void setFocusable(boolean focusable) {
+ if (mHandle.focusable == focusable) {
+ return;
+ }
+ mHandle.focusable = focusable;
+ mChanged = true;
+ }
+
+ void setTouchOcclusionMode(int mode) {
+ if (mHandle.touchOcclusionMode == mode) {
+ return;
+ }
+ mHandle.touchOcclusionMode = mode;
+ mChanged = true;
+ }
+
+ void setHasWallpaper(boolean hasWallpaper) {
+ if (mHandle.hasWallpaper == hasWallpaper) {
+ return;
+ }
+ mHandle.hasWallpaper = hasWallpaper;
+ mChanged = true;
+ }
+
+ void setPaused(boolean paused) {
+ if (mHandle.paused == paused) {
+ return;
+ }
+ mHandle.paused = paused;
+ mChanged = true;
+ }
+
+ void setTrustedOverlay(boolean trustedOverlay) {
+ if (mHandle.trustedOverlay == trustedOverlay) {
+ return;
+ }
+ mHandle.trustedOverlay = trustedOverlay;
+ mChanged = true;
+ }
+
+ void setOwnerPid(int pid) {
+ if (mHandle.ownerPid == pid) {
+ return;
+ }
+ mHandle.ownerPid = pid;
+ mChanged = true;
+ }
+
+ void setOwnerUid(int uid) {
+ if (mHandle.ownerUid == uid) {
+ return;
+ }
+ mHandle.ownerUid = uid;
+ mChanged = true;
+ }
+
+ void setPackageName(String packageName) {
+ if (Objects.equals(mHandle.packageName, packageName)) {
+ return;
+ }
+ mHandle.packageName = packageName;
+ mChanged = true;
+ }
+
+ void setInputFeatures(int features) {
+ if (mHandle.inputFeatures == features) {
+ return;
+ }
+ mHandle.inputFeatures = features;
+ mChanged = true;
+ }
+
+ void setDisplayId(int displayId) {
+ if (mHandle.displayId == displayId) {
+ return;
+ }
+ mHandle.displayId = displayId;
+ mChanged = true;
+ }
+
+ void setPortalToDisplayId(int displayId) {
+ if (mHandle.portalToDisplayId == displayId) {
+ return;
+ }
+ mHandle.portalToDisplayId = displayId;
+ mChanged = true;
+ }
+
+ void setFrame(int left, int top, int right, int bottom) {
+ if (mHandle.frameLeft == left && mHandle.frameTop == top && mHandle.frameRight == right
+ && mHandle.frameBottom == bottom) {
+ return;
+ }
+ mHandle.frameLeft = left;
+ mHandle.frameTop = top;
+ mHandle.frameRight = right;
+ mHandle.frameBottom = bottom;
+ mChanged = true;
+ }
+
+ void setSurfaceInset(int inset) {
+ if (mHandle.surfaceInset == inset) {
+ return;
+ }
+ mHandle.surfaceInset = inset;
+ mChanged = true;
+ }
+
+ void setScaleFactor(float scale) {
+ if (mHandle.scaleFactor == scale) {
+ return;
+ }
+ mHandle.scaleFactor = scale;
+ mChanged = true;
+ }
+
+ void setTouchableRegionCrop(@Nullable SurfaceControl bounds) {
+ if (mHandle.touchableRegionSurfaceControl.get() == bounds) {
+ return;
+ }
+ mHandle.setTouchableRegionCrop(bounds);
+ mChanged = true;
+ }
+
+ void setReplaceTouchableRegionWithCrop(boolean replace) {
+ if (mHandle.replaceTouchableRegionWithCrop == replace) {
+ return;
+ }
+ mHandle.replaceTouchableRegionWithCrop = replace;
+ mChanged = true;
+ }
+
+ @Override
+ public String toString() {
+ return mHandle + ", changed=" + mChanged;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index e83151dae161..a82133da1b34 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -151,6 +151,7 @@ class InsetsSourceProvider {
// TODO: Ideally, we should wait for the animation to finish so previous window can
// animate-out as new one animates-in.
mWin.cancelAnimation();
+ mWin.mPendingPositionChanged = null;
}
ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
mWin = win;
@@ -181,7 +182,9 @@ class InsetsSourceProvider {
* window gets laid out.
*/
void updateSourceFrame() {
- if (mWin == null) {
+ if (mWin == null || mWin.mGivenInsetsPending) {
+ // If the given insets are pending, they are not reliable for now. The source frame
+ // should be updated after the new given insets are sent to window manager.
return;
}
@@ -238,19 +241,45 @@ class InsetsSourceProvider {
return;
}
- setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy()
- && !mWin.mGivenInsetsPending);
+ setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy());
updateSourceFrame();
if (mControl != null) {
final Rect frame = mWin.getWindowFrames().mFrame;
if (mControl.setSurfacePosition(frame.left, frame.top) && mControlTarget != null) {
- // The leash has been stale, we need to create a new one for the client.
- updateControlForTarget(mControlTarget, true /* force */);
+ if (!mWin.getWindowFrames().didFrameSizeChange()) {
+ updateLeashPosition(frame, -1 /* frameNumber */);
+ } else if (mWin.mInRelayout) {
+ updateLeashPosition(frame, mWin.getFrameNumber());
+ } else {
+ mWin.mPendingPositionChanged = this;
+ }
mStateController.notifyControlChanged(mControlTarget);
}
}
}
+ void updateLeashPosition(Rect frame, long frameNumber) {
+ if (mControl == null) {
+ return;
+ }
+ final SurfaceControl leash = mControl.getLeash();
+ if (leash != null) {
+ final Transaction t = mDisplayContent.getPendingTransaction();
+ Point position = new Point();
+ mWin.transformFrameToSurfacePosition(frame.left, frame.top, position);
+ t.setPosition(leash, position.x, position.y);
+ deferTransactionUntil(t, leash, frameNumber);
+ }
+ }
+
+ private void deferTransactionUntil(Transaction t, SurfaceControl leash, long frameNumber) {
+ if (frameNumber >= 0) {
+ final SurfaceControl barrier = mWin.getClientViewRootSurface();
+ t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
+ t.deferTransactionUntil(leash, barrier, frameNumber);
+ }
+ }
+
/**
* @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget)
*/
@@ -305,14 +334,12 @@ class InsetsSourceProvider {
final SurfaceControl leash = mAdapter.mCapturedLeash;
final long frameNumber = mFinishSeamlessRotateFrameNumber;
mFinishSeamlessRotateFrameNumber = -1;
- if (frameNumber >= 0 && mWin.mHasSurface && leash != null) {
+ if (mWin.mHasSurface && leash != null) {
// We just finished the seamless rotation. We don't want to change the position or the
// 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.getClientViewRootSurface();
- t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
- t.deferTransactionUntil(leash, barrier, frameNumber);
+ deferTransactionUntil(t, leash, frameNumber);
}
mControlTarget = target;
updateVisibility();
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index e7f140f989cc..9d70fd771f31 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
@@ -35,6 +36,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
import android.app.WindowConfiguration.WindowingMode;
+import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -191,6 +193,8 @@ class InsetsStateController {
state.removeSource(ITYPE_STATUS_BAR);
state.removeSource(ITYPE_CLIMATE_BAR);
state.removeSource(ITYPE_CAPTION_BAR);
+ state.removeSource(ITYPE_NAVIGATION_BAR);
+ state.removeSource(ITYPE_EXTRA_NAVIGATION_BAR);
}
// Status bar doesn't get influenced by caption bar
@@ -281,6 +285,7 @@ class InsetsStateController {
* Called when a layout pass has occurred.
*/
void onPostLayout() {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "ISC.onPostLayout");
for (int i = mProviders.size() - 1; i >= 0; i--) {
mProviders.valueAt(i).onPostLayout();
}
@@ -297,6 +302,7 @@ class InsetsStateController {
}
}
winInsetsChanged.clear();
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
void onInsetsModified(InsetsControlTarget caller) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 79b88d87f268..9068bb75f405 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -92,6 +92,10 @@ class KeyguardController {
mRootWindowContainer = mService.mRootWindowContainer;
}
+ boolean isAodShowing() {
+ return mAodShowing;
+ }
+
/**
* @return true if either Keyguard or AOD are showing, not going away, and not being occluded
* on the given display, false otherwise.
@@ -163,11 +167,15 @@ class KeyguardController {
"setKeyguardShown");
mKeyguardShowing = keyguardShowing;
mAodShowing = aodShowing;
- mWindowManager.setAodShowing(aodShowing);
+ if (aodChanged) {
+ // Ensure the new state takes effect.
+ mWindowManager.mWindowPlacerLocked.performSurfacePlacement();
+ }
if (keyguardChanged) {
// Irrelevant to AOD.
- dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */);
+ dismissMultiWindowModeForTaskIfNeeded(null /* currentTaskControllsingOcclusion */,
+ false /* turningScreenOn */);
setKeyguardGoingAway(false);
if (keyguardShowing) {
mDismissalRequested = false;
@@ -369,7 +377,6 @@ class KeyguardController {
mService.continueWindowLayout();
}
}
- dismissMultiWindowModeForTaskIfNeeded(currentTaskControllingOcclusion);
}
/**
@@ -398,6 +405,21 @@ class KeyguardController {
}
}
+ /**
+ * Called when somebody wants to turn screen on.
+ */
+ private void handleTurnScreenOn(int displayId) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+
+ mStackSupervisor.wakeUp("handleTurnScreenOn");
+ if (mKeyguardShowing && canDismissKeyguard()) {
+ mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
+ mDismissalRequested = true;
+ }
+ }
+
boolean isDisplayOccluded(int displayId) {
return getDisplayState(displayId).mOccluded;
}
@@ -433,14 +455,15 @@ class KeyguardController {
}
private void dismissMultiWindowModeForTaskIfNeeded(
- @Nullable Task currentTaskControllingOcclusion) {
+ @Nullable Task currentTaskControllingOcclusion, boolean turningScreenOn) {
+ // If turningScreenOn is true, it means that the visibility state has changed from
+ // currentTaskControllingOcclusion and we should update windowing mode.
// TODO(b/113840485): Handle docked stack for individual display.
- if (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY)) {
+ if (!turningScreenOn && (!mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY))) {
return;
}
// Dismiss split screen
-
// The lock screen is currently showing, but is occluded by a window that can
// show on top of the lock screen. In this can we want to dismiss the docked
// stack since it will be complicated/risky to try to put the activity on top
@@ -579,17 +602,26 @@ class KeyguardController {
&& controller.mWindowManager.isKeyguardSecure(
controller.mService.getCurrentUserId());
+ boolean occludingChange = false;
+ boolean turningScreenOn = false;
if (mTopTurnScreenOnActivity != lastTurnScreenOnActivity
&& mTopTurnScreenOnActivity != null
&& !mService.mWindowManager.mPowerManager.isInteractive()
- && (mRequestDismissKeyguard || occludedByActivity)) {
- controller.mStackSupervisor.wakeUp("handleTurnScreenOn");
+ && (mRequestDismissKeyguard || occludedByActivity
+ || controller.canDismissKeyguard())) {
+ turningScreenOn = true;
+ controller.handleTurnScreenOn(mDisplayId);
mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
}
if (lastOccluded != mOccluded) {
+ occludingChange = true;
controller.handleOccludedChanged(mDisplayId, task);
}
+
+ if (occludingChange || turningScreenOn) {
+ controller.dismissMultiWindowModeForTaskIfNeeded(task, turningScreenOn);
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index b33c2f2823a5..5b7b5a122b42 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -24,6 +24,8 @@ import static android.content.Context.DEVICE_POLICY_SERVICE;
import static android.content.Context.STATUS_BAR_SERVICE;
import static android.content.Intent.ACTION_CALL_EMERGENCY;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_CURRENT;
@@ -33,11 +35,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_ALLOWLISTED;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_PINNABLE;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -129,6 +126,18 @@ public class LockTaskController {
/** Tag used for disabling of keyguard */
private static final String LOCK_TASK_TAG = "Lock-to-App";
+ /** Can't be put in lockTask mode. */
+ static final int LOCK_TASK_AUTH_DONT_LOCK = 0;
+ /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
+ static final int LOCK_TASK_AUTH_PINNABLE = 1;
+ /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
+ static final int LOCK_TASK_AUTH_LAUNCHABLE = 2;
+ /** Can enter lockTask without user approval. Can start over existing lockTask task. */
+ static final int LOCK_TASK_AUTH_ALLOWLISTED = 3;
+ /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
+ * lockTask task. */
+ static final int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
+
private final IBinder mToken = new LockTaskToken();
private final ActivityStackSupervisor mSupervisor;
private final Context mContext;
@@ -265,11 +274,10 @@ public class LockTaskController {
}
/**
- * @return whether the requested task is allowed to be locked (either allowlisted, or declares
- * lockTaskMode="always" in the manifest).
+ * @return whether the requested task auth is allowed to be locked.
*/
- boolean isTaskAllowlisted(Task task) {
- switch(task.mLockTaskAuth) {
+ static boolean isTaskAuthAllowlisted(int lockTaskAuth) {
+ switch(lockTaskAuth) {
case LOCK_TASK_AUTH_ALLOWLISTED:
case LOCK_TASK_AUTH_LAUNCHABLE:
case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
@@ -293,7 +301,30 @@ public class LockTaskController {
* @return whether the requested task is disallowed to be launched.
*/
boolean isLockTaskModeViolation(Task task, boolean isNewClearTask) {
- if (isLockTaskModeViolationInternal(task, isNewClearTask)) {
+ // TODO: Double check what's going on here. If the task is already in lock task mode, it's
+ // likely allowlisted, so will return false below.
+ if (isTaskLocked(task) && !isNewClearTask) {
+ // If the task is already at the top and won't be cleared, then allow the operation
+ } else if (isLockTaskModeViolationInternal(task, task.mUserId, task.intent,
+ task.mLockTaskAuth)) {
+ showLockTaskToast();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param activity an activity that is going to be started in a new task as the root activity.
+ * @return whether the given activity is allowed to be launched.
+ */
+ boolean isNewTaskLockTaskModeViolation(ActivityRecord activity) {
+ // Use the belong task (if any) to perform the lock task checks
+ if (activity.getTask() != null) {
+ return isLockTaskModeViolation(activity.getTask());
+ }
+
+ int auth = getLockTaskAuth(activity, null /* task */);
+ if (isLockTaskModeViolationInternal(activity, activity.mUserId, activity.intent, auth)) {
showLockTaskToast();
return true;
}
@@ -310,25 +341,19 @@ public class LockTaskController {
return mLockTaskModeTasks.get(0);
}
- private boolean isLockTaskModeViolationInternal(Task task, boolean isNewClearTask) {
- // TODO: Double check what's going on here. If the task is already in lock task mode, it's
- // likely allowlisted, so will return false below.
- if (isTaskLocked(task) && !isNewClearTask) {
- // If the task is already at the top and won't be cleared, then allow the operation
- return false;
- }
-
+ private boolean isLockTaskModeViolationInternal(WindowContainer wc, int userId,
+ Intent intent, int taskAuth) {
// Allow recents activity if enabled by policy
- if (task.isActivityTypeRecents() && isRecentsAllowed(task.mUserId)) {
+ if (wc.isActivityTypeRecents() && isRecentsAllowed(userId)) {
return false;
}
// Allow emergency calling when the device is protected by a locked keyguard
- if (isKeyguardAllowed(task.mUserId) && isEmergencyCallTask(task)) {
+ if (isKeyguardAllowed(userId) && isEmergencyCallIntent(intent)) {
return false;
}
- return !(isTaskAllowlisted(task) || mLockTaskModeTasks.isEmpty());
+ return !(isTaskAuthAllowlisted(taskAuth) || mLockTaskModeTasks.isEmpty());
}
private boolean isRecentsAllowed(int userId) {
@@ -360,8 +385,7 @@ public class LockTaskController {
return isPackageAllowlisted(userId, packageName);
}
- private boolean isEmergencyCallTask(Task task) {
- final Intent intent = task.intent;
+ private boolean isEmergencyCallIntent(Intent intent) {
if (intent == null) {
return false;
}
@@ -697,6 +721,40 @@ public class LockTaskController {
}
}
+ int getLockTaskAuth(@Nullable ActivityRecord rootActivity, @Nullable Task task) {
+ if (rootActivity == null && task == null) {
+ return LOCK_TASK_AUTH_DONT_LOCK;
+ }
+ if (rootActivity == null) {
+ return LOCK_TASK_AUTH_PINNABLE;
+ }
+
+ final String pkg = (task == null || task.realActivity == null) ? null
+ : task.realActivity.getPackageName();
+ final int userId = task != null ? task.mUserId : rootActivity.mUserId;
+ int lockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
+ switch (rootActivity.lockTaskLaunchMode) {
+ case LOCK_TASK_LAUNCH_MODE_DEFAULT:
+ lockTaskAuth = isPackageAllowlisted(userId, pkg)
+ ? LOCK_TASK_AUTH_ALLOWLISTED : LOCK_TASK_AUTH_PINNABLE;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_NEVER:
+ lockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_ALWAYS:
+ lockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+ break;
+
+ case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
+ lockTaskAuth = isPackageAllowlisted(userId, pkg)
+ ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
+ break;
+ }
+ return lockTaskAuth;
+ }
+
boolean isPackageAllowlisted(int userId, String pkg) {
if (pkg == null) {
return false;
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 0503c0de5195..45cd35977168 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -658,8 +658,8 @@ class RecentTasks {
}
for (int i = mTasks.size() - 1; i >= 0; --i) {
final Task task = mTasks.get(i);
- if (task.mUserId == userId
- && !mService.getLockTaskController().isTaskAllowlisted(task)) {
+ if (task.mUserId == userId && !mService.getLockTaskController().isTaskAuthAllowlisted(
+ task.mLockTaskAuth)) {
remove(task);
}
}
@@ -1874,11 +1874,23 @@ class RecentTasks {
* Creates a new RecentTaskInfo from a Task.
*/
ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras) {
- ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
+ final ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
tr.fillTaskInfo(rti, stripExtras);
- // Fill in some deprecated values
+ // Fill in some deprecated values.
rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
rti.persistentId = rti.taskId;
+
+ // Fill in organized child task info for the task created by organizer.
+ if (tr.mCreatedByOrganizer) {
+ for (int i = tr.getChildCount() - 1; i >= 0; i--) {
+ final Task childTask = tr.getChildAt(i).asTask();
+ if (childTask != null && childTask.isOrganized()) {
+ final ActivityManager.RecentTaskInfo cti = new ActivityManager.RecentTaskInfo();
+ childTask.fillTaskInfo(cti);
+ rti.childrenTaskInfos.add(cti);
+ }
+ }
+ }
return rti;
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 757c57f94a36..3200bbc90de1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -59,7 +59,7 @@ import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityStackSupervisor.dumpHistoryList;
import static com.android.server.wm.ActivityStackSupervisor.printThisActivity;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
@@ -76,9 +76,9 @@ import static com.android.server.wm.Task.ActivityState.PAUSED;
import static com.android.server.wm.Task.ActivityState.RESUMED;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
-import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
-import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
-import static com.android.server.wm.Task.STACK_VISIBILITY_INVISIBLE;
+import static com.android.server.wm.Task.REPARENT_LEAVE_ROOT_TASK_IN_PLACE;
+import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
+import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
@@ -232,20 +232,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
- MATCH_TASK_IN_STACKS_ONLY,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
+ MATCH_ATTACHED_TASK_ONLY,
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS,
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE
})
public @interface AnyTaskForIdMatchTaskMode {
}
- // Match only tasks in the current stacks
- static final int MATCH_TASK_IN_STACKS_ONLY = 0;
- // Match either tasks in the current stacks, or in the recent tasks if not found in the stacks
- static final int MATCH_TASK_IN_STACKS_OR_RECENT_TASKS = 1;
- // Match either tasks in the current stacks, or in the recent tasks, restoring it to the
- // provided stack id
- static final int MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE = 2;
+ // Match only tasks that are attached to the hierarchy
+ static final int MATCH_ATTACHED_TASK_ONLY = 0;
+ // Match either attached tasks, or in the recent tasks if the tasks are detached
+ static final int MATCH_ATTACHED_TASK_OR_RECENT_TASKS = 1;
+ // Match either attached tasks, or in the recent tasks, restoring it to the provided task id
+ static final int MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE = 2;
ActivityTaskManagerService mService;
ActivityStackSupervisor mStackSupervisor;
@@ -707,7 +706,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
boolean canShowStrictModeViolation(int pid) {
- final WindowState win = getWindow((w) -> w.mSession.mPid == pid && w.isVisibleLw());
+ final WindowState win = getWindow((w) -> w.mSession.mPid == pid && w.isVisible());
return win != null;
}
@@ -1813,7 +1812,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// Passing null here for 'starting' param value, so that visibility of actual starting
// activity will be properly updated.
ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
- false /* preserveWindows */, false /* notifyClients */);
+ false /* preserveWindows */, false /* notifyClients */,
+ mStackSupervisor.mUserLeaving);
if (displayId == INVALID_DISPLAY) {
// The caller didn't provide a valid display id, skip updating config.
@@ -1953,7 +1953,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
for (int taskNdx = displayArea.getStackCount() - 1; taskNdx >= 0; --taskNdx) {
final Task rootTask = displayArea.getStackAt(taskNdx);
- if (rootTask.getVisibility(null /*starting*/) == STACK_VISIBILITY_INVISIBLE) {
+ if (rootTask.getVisibility(null /*starting*/) == TASK_VISIBILITY_INVISIBLE) {
break;
}
@@ -2006,14 +2006,15 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
*/
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
boolean preserveWindows) {
- ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */);
+ ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */,
+ mStackSupervisor.mUserLeaving);
}
/**
* @see #ensureActivitiesVisible(ActivityRecord, int, boolean)
*/
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients) {
+ boolean preserveWindows, boolean notifyClients, boolean userLeaving) {
if (mStackSupervisor.inActivityVisibilityUpdate()) {
// Don't do recursive work.
return;
@@ -2025,7 +2026,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
display.ensureActivitiesVisible(starting, configChanges, preserveWindows,
- notifyClients);
+ notifyClients, userLeaving);
}
} finally {
mStackSupervisor.endActivityVisibilityUpdate();
@@ -2556,7 +2557,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
@Override
public void onDisplayAdded(int displayId) {
- if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
+ if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display added displayId=" + displayId);
synchronized (mService.mGlobalLock) {
final DisplayContent display = getDisplayContentOrCreate(displayId);
if (display == null) {
@@ -2578,7 +2579,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
@Override
public void onDisplayRemoved(int displayId) {
- if (DEBUG_STACK) Slog.v(TAG, "Display removed displayId=" + displayId);
+ if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display removed displayId=" + displayId);
if (displayId == DEFAULT_DISPLAY) {
throw new IllegalArgumentException("Can't remove the primary display.");
}
@@ -2595,7 +2596,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
@Override
public void onDisplayChanged(int displayId) {
- if (DEBUG_STACK) Slog.v(TAG, "Display changed displayId=" + displayId);
+ if (DEBUG_ROOT_TASK) Slog.v(TAG, "Display changed displayId=" + displayId);
synchronized (mService.mGlobalLock) {
final DisplayContent displayContent = getDisplayContent(displayId);
if (displayContent != null) {
@@ -2888,7 +2889,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// Temporarily set the task id to invalid in case in re-entry.
options.setLaunchTaskId(INVALID_TASK_ID);
final Task task = anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options, onTop);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, options, onTop);
options.setLaunchTaskId(taskId);
if (task != null) {
return task.getRootTask();
@@ -3444,7 +3445,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
Task anyTaskForId(int id) {
- return anyTaskForId(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE);
+ return anyTaskForId(id, MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE);
}
Task anyTaskForId(int id, @RootWindowContainer.AnyTaskForIdMatchTaskMode int matchMode) {
@@ -3462,7 +3463,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
Task anyTaskForId(int id, @RootWindowContainer.AnyTaskForIdMatchTaskMode int matchMode,
@Nullable ActivityOptions aOptions, boolean onTop) {
// If options are set, ensure that we are attempting to actually restore a task
- if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) {
+ if (matchMode != MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) {
throw new IllegalArgumentException("Should not specify activity options for non-restore"
+ " lookup");
}
@@ -3480,7 +3481,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
getLaunchStack(null, aOptions, task, onTop);
if (launchStack != null && task.getRootTask() != launchStack) {
final int reparentMode = onTop
- ? REPARENT_MOVE_STACK_TO_FRONT : REPARENT_LEAVE_STACK_IN_PLACE;
+ ? REPARENT_MOVE_ROOT_TASK_TO_FRONT : REPARENT_LEAVE_ROOT_TASK_IN_PLACE;
task.reparent(launchStack, onTop, reparentMode, ANIMATE, DEFER_RESUME,
"anyTaskForId");
}
@@ -3489,7 +3490,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
// If we are matching stack tasks only, return now
- if (matchMode == MATCH_TASK_IN_STACKS_ONLY) {
+ if (matchMode == MATCH_ATTACHED_TASK_ONLY) {
return null;
}
@@ -3506,11 +3507,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return null;
}
- if (matchMode == MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) {
+ if (matchMode == MATCH_ATTACHED_TASK_OR_RECENT_TASKS) {
return task;
}
- // Implicitly, this case is MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
+ // Implicitly, this case is MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE
if (!mStackSupervisor.restoreRecentTaskLocked(task, aOptions, onTop)) {
if (DEBUG_RECENTS) {
Slog.w(TAG_RECENTS,
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 6fbd35164874..b46e796698e4 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -24,6 +24,7 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.Intent.EXTRA_SHORTCUT_ID;
import static android.content.Intent.EXTRA_TASK_ID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -43,6 +44,7 @@ import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ShortcutServiceInternal;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
@@ -288,7 +290,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
// Validate and resolve ClipDescription data before clearing the calling identity
- validateAndResolveDragMimeTypeExtras(data, Binder.getCallingUid());
+ validateAndResolveDragMimeTypeExtras(data, Binder.getCallingUid(), Binder.getCallingPid(),
+ mPackageName);
final long ident = Binder.clearCallingIdentity();
try {
return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource,
@@ -302,8 +305,9 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
* Validates the given drag data.
*/
@VisibleForTesting
- public void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid) {
- if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+ void validateAndResolveDragMimeTypeExtras(ClipData data, int callingUid, int callingPid,
+ String callingPackage) {
+ if (callingUid == Process.SYSTEM_UID) {
throw new IllegalStateException("Need to validate before calling identify is cleared");
}
final ClipDescription desc = data != null ? data.getDescription() : null;
@@ -358,26 +362,58 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
Binder.restoreCallingIdentity(origId);
}
} else if (hasShortcut) {
+ // Restrict who can start a shortcut drag since it will start the shortcut as the
+ // target shortcut package
mService.mAtmService.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
"performDrag");
for (int i = 0; i < data.getItemCount(); i++) {
- final Intent intent = data.getItemAt(i).getIntent();
+ final ClipData.Item item = data.getItemAt(i);
+ final Intent intent = item.getIntent();
+ final String shortcutId = intent.getStringExtra(EXTRA_SHORTCUT_ID);
+ final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
- if (!intent.hasExtra(EXTRA_SHORTCUT_ID)
- || TextUtils.isEmpty(intent.getStringExtra(EXTRA_SHORTCUT_ID))
+ if (TextUtils.isEmpty(shortcutId)
+ || TextUtils.isEmpty(packageName)
|| user == null) {
- throw new IllegalArgumentException("Clip item must include the shortcut id and "
- + "the user to launch for.");
+ throw new IllegalArgumentException("Clip item must include the package name, "
+ + "shortcut id, and the user to launch for.");
}
+ final ShortcutServiceInternal shortcutService =
+ LocalServices.getService(ShortcutServiceInternal.class);
+ final Intent[] shortcutIntents = shortcutService.createShortcutIntents(
+ callingUid, callingPackage, packageName, shortcutId,
+ user.getIdentifier(), callingPid, callingUid);
+ if (shortcutIntents == null || shortcutIntents.length == 0) {
+ throw new IllegalArgumentException("Invalid shortcut id");
+ }
+ final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
+ shortcutIntents[0], null /* resolvedType */, user.getIdentifier(),
+ callingUid);
+ item.setActivityInfo(info);
}
} else if (hasTask) {
+ // TODO(b/169894807): Consider opening this up for tasks from the same app as the caller
mService.mAtmService.enforceCallerIsRecentsOrHasPermission(START_TASKS_FROM_RECENTS,
"performDrag");
for (int i = 0; i < data.getItemCount(); i++) {
- final Intent intent = data.getItemAt(i).getIntent();
- if (intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID) == INVALID_TASK_ID) {
+ final ClipData.Item item = data.getItemAt(i);
+ final Intent intent = item.getIntent();
+ final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
+ if (taskId == INVALID_TASK_ID) {
throw new IllegalArgumentException("Clip item must include the task id.");
}
+ final Task task = mService.mRoot.anyTaskForId(taskId);
+ if (task == null) {
+ throw new IllegalArgumentException("Invalid task id.");
+ }
+ if (task.getRootActivity() != null) {
+ item.setActivityInfo(task.getRootActivity().info);
+ } else {
+ // Resolve the activity info manually if the task was restored after reboot
+ final ActivityInfo info = mService.mAtmService.resolveActivityInfoForIntent(
+ task.intent, null /* resolvedType */, task.mUserId, callingUid);
+ item.setActivityInfo(info);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/SplashScreenStartingData.java b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
index 726b7dac6938..50a101d58ce3 100644
--- a/services/core/java/com/android/server/wm/SplashScreenStartingData.java
+++ b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
@@ -53,8 +53,9 @@ class SplashScreenStartingData extends StartingData {
@Override
StartingSurface createStartingSurface(ActivityRecord activity) {
- return mService.mPolicy.addSplashScreen(activity.token, mPkg, mTheme, mCompatInfo,
- mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags,
- mMergedOverrideConfiguration, activity.getDisplayContent().getDisplayId());
+ return mService.mStartingSurfaceController.createSplashScreenStartingSurface(
+ activity, mPkg, mTheme, mCompatInfo, mNonLocalizedLabel, mLabelRes, mIcon,
+ mLogo, mWindowFlags, mMergedOverrideConfiguration,
+ activity.getDisplayContent().getDisplayId());
}
}
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
new file mode 100644
index 000000000000..6d7ddf607ffe
--- /dev/null
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.os.SystemProperties;
+
+import com.android.server.policy.WindowManagerPolicy.StartingSurface;
+
+/**
+ * Managing to create and release a starting window surface.
+ */
+public class StartingSurfaceController {
+
+ /** Set to {@code true} to enable shell starting surface drawer. */
+ private static final boolean DEBUG_ENABLE_SHELL_DRAWER =
+ SystemProperties.getBoolean("persist.debug.shell_starting_surface", false);
+
+ private final WindowManagerService mService;
+
+ public StartingSurfaceController(WindowManagerService wm) {
+ mService = wm;
+ }
+
+ StartingSurface createSplashScreenStartingSurface(ActivityRecord activity, String packageName,
+ int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
+ int icon, int logo, int windowFlags, Configuration overrideConfig, int displayId) {
+ if (!DEBUG_ENABLE_SHELL_DRAWER) {
+ return mService.mPolicy.addSplashScreen(activity.token, packageName, theme,
+ compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
+ overrideConfig, displayId);
+ }
+
+ final Task task = activity.getTask();
+ if (task != null && mService.mAtmService.mTaskOrganizerController.addStartingWindow(task,
+ activity.token)) {
+ return new SplashScreenContainerSurface(task);
+ }
+ return null;
+ }
+
+ private final class SplashScreenContainerSurface implements StartingSurface {
+ private final Task mTask;
+
+ SplashScreenContainerSurface(Task task) {
+ mTask = task;
+ }
+
+ @Override
+ public void remove() {
+ mService.mAtmService.mTaskOrganizerController.removeStartingWindow(mTask);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9273bf71f673..90c3f9ec21ef 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -43,10 +43,6 @@ import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
@@ -107,7 +103,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKT
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ROOT_TASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
@@ -120,6 +116,11 @@ import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_PINNABLE;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.Task.ActivityState.PAUSED;
import static com.android.server.wm.Task.ActivityState.PAUSING;
@@ -145,7 +146,7 @@ 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;
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_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.MIN_TASK_LETTERBOX_ASPECT_RATIO;
@@ -161,7 +162,6 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityManager.TaskSnapshot;
-import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
@@ -251,7 +251,7 @@ class Task extends WindowContainer<WindowContainer> {
static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
- private static final String TAG_STACK = TAG + POSTFIX_STACK;
+ private static final String TAG_ROOT_TASK = TAG + POSTFIX_ROOT_TASK;
private static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION;
@@ -308,38 +308,37 @@ class Task extends WindowContainer<WindowContainer> {
private float mShadowRadius = 0;
/**
- * The modes to control how the stack is moved to the front when calling {@link Task#reparent}.
+ * The modes to control how root task is moved to the front when calling {@link Task#reparent}.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({
- REPARENT_MOVE_STACK_TO_FRONT,
- REPARENT_KEEP_STACK_AT_FRONT,
- REPARENT_LEAVE_STACK_IN_PLACE
+ REPARENT_MOVE_ROOT_TASK_TO_FRONT,
+ REPARENT_KEEP_ROOT_TASK_AT_FRONT,
+ REPARENT_LEAVE_ROOT_TASK_IN_PLACE
})
- @interface ReparentMoveStackMode {}
- // Moves the stack to the front if it was not at the front
- static final int REPARENT_MOVE_STACK_TO_FRONT = 0;
- // Only moves the stack to the front if it was focused or front most already
- static final int REPARENT_KEEP_STACK_AT_FRONT = 1;
- // Do not move the stack as a part of reparenting
- static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
-
- // TODO (b/157876447): switch to Task related name
- @IntDef(prefix = {"STACK_VISIBILITY"}, value = {
- STACK_VISIBILITY_VISIBLE,
- STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
- STACK_VISIBILITY_INVISIBLE,
+ @interface ReparentMoveRootTaskMode {}
+ // Moves the root task to the front if it was not at the front
+ static final int REPARENT_MOVE_ROOT_TASK_TO_FRONT = 0;
+ // Only moves the root task to the front if it was focused or front most already
+ static final int REPARENT_KEEP_ROOT_TASK_AT_FRONT = 1;
+ // Do not move the root task as a part of reparenting
+ static final int REPARENT_LEAVE_ROOT_TASK_IN_PLACE = 2;
+
+ @IntDef(prefix = {"TASK_VISIBILITY"}, value = {
+ TASK_VISIBILITY_VISIBLE,
+ TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ TASK_VISIBILITY_INVISIBLE,
})
- @interface StackVisibility {}
+ @interface TaskVisibility {}
- /** Stack is visible. No other stacks on top that fully or partially occlude it. */
- static final int STACK_VISIBILITY_VISIBLE = 0;
+ /** Task is visible. No other tasks on top that fully or partially occlude it. */
+ static final int TASK_VISIBILITY_VISIBLE = 0;
- /** Stack is partially occluded by other translucent stack(s) on top of it. */
- static final int STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1;
+ /** Task is partially occluded by other translucent task(s) on top of it. */
+ static final int TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1;
- /** Stack is completely invisible. */
- static final int STACK_VISIBILITY_INVISIBLE = 2;
+ /** Task is completely invisible. */
+ static final int TASK_VISIBILITY_INVISIBLE = 2;
enum ActivityState {
INITIALIZING,
@@ -407,17 +406,6 @@ class Task extends WindowContainer<WindowContainer> {
boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
// was changed.
- /** Can't be put in lockTask mode. */
- final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
- /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_PINNABLE = 1;
- /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
- /** Can enter lockTask without user approval. Can start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_ALLOWLISTED = 3;
- /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
- * lockTask task. */
- final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
int mLockTaskUid = -1; // The uid of the application that called startLockTask().
@@ -582,6 +570,10 @@ class Task extends WindowContainer<WindowContainer> {
/** Current activity that is resumed, or null if there is none. */
ActivityRecord mResumedActivity = null;
+ /** Last activity that is used to compute the Task bounds. */
+ @Nullable
+ private ActivityRecord mLastTaskBoundsComputeActivity;
+
private boolean mForceShowForAllUsers;
/** When set, will force the task to report as invisible. */
@@ -964,7 +956,7 @@ class Task extends WindowContainer<WindowContainer> {
mAtmService.getLockTaskController().clearLockedTask(this);
}
if (shouldDeferRemoval()) {
- if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
+ if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
return;
}
removeImmediately();
@@ -1056,7 +1048,7 @@ class Task extends WindowContainer<WindowContainer> {
/** Convenience method to reparent a task to the top or bottom position of the stack. */
boolean reparent(Task preferredStack, boolean toTop,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ @ReparentMoveRootTaskMode int moveStackMode, boolean animate, boolean deferResume,
String reason) {
return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume,
true /* schedulePictureInPictureModeChange */, reason);
@@ -1067,7 +1059,7 @@ class Task extends WindowContainer<WindowContainer> {
* an option to skip scheduling the picture-in-picture mode change.
*/
boolean reparent(Task preferredStack, boolean toTop,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ @ReparentMoveRootTaskMode int moveStackMode, boolean animate, boolean deferResume,
boolean schedulePictureInPictureModeChange, String reason) {
return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate,
deferResume, schedulePictureInPictureModeChange, reason);
@@ -1075,7 +1067,7 @@ class Task extends WindowContainer<WindowContainer> {
/** Convenience method to reparent a task to a specific position of the stack. */
boolean reparent(Task preferredStack, int position,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ @ReparentMoveRootTaskMode int moveStackMode, boolean animate, boolean deferResume,
String reason) {
return reparent(preferredStack, position, moveStackMode, animate, deferResume,
true /* schedulePictureInPictureModeChange */, reason);
@@ -1101,7 +1093,7 @@ class Task extends WindowContainer<WindowContainer> {
// TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
// re-parenting the task. Can only be done when we are no longer using static stack Ids.
boolean reparent(Task preferredStack, int position,
- @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+ @ReparentMoveRootTaskMode int moveStackMode, boolean animate, boolean deferResume,
boolean schedulePictureInPictureModeChange, String reason) {
final ActivityStackSupervisor supervisor = mStackSupervisor;
final RootWindowContainer root = mRootWindowContainer;
@@ -1156,8 +1148,9 @@ class Task extends WindowContainer<WindowContainer> {
final boolean wasFront = r != null && sourceStack.isTopStackInDisplayArea()
&& (sourceStack.topRunningActivity() == r);
- final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
- || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
+ final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_ROOT_TASK_TO_FRONT
+ || (moveStackMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT
+ && (wasFocused || wasFront));
reparent(toStack, position, moveStackToFront, reason);
@@ -1181,7 +1174,7 @@ class Task extends WindowContainer<WindowContainer> {
toStack.prepareFreezingTaskBounds();
if (toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
+ && moveStackMode == REPARENT_KEEP_ROOT_TASK_AT_FRONT) {
// Move recents to front so it is not behind home stack when going into docked
// mode
mStackSupervisor.moveRecentsStackToFront(reason);
@@ -1506,6 +1499,11 @@ class Task extends WindowContainer<WindowContainer> {
}
void cleanUpActivityReferences(ActivityRecord r) {
+ // mLastTaskBoundsComputeActivity is set at leaf Task
+ if (mLastTaskBoundsComputeActivity == r) {
+ mLastTaskBoundsComputeActivity = null;
+ }
+
final WindowContainer parent = getParent();
if (parent != null && parent.asTask() != null) {
parent.asTask().cleanUpActivityReferences(r);
@@ -1532,7 +1530,7 @@ class Task extends WindowContainer<WindowContainer> {
return;
}
- if (ActivityTaskManagerDebugConfig.DEBUG_STACK) Slog.d(TAG_STACK,
+ if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) Slog.d(TAG_ROOT_TASK,
"setResumedActivity stack:" + this + " + from: "
+ mResumedActivity + " to:" + r + " reason:" + reason);
mResumedActivity = r;
@@ -1941,32 +1939,7 @@ class Task extends WindowContainer<WindowContainer> {
}
private void setLockTaskAuth(@Nullable ActivityRecord r) {
- if (r == null) {
- mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
- return;
- }
-
- final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
- final LockTaskController lockTaskController = mAtmService.getLockTaskController();
- switch (r.lockTaskLaunchMode) {
- case LOCK_TASK_LAUNCH_MODE_DEFAULT:
- mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
- ? LOCK_TASK_AUTH_ALLOWLISTED : LOCK_TASK_AUTH_PINNABLE;
- break;
-
- case LOCK_TASK_LAUNCH_MODE_NEVER:
- mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
- break;
-
- case LOCK_TASK_LAUNCH_MODE_ALWAYS:
- mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
- break;
-
- case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
- mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
- ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
- break;
- }
+ mLockTaskAuth = mAtmService.getLockTaskController().getLockTaskAuth(r, this);
ProtoLog.d(WM_DEBUG_LOCKTASK, "setLockTaskAuth: task=%s mLockTaskAuth=%s", this,
lockTaskAuthToString());
}
@@ -2210,8 +2183,8 @@ class Task extends WindowContainer<WindowContainer> {
}
if (state == RESUMED) {
- if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
- Slog.v(TAG_STACK, "set resumed activity to:" + record + " reason:" + reason);
+ if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
+ Slog.v(TAG_ROOT_TASK, "set resumed activity to:" + record + " reason:" + reason);
}
setResumedActivity(record, reason + " - onActivityStateChanged");
if (record == mRootWindowContainer.getTopResumedActivity()) {
@@ -2868,6 +2841,8 @@ class Task extends WindowContainer<WindowContainer> {
private void resolveLeafOnlyOverrideConfigs(Configuration newParentConfig,
Rect previousBounds) {
+ mLastTaskBoundsComputeActivity = getTopNonFinishingActivity(false /* includeOverlays */);
+
int windowingMode =
getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
@@ -2998,6 +2973,11 @@ class Task extends WindowContainer<WindowContainer> {
return bounds;
}
+ @Nullable
+ ActivityRecord getLastTaskBoundsComputeActivity() {
+ return mLastTaskBoundsComputeActivity;
+ }
+
/** Updates the task's bounds and override configuration to match what is expected for the
* input stack. */
void updateOverrideConfigurationForStack(Task inStack) {
@@ -3265,7 +3245,7 @@ class Task extends WindowContainer<WindowContainer> {
@Override
void removeImmediately() {
- if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
+ if (DEBUG_ROOT_TASK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask");
// If applicable let the TaskOrganizer know the Task is vanishing.
@@ -3276,7 +3256,7 @@ class Task extends WindowContainer<WindowContainer> {
// TODO: Consolidate this with Task.reparent()
void reparent(Task stack, int position, boolean moveParents, String reason) {
- if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
+ if (DEBUG_ROOT_TASK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
+ " from stack=" + getRootTask());
EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask:" + reason);
@@ -3342,18 +3322,6 @@ class Task extends WindowContainer<WindowContainer> {
// No one in higher hierarchy handles this request, let's adjust our bounds to fulfill
// it if possible.
if (getParent() != null) {
- final ActivityRecord activity = requestingContainer.asActivityRecord();
- if (activity != null) {
- // Clear the size compat cache to recompute the bounds for requested orientation;
- // otherwise when Task#computeFullscreenBounds(), it will not try to do Task level
- // letterboxing because app may prefer to keep its original size (size compat).
- //
- // Normally, ActivityRecord#clearSizeCompatMode() recomputes from its parent Task,
- // which is the leaf Task. However, because this orientation request is new to all
- // Tasks, pass false to clearSizeCompatMode, and trigger onConfigurationChanged from
- // here (root Task) to make sure all Tasks are up-to-date.
- activity.clearSizeCompatMode(false /* recomputeTask */);
- }
onConfigurationChanged(getParent().getConfiguration());
return true;
}
@@ -4103,6 +4071,10 @@ class Task extends WindowContainer<WindowContainer> {
info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
info.configuration.setTo(getConfiguration());
+ // Update to the task's current activity type and windowing mode which may differ from the
+ // window configuration
+ info.configuration.windowConfiguration.setActivityType(getActivityType());
+ info.configuration.windowConfiguration.setWindowingMode(getWindowingMode());
info.token = mRemoteToken.toWindowContainerToken();
//TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child
@@ -4180,7 +4152,7 @@ class Task extends WindowContainer<WindowContainer> {
* @param starting The currently starting activity or null if there is none.
*/
boolean shouldBeVisible(ActivityRecord starting) {
- return getVisibility(starting) != STACK_VISIBILITY_INVISIBLE;
+ return getVisibility(starting) != TASK_VISIBILITY_INVISIBLE;
}
/**
@@ -4188,14 +4160,14 @@ class Task extends WindowContainer<WindowContainer> {
*
* @param starting The currently starting activity or null if there is none.
*/
- @Task.StackVisibility
+ @TaskVisibility
int getVisibility(ActivityRecord starting) {
if (!isAttached() || isForceHidden()) {
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
if (isTopActivityLaunchedBehind()) {
- return STACK_VISIBILITY_VISIBLE;
+ return TASK_VISIBILITY_VISIBLE;
}
boolean gotSplitScreenStack = false;
@@ -4211,10 +4183,10 @@ class Task extends WindowContainer<WindowContainer> {
final WindowContainer parent = getParent();
if (parent.asTask() != null) {
final int parentVisibility = parent.asTask().getVisibility(starting);
- if (parentVisibility == STACK_VISIBILITY_INVISIBLE) {
+ if (parentVisibility == TASK_VISIBILITY_INVISIBLE) {
// Can't be visible if parent isn't visible
- return STACK_VISIBILITY_INVISIBLE;
- } else if (parentVisibility == STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) {
+ return TASK_VISIBILITY_INVISIBLE;
+ } else if (parentVisibility == TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT) {
// Parent is behind a translucent container so the highest visibility this container
// can get is that.
gotTranslucentFullscreen = true;
@@ -4249,7 +4221,7 @@ class Task extends WindowContainer<WindowContainer> {
gotTranslucentFullscreen = true;
continue;
}
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
} else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
&& !gotOpaqueSplitScreenPrimary) {
gotSplitScreenStack = true;
@@ -4258,7 +4230,7 @@ class Task extends WindowContainer<WindowContainer> {
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
&& gotOpaqueSplitScreenPrimary) {
// Can not be visible behind another opaque stack in split-screen-primary mode.
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
} else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
&& !gotOpaqueSplitScreenSecondary) {
@@ -4268,24 +4240,24 @@ class Task extends WindowContainer<WindowContainer> {
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
&& gotOpaqueSplitScreenSecondary) {
// Can not be visible behind another opaque stack in split-screen-secondary mode.
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
}
if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) {
// Can not be visible if we are in split-screen windowing mode and both halves of
// the screen are opaque.
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
if (isAssistantType && gotSplitScreenStack) {
// Assistant stack can't be visible behind split-screen. In addition to this not
// making sense, it also works around an issue here we boost the z-order of the
// assistant window surfaces in window manager whenever it is visible.
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
}
if (!shouldBeVisible) {
- return STACK_VISIBILITY_INVISIBLE;
+ return TASK_VISIBILITY_INVISIBLE;
}
// Handle cases when there can be a translucent split-screen stack on top.
@@ -4293,26 +4265,26 @@ class Task extends WindowContainer<WindowContainer> {
case WINDOWING_MODE_FULLSCREEN:
if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) {
// At least one of the split-screen stacks that covers this one is translucent.
- return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+ return TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
}
break;
case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
if (gotTranslucentSplitScreenPrimary) {
// Covered by translucent primary split-screen on top.
- return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+ return TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
}
break;
case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
if (gotTranslucentSplitScreenSecondary) {
// Covered by translucent secondary split-screen on top.
- return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+ return TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
}
break;
}
// Lastly - check if there is a translucent fullscreen stack on top.
- return gotTranslucentFullscreen ? STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
- : STACK_VISIBILITY_VISIBLE;
+ return gotTranslucentFullscreen ? TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
+ : TASK_VISIBILITY_VISIBLE;
}
private boolean isTopActivityLaunchedBehind() {
@@ -5720,19 +5692,6 @@ class Task extends WindowContainer<WindowContainer> {
if (prev != null) {
prev.resumeKeyDispatchingLocked();
-
- if (prev.hasProcess() && prev.cpuTimeAtResume > 0) {
- final long diff = prev.app.getCpuTime() - prev.cpuTimeAtResume;
- if (diff > 0) {
- final Runnable r = PooledLambda.obtainRunnable(
- ActivityManagerInternal::updateForegroundTimeIfOnBattery,
- mAtmService.mAmInternal, prev.info.packageName,
- prev.info.applicationInfo.uid,
- diff);
- mAtmService.mH.post(r);
- }
- }
- prev.cpuTimeAtResume = 0; // reset it
}
mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
@@ -5775,7 +5734,8 @@ class Task extends WindowContainer<WindowContainer> {
*/
void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
boolean preserveWindows) {
- ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */);
+ ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */,
+ mStackSupervisor.mUserLeaving);
}
/**
@@ -5792,14 +5752,16 @@ class Task extends WindowContainer<WindowContainer> {
* @param configChanges Parts of the configuration that changed for this activity for evaluating
* if the screen should be frozen as part of
* {@link mEnsureActivitiesVisibleHelper}.
+ * @param userLeaving Flag indicating whether a userLeaving callback should be issued in the
+ * case an activity is being set to invisible.
*/
// TODO: Should be re-worked based on the fact that each task as a stack in most cases.
void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients) {
+ boolean preserveWindows, boolean notifyClients, boolean userLeaving) {
mStackSupervisor.beginActivityVisibilityUpdate();
try {
forAllLeafTasks(task -> task.mEnsureActivitiesVisibleHelper.process(
- starting, configChanges, preserveWindows, notifyClients),
+ starting, configChanges, preserveWindows, notifyClients, userLeaving),
true /* traverseTopToBottom */);
if (mTranslucentActivityWaiting != null &&
@@ -5926,7 +5888,21 @@ class Task extends WindowContainer<WindowContainer> {
try {
// Protect against recursion.
mInResumeTopActivity = true;
- result = resumeTopActivityInnerLocked(prev, options);
+
+ // TODO(b/172885410): Allow the top activities of all visible leaf tasks to be resumed
+ if (mCreatedByOrganizer && !isLeafTask()
+ && getConfiguration().windowConfiguration.getWindowingMode()
+ == WINDOWING_MODE_FULLSCREEN) {
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final Task child = (Task) getChildAt(i);
+ if (!child.shouldBeVisible(null /* starting */)) {
+ break;
+ }
+ result |= child.resumeTopActivityUncheckedLocked(prev, options);
+ }
+ } else {
+ result = resumeTopActivityInnerLocked(prev, options);
+ }
// When resuming the top activity, it may be necessary to pause the top activity (for
// example, returning to the lock screen. We suppress the normal pause logic in
@@ -5981,17 +5957,20 @@ class Task extends WindowContainer<WindowContainer> {
final TaskDisplayArea taskDisplayArea = getDisplayArea();
// If the top activity is the resumed one, nothing to do.
- // For devices that are not in fullscreen mode (e.g. freeform windows), it's possible
- // we still want to proceed if the visibility of other windows have changed (e.g. bringing
- // a fullscreen window forward to cover another freeform activity.)
if (mResumedActivity == next && next.isState(RESUMED)
- && taskDisplayArea.getWindowingMode() != WINDOWING_MODE_FREEFORM
&& taskDisplayArea.allResumedActivitiesComplete()) {
// The activity may be waiting for stop, but that is no longer appropriate for it.
mStackSupervisor.mStoppingActivities.remove(next);
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
+ // For devices that are not in fullscreen mode (e.g. freeform windows), it's possible
+ // we still want to check if the visibility of other windows have changed (e.g. bringing
+ // a fullscreen window forward to cover another freeform activity.)
+ if (taskDisplayArea.inMultiWindowMode()) {
+ taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ false /* preserveWindows */, true /* notifyClients */, userLeaving);
+ }
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity "
+ "resumed %s", next);
return false;
@@ -7326,7 +7305,7 @@ class Task extends WindowContainer<WindowContainer> {
boolean toTop = position >= getChildCount();
boolean includingParents = toTop || getDisplayArea().getNextFocusableStack(this,
true /* ignoreCurrent */) == null;
- if (WindowManagerDebugConfig.DEBUG_STACK) {
+ if (WindowManagerDebugConfig.DEBUG_ROOT_TASK) {
Slog.i(TAG_WM, "positionChildAt: positioning task=" + task + " at " + position);
}
positionChildAt(position, task, includingParents);
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index e7213192dfd3..802c8f9f1ec9 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -37,11 +37,11 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
-import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
+import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK;
import static com.android.server.wm.DisplayContent.alwaysCreateStack;
import static com.android.server.wm.Task.ActivityState.RESUMED;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.Nullable;
@@ -311,7 +311,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
@Override
void addChild(Task task, int position) {
- if (DEBUG_STACK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this);
+ if (DEBUG_ROOT_TASK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this);
addStackReferenceIfNeeded(task);
position = findPositionForStack(position, task, true /* adding */);
@@ -831,8 +831,8 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
void onStackRemoved(Task stack) {
- if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
- Slog.v(TAG_STACK, "removeStack: detaching " + stack + " from displayId="
+ if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
+ Slog.v(TAG_ROOT_TASK, "removeStack: detaching " + stack + " from displayId="
+ mDisplayContent.mDisplayId);
}
if (mPreferredTopFocusableStack == stack) {
@@ -870,7 +870,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
homeParentTask.positionChildAtBottom(task);
} else {
task.reparent(homeParentTask, false /* toTop */,
- Task.REPARENT_LEAVE_STACK_IN_PLACE, false /* animate */,
+ Task.REPARENT_LEAVE_ROOT_TASK_IN_PLACE, false /* animate */,
false /* deferResume */, "positionTaskBehindHome");
}
}
@@ -1205,8 +1205,8 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
}
final Task currentFocusedStack = getFocusedStack();
- if (ActivityTaskManagerDebugConfig.DEBUG_STACK) {
- Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
+ if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
+ Slog.d(TAG_ROOT_TASK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
+ mLastFocusedStack + " to=" + currentFocusedStack);
}
mLastFocusedStack = currentFocusedStack;
@@ -1230,7 +1230,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
final Task stack = getStackAt(stackNdx);
final ActivityRecord resumedActivity = stack.getResumedActivity();
if (resumedActivity != null
- && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
+ && (stack.getVisibility(resuming) != TASK_VISIBILITY_VISIBLE
|| !stack.isTopActivityFocusable())) {
ProtoLog.d(WM_DEBUG_STATES, "pauseBackStacks: stack=%s "
+ "mResumedActivity=%s", stack, resumedActivity);
@@ -1806,13 +1806,13 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
- boolean preserveWindows, boolean notifyClients) {
+ boolean preserveWindows, boolean notifyClients, boolean userLeaving) {
mAtmService.mStackSupervisor.beginActivityVisibilityUpdate();
try {
for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
final Task stack = getStackAt(stackNdx);
stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
- notifyClients);
+ notifyClients, userLeaving);
}
} finally {
mAtmService.mStackSupervisor.endActivityVisibilityUpdate();
@@ -1851,8 +1851,12 @@ final class TaskDisplayArea extends DisplayArea<Task> {
.getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null;
for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
final Task stack = getStackAt(stackNdx);
- // Always finish non-standard type stacks.
- if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
+ // Always finish non-standard type stacks and stacks created by a organizer.
+ // TODO: For stacks created by organizer, consider reparenting children tasks if the use
+ // case arises in the future.
+ if (destroyContentOnRemoval
+ || !stack.isActivityTypeStandardOrUndefined()
+ || stack.mCreatedByOrganizer) {
stack.finishAllActivitiesImmediately();
} else {
// Reparent the stack to the root task of secondary-split-screen or display area.
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index a1c5670ec9af..bb8b4a5f966f 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -116,6 +116,28 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return mTaskOrganizer.asBinder();
}
+ void addStartingWindow(Task task, IBinder appToken) {
+ final RunningTaskInfo taskInfo = task.getTaskInfo();
+ mDeferTaskOrgCallbacksConsumer.accept(() -> {
+ try {
+ mTaskOrganizer.addStartingWindow(taskInfo, appToken);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onTaskStart callback", e);
+ }
+ });
+ }
+
+ void removeStartingWindow(Task task) {
+ final RunningTaskInfo taskInfo = task.getTaskInfo();
+ mDeferTaskOrgCallbacksConsumer.accept(() -> {
+ try {
+ mTaskOrganizer.removeStartingWindow(taskInfo);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
+ }
+ });
+ }
+
SurfaceControl prepareLeash(Task task, boolean visible, String reason) {
SurfaceControl outSurfaceControl = new SurfaceControl(task.getSurfaceControl(), reason);
if (!task.mCreatedByOrganizer && !visible) {
@@ -218,6 +240,14 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
mUid = uid;
}
+ void addStartingWindow(Task t, IBinder appToken) {
+ mOrganizer.addStartingWindow(t, appToken);
+ }
+
+ void removeStartingWindow(Task t) {
+ mOrganizer.removeStartingWindow(t);
+ }
+
/**
* Register this task with this state, but doesn't trigger the task appeared callback to
* the organizer.
@@ -390,6 +420,27 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return !ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, winMode);
}
+ boolean addStartingWindow(Task task, IBinder appToken) {
+ final Task rootTask = task.getRootTask();
+ if (rootTask == null || rootTask.mTaskOrganizer == null) {
+ return false;
+ }
+ final TaskOrganizerState state =
+ mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
+ state.addStartingWindow(task, appToken);
+ return true;
+ }
+
+ void removeStartingWindow(Task task) {
+ final Task rootTask = task.getRootTask();
+ if (rootTask == null || rootTask.mTaskOrganizer == null) {
+ return;
+ }
+ final TaskOrganizerState state =
+ mTaskOrganizerStates.get(rootTask.mTaskOrganizer.asBinder());
+ state.removeStartingWindow(task);
+ }
+
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
state.addTask(task);
@@ -442,7 +493,11 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final Task task = WindowContainer.fromBinder(token.asBinder()).asTask();
+ final WindowContainer wc = WindowContainer.fromBinder(token.asBinder());
+ if (wc == null) {
+ throw new IllegalArgumentException("Can't resolve window from token");
+ }
+ final Task task = wc.asTask();
if (task == null) return false;
if (!task.mCreatedByOrganizer) {
throw new IllegalArgumentException(
@@ -493,8 +548,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
mTmpTaskInfo.positionInParent,
lastInfo.positionInParent)
|| mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams
- || mTmpTaskInfo.getConfiguration().windowConfiguration.getWindowingMode()
- != lastInfo.getConfiguration().windowConfiguration.getWindowingMode()
+ || mTmpTaskInfo.getWindowingMode() != lastInfo.getWindowingMode()
|| !TaskDescription.equals(mTmpTaskInfo.taskDescription, lastInfo.taskDescription);
if (!changed) {
int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
@@ -564,8 +618,14 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
if (defaultTaskDisplayArea == null) {
return;
}
- Task task = token == null
- ? null : WindowContainer.fromBinder(token.asBinder()).asTask();
+ WindowContainer wc = null;
+ if (token != null) {
+ wc = WindowContainer.fromBinder(token.asBinder());
+ if (wc == null) {
+ throw new IllegalArgumentException("Can't resolve window from token");
+ }
+ }
+ final Task task = wc == null ? null : wc.asTask();
if (task == null) {
defaultTaskDisplayArea.mLaunchRootTask = null;
return;
@@ -666,7 +726,12 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
synchronized (mGlobalLock) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Set intercept back pressed on root=%b",
interceptBackPressed);
- final Task task = WindowContainer.fromBinder(token.asBinder()).asTask();
+ final WindowContainer wc = WindowContainer.fromBinder(token.asBinder());
+ if (wc == null) {
+ Slog.w(TAG, "Could not resolve window from token");
+ return;
+ }
+ final Task task = wc.asTask();
if (task == null) {
Slog.w(TAG, "Could not resolve task from token");
return;
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index a3dc29058f1e..eff4b9e5a96a 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -16,7 +16,7 @@
package com.android.server.wm;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import android.annotation.NonNull;
import android.graphics.Bitmap;
@@ -330,7 +330,7 @@ public class TaskPersister implements PersisterQueue.Listener {
final int taskId = task.mTaskId;
if (mService.mRootWindowContainer.anyTaskForId(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) {
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS) != null) {
// Should not happen.
Slog.wtf(TAG, "Existing task with taskId " + taskId + "found");
} else if (userId != task.mUserId) {
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index a6f0f464c8b3..614d2210189c 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -225,10 +225,8 @@ class TaskPositioner implements IBinder.DeathRecipient {
mClientChannel, mService.mAnimationHandler.getLooper(),
mService.mAnimator.getChoreographer());
- mDragApplicationHandle = new InputApplicationHandle(new Binder());
- mDragApplicationHandle.name = TAG;
- mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
-
+ mDragApplicationHandle = new InputApplicationHandle(new Binder(), TAG,
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
displayContent.getDisplayId());
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index aab5da6de214..30f09ce9a3e6 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -36,6 +36,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATIO
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
@@ -129,6 +130,7 @@ class TaskSnapshotSurface implements StartingSurface {
private SurfaceControl mChildSurfaceControl;
private final IWindowSession mSession;
private final WindowManagerService mService;
+ private final int mDisplayId;
private final Rect mTaskBounds;
private final Rect mFrame = new Rect();
private final Rect mSystemBarInsets = new Rect();
@@ -151,10 +153,15 @@ class TaskSnapshotSurface implements StartingSurface {
static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
TaskSnapshot snapshot) {
+ return create(service, activity, snapshot, WindowManagerGlobal.getWindowSession());
+ }
+
+ @VisibleForTesting
+ static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
+ TaskSnapshot snapshot, IWindowSession session) {
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
final Window window = new Window();
- final IWindowSession session = WindowManagerGlobal.getWindowSession();
window.setSession(session);
final SurfaceControl surfaceControl = new SurfaceControl();
final ClientWindowFrames tmpFrames = new ClientWindowFrames();
@@ -215,7 +222,10 @@ class TaskSnapshotSurface implements StartingSurface {
layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
| FLAG_NOT_FOCUSABLE
| FLAG_NOT_TOUCHABLE;
- layoutParams.privateFlags = windowPrivateFlags & PRIVATE_FLAG_INHERITS;
+ // Setting as trusted overlay to let touches pass through. This is safe because this
+ // window is controlled by the system.
+ layoutParams.privateFlags = (windowPrivateFlags & PRIVATE_FLAG_INHERITS)
+ | PRIVATE_FLAG_TRUSTED_OVERLAY;
layoutParams.token = activity.token;
layoutParams.width = LayoutParams.MATCH_PARENT;
layoutParams.height = LayoutParams.MATCH_PARENT;
@@ -239,11 +249,11 @@ class TaskSnapshotSurface implements StartingSurface {
insetsState = getInsetsStateWithVisibilityOverride(topFullscreenOpaqueWindow);
}
+ int displayId = activity.getDisplayContent().getDisplayId();
try {
final int res = session.addToDisplay(window, layoutParams,
- View.GONE, activity.getDisplayContent().getDisplayId(), mTmpInsetsState,
- tmpFrames.frame, tmpFrames.displayCutout, null /* outInputChannel */,
- mTmpInsetsState, mTempControls);
+ View.GONE, displayId, mTmpInsetsState, tmpFrames.frame, tmpFrames.displayCutout,
+ null /* outInputChannel */, mTmpInsetsState, mTempControls);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
return null;
@@ -251,10 +261,10 @@ class TaskSnapshotSurface implements StartingSurface {
} catch (RemoteException e) {
// Local call.
}
- final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
- surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
- windowFlags, windowPrivateFlags, taskBounds, currentOrientation, activityType,
- insetsState);
+ final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, displayId,
+ window, surfaceControl, snapshot, layoutParams.getTitle(), taskDescription,
+ appearance, windowFlags, windowPrivateFlags, taskBounds, currentOrientation,
+ activityType, insetsState);
window.setOuter(snapshotSurface);
try {
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
@@ -271,11 +281,13 @@ class TaskSnapshotSurface implements StartingSurface {
}
@VisibleForTesting
- TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
- TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
- int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
- int currentOrientation, int activityType, InsetsState insetsState) {
+ TaskSnapshotSurface(WindowManagerService service, int displayId, Window window,
+ SurfaceControl surfaceControl, TaskSnapshot snapshot, CharSequence title,
+ TaskDescription taskDescription, int appearance, int windowFlags,
+ int windowPrivateFlags, Rect taskBounds, int currentOrientation, int activityType,
+ InsetsState insetsState) {
mService = service;
+ mDisplayId = displayId;
mSurface = service.mSurfaceFactory.get();
mHandler = new Handler(mService.mH.getLooper());
mSession = WindowManagerGlobal.getWindowSession();
@@ -368,8 +380,9 @@ class TaskSnapshotSurface implements StartingSurface {
- ((float) mFrame.width() / mFrame.height())) > 0.01f;
// Keep a reference to it such that it doesn't get destroyed when finalized.
+ final String name = mTitle + " - task-snapshot-surface";
mChildSurfaceControl = mService.mSurfaceControlFactory.apply(session)
- .setName(mTitle + " - task-snapshot-surface")
+ .setName(name)
.setBufferSize(buffer.getWidth(), buffer.getHeight())
.setFormat(buffer.getFormat())
.setParent(mSurfaceControl)
@@ -401,6 +414,11 @@ class TaskSnapshotSurface implements StartingSurface {
mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL);
mTransaction.setMatrix(mChildSurfaceControl, mSnapshotMatrix, mTmpFloat9);
+ // This is the way to tell the input system to exclude this surface from occlusion
+ // detection since we don't have a window for it. We do this because this window is
+ // generated by the system as well as its content (the snapshot of the app).
+ InputMonitor.setTrustedOverlayInputInfo(mChildSurfaceControl, mTransaction, mDisplayId,
+ name);
mTransaction.apply();
surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
surface.release();
diff --git a/services/core/java/com/android/server/wm/VisibleActivityProcessTracker.java b/services/core/java/com/android/server/wm/VisibleActivityProcessTracker.java
new file mode 100644
index 000000000000..7f626308976b
--- /dev/null
+++ b/services/core/java/com/android/server/wm/VisibleActivityProcessTracker.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.server.wm;
+
+import android.util.ArrayMap;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A quick lookup for all processes with visible activities. It also tracks the CPU usage of
+ * host process with foreground (resumed) activity.
+ */
+class VisibleActivityProcessTracker {
+ @GuardedBy("mProcMap")
+ private final ArrayMap<WindowProcessController, CpuTimeRecord> mProcMap = new ArrayMap<>();
+ final Executor mBgExecutor = BackgroundThread.getExecutor();
+ final ActivityTaskManagerService mAtms;
+
+ VisibleActivityProcessTracker(ActivityTaskManagerService atms) {
+ mAtms = atms;
+ }
+
+ /** Called when any activity is visible in the process that didn't have one. */
+ void onAnyActivityVisible(WindowProcessController wpc) {
+ final CpuTimeRecord r = new CpuTimeRecord(wpc);
+ synchronized (mProcMap) {
+ mProcMap.put(wpc, r);
+ }
+ if (wpc.hasResumedActivity()) {
+ r.mShouldGetCpuTime = true;
+ mBgExecutor.execute(r);
+ }
+ }
+
+ /** Called when all visible activities of the process are no longer visible. */
+ void onAllActivitiesInvisible(WindowProcessController wpc) {
+ final CpuTimeRecord r = removeProcess(wpc);
+ if (r != null && r.mShouldGetCpuTime) {
+ mBgExecutor.execute(r);
+ }
+ }
+
+ /** Called when an activity is resumed on a process which is known to have visible activity. */
+ void onActivityResumedWhileVisible(WindowProcessController wpc) {
+ final CpuTimeRecord r;
+ synchronized (mProcMap) {
+ r = mProcMap.get(wpc);
+ }
+ if (r != null && !r.mShouldGetCpuTime) {
+ r.mShouldGetCpuTime = true;
+ mBgExecutor.execute(r);
+ }
+ }
+
+ boolean hasResumedActivity(int uid) {
+ synchronized (mProcMap) {
+ for (int i = mProcMap.size() - 1; i >= 0; i--) {
+ final WindowProcessController wpc = mProcMap.keyAt(i);
+ if (wpc.mUid == uid && wpc.hasResumedActivity()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ CpuTimeRecord removeProcess(WindowProcessController wpc) {
+ synchronized (mProcMap) {
+ return mProcMap.remove(wpc);
+ }
+ }
+
+ /**
+ * Get CPU time in background thread because it will access proc files or the lock of cpu
+ * tracker is held by a background thread.
+ */
+ private class CpuTimeRecord implements Runnable {
+ private final WindowProcessController mProc;
+ private long mCpuTime;
+ private boolean mHasStartCpuTime;
+ boolean mShouldGetCpuTime;
+
+ CpuTimeRecord(WindowProcessController wpc) {
+ mProc = wpc;
+ }
+
+ @Override
+ public void run() {
+ if (mProc.getPid() == 0) {
+ // The process is dead.
+ return;
+ }
+ if (!mHasStartCpuTime) {
+ mHasStartCpuTime = true;
+ mCpuTime = mProc.getCpuTime();
+ } else {
+ final long diff = mProc.getCpuTime() - mCpuTime;
+ if (diff > 0) {
+ mAtms.mAmInternal.updateForegroundTimeIfOnBattery(
+ mProc.mInfo.packageName, mProc.mInfo.uid, diff);
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 0f6b62bae55f..aeb5be717e0f 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1169,7 +1169,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
/**
- * Get the configuration orientation by the requested screen orientation
+ * Gets the configuration orientation by the requested screen orientation
* ({@link ActivityInfo.ScreenOrientation}) of this activity.
*
* @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE},
@@ -1177,9 +1177,26 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
* {@link Configuration#ORIENTATION_UNDEFINED}).
*/
int getRequestedConfigurationOrientation() {
+ return getRequestedConfigurationOrientation(false /* forDisplay */);
+ }
+
+ /**
+ * Gets the configuration orientation by the requested screen orientation
+ * ({@link ActivityInfo.ScreenOrientation}) of this activity.
+ *
+ * @param forDisplay whether it is the requested config orientation for display.
+ * If {@code true}, we may reverse the requested orientation if the root is
+ * different from the display, so that when the display rotates to the
+ * reversed orientation, the requested app will be in the requested
+ * orientation.
+ * @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE},
+ * {@link Configuration#ORIENTATION_PORTRAIT},
+ * {@link Configuration#ORIENTATION_UNDEFINED}).
+ */
+ int getRequestedConfigurationOrientation(boolean forDisplay) {
int requestedOrientation = mOrientation;
final RootDisplayArea root = getRootDisplayArea();
- if (root != null && root.isOrientationDifferentFromDisplay()) {
+ if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) {
// Reverse the requested orientation if the orientation of its root is different from
// the display, so that when the display rotates to the reversed orientation, the
// requested app will be in the requested orientation.
@@ -2878,6 +2895,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return true;
}
+ @Nullable
static WindowContainer fromBinder(IBinder binder) {
return RemoteToken.fromBinder(binder).getContainer();
}
@@ -2891,6 +2909,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
mWeakRef = new WeakReference<>(container);
}
+ @Nullable
WindowContainer getContainer() {
return mWeakRef.get();
}
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 259dee48fb39..81122ac334b5 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -203,7 +203,7 @@ public class WindowFrames {
/**
* @return true if the width or height has changed since last reported to the client.
*/
- private boolean didFrameSizeChange() {
+ boolean didFrameSizeChange() {
return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 93b0fd9b1fe3..74337c2b38ed 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -50,7 +50,7 @@ public class WindowManagerDebugConfig {
static final boolean DEBUG_WINDOW_TRACE = false;
static final boolean DEBUG_TASK_MOVEMENT = false;
static final boolean DEBUG_TASK_POSITIONING = false;
- static final boolean DEBUG_STACK = false;
+ static final boolean DEBUG_ROOT_TASK = false;
static final boolean DEBUG_DISPLAY = false;
static final boolean DEBUG_POWER = false;
static final boolean SHOW_VERBOSE_TRANSACTIONS = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 66cb674f0acd..872980149246 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -430,9 +430,6 @@ public abstract class WindowManagerInternal {
public abstract void setOnHardKeyboardStatusChangeListener(
OnHardKeyboardStatusChangeListener listener);
- /** Returns true if a stack in the windowing mode is currently visible. */
- public abstract boolean isStackVisibleLw(int windowingMode);
-
/**
* Requests the window manager to resend the windows for accessibility on specified display.
*
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c806c94358cb..8a09bd43e452 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -44,6 +44,7 @@ import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDO
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
+import static android.provider.Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS;
import static android.provider.Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -197,7 +198,6 @@ import android.os.SystemService;
import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
@@ -490,6 +490,7 @@ public class WindowManagerService extends IWindowManager.Stub
final Map<IBinder, KeyInterceptionInfo> mKeyInterceptionInfoForToken =
Collections.synchronizedMap(new ArrayMap<>());
+ final StartingSurfaceController mStartingSurfaceController;
private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
@Override
@@ -576,6 +577,7 @@ public class WindowManagerService extends IWindowManager.Stub
final PackageManagerInternal mPmInternal;
private final TestUtilityService mTestUtilityService;
+ final DisplayWindowSettingsProvider mDisplayWindowSettingsProvider;
final DisplayWindowSettings mDisplayWindowSettings;
/** If the system should display notifications for apps displaying an alert window. */
@@ -799,6 +801,8 @@ public class WindowManagerService extends IWindowManager.Stub
DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM);
private final Uri mRenderShadowsInCompositorUri = Settings.Global.getUriFor(
DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR);
+ private final Uri mIgnoreVendorDisplaySettingsUri = Settings.Global.getUriFor(
+ DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS);
public SettingsObserver() {
super(new Handler());
@@ -823,6 +827,8 @@ public class WindowManagerService extends IWindowManager.Stub
UserHandle.USER_ALL);
resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(mIgnoreVendorDisplaySettingsUri, false, this,
+ UserHandle.USER_ALL);
}
@Override
@@ -866,6 +872,11 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
+ if (mIgnoreVendorDisplaySettingsUri.equals(uri)) {
+ updateIgnoreVendorDisplaySettings();
+ return;
+ }
+
@UpdateAnimationScaleMode
final int mode;
if (mWindowAnimationScaleUri.equals(uri)) {
@@ -955,6 +966,19 @@ public class WindowManagerService extends IWindowManager.Stub
mAtmService.mSizeCompatFreeform = sizeCompatFreeform;
}
+
+ void updateIgnoreVendorDisplaySettings() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ final boolean ignoreVendorSettings = Settings.Global.getInt(resolver,
+ DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0;
+ synchronized (mGlobalLock) {
+ mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorSettings);
+ mRoot.forAllDisplays(display -> {
+ mDisplayWindowSettings.applySettingsToDisplayLocked(display);
+ display.reconfigureDisplayLocked();
+ });
+ }
+ }
}
private void setShadowRenderer() {
@@ -1213,7 +1237,6 @@ public class WindowManagerService extends IWindowManager.Stub
mSurfaceFactory = surfaceFactory;
mTransaction = mTransactionFactory.get();
- mDisplayWindowSettings = new DisplayWindowSettings(this);
mPolicy = policy;
mAnimator = new WindowAnimator(this);
mRoot = new RootWindowContainer(this);
@@ -1312,6 +1335,12 @@ public class WindowManagerService extends IWindowManager.Stub
mForceDesktopModeOnExternalDisplays = Settings.Global.getInt(resolver,
DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 0) != 0;
+ final boolean ignoreVendorDisplaySettings = Settings.Global.getInt(resolver,
+ DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS, 0) != 0;
+ mDisplayWindowSettingsProvider = new DisplayWindowSettingsProvider();
+ mDisplayWindowSettingsProvider.setVendorSettingsIgnored(ignoreVendorDisplaySettings);
+ mDisplayWindowSettings = new DisplayWindowSettings(this, mDisplayWindowSettingsProvider);
+
IntentFilter filter = new IntentFilter();
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
filter.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
@@ -1347,6 +1376,8 @@ public class WindowManagerService extends IWindowManager.Stub
mContext.getResources());
setGlobalShadowSettings();
+
+ mStartingSurfaceController = new StartingSurfaceController(this);
}
private void setGlobalShadowSettings() {
@@ -1531,7 +1562,7 @@ public class WindowManagerService extends IWindowManager.Stub
ProtoLog.w(WM_ERROR, "Attempted to add window with exiting application token "
+ ".%s Aborting.", token);
return WindowManagerGlobal.ADD_APP_EXITING;
- } else if (type == TYPE_APPLICATION_STARTING && activity.startingWindow != null) {
+ } else if (type == TYPE_APPLICATION_STARTING && activity.mStartingWindow != null) {
ProtoLog.w(WM_ERROR,
"Attempted to add starting window to token with already existing"
+ " starting window");
@@ -1680,7 +1711,7 @@ public class WindowManagerService extends IWindowManager.Stub
final ActivityRecord tokenActivity = token.asActivityRecord();
if (type == TYPE_APPLICATION_STARTING && tokenActivity != null) {
- tokenActivity.startingWindow = win;
+ tokenActivity.mStartingWindow = win;
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s",
activity, win);
}
@@ -2163,6 +2194,11 @@ public class WindowManagerService extends IWindowManager.Stub
win.finishSeamlessRotation(false /* timeout */);
}
+ if (win.mPendingPositionChanged != null) {
+ win.mPendingPositionChanged.updateLeashPosition(win.getFrame(), frameNumber);
+ win.mPendingPositionChanged = null;
+ }
+
if (mUseBLASTSync && win.useBLASTSync()) {
result |= RELAYOUT_RES_BLAST_SYNC;
}
@@ -5582,7 +5618,7 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowState win = (WindowState) container.mWaitingForDrawn.get(j);
ProtoLog.i(WM_DEBUG_SCREEN_ON,
"Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
- win, win.mRemoved, win.isVisibleLw(), win.mHasSurface,
+ win, win.mRemoved, win.isVisible(), win.mHasSurface,
win.mWinAnimator.mDrawState);
if (win.mRemoved || !win.mHasSurface || !win.isVisibleByPolicy()) {
// Window has been removed or hidden; no draw will now happen, so stop waiting.
@@ -7568,13 +7604,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public boolean isStackVisibleLw(int windowingMode) {
- // TODO(b/153090332): Support multiple task display areas & displays
- final TaskDisplayArea tc = mRoot.getDefaultTaskDisplayArea();
- return tc.isStackVisible(windowingMode);
- }
-
- @Override
public void computeWindowsForAccessibility(int displayId) {
final AccessibilityController accessibilityController;
synchronized (mGlobalLock) {
@@ -7669,6 +7698,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (imeTarget == null) {
return;
}
+ Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.showImePostLayout", 0);
final InsetsControlTarget controlTarget = imeTarget.getImeControlTarget();
imeTarget = controlTarget.getWindow();
// If InsetsControlTarget doesn't have a window, its using remoteControlTarget which
@@ -7682,6 +7712,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void hideIme(IBinder imeTargetWindowToken, int displayId) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.hideIme");
synchronized (mGlobalLock) {
WindowState imeTarget = mWindowMap.get(imeTargetWindowToken);
ProtoLog.d(WM_DEBUG_IME, "hideIme target: %s ", imeTarget);
@@ -7702,6 +7733,7 @@ public class WindowManagerService extends IWindowManager.Stub
WindowInsets.Type.ime(), true /* fromIme */);
}
}
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@Override
@@ -7964,19 +7996,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- /**
- * Updates {@link WindowManagerPolicy} with new value about whether AOD is showing. If AOD
- * has changed, this will trigger a {@link WindowSurfacePlacer#performSurfacePlacement} to
- * ensure the new value takes effect.
- */
- public void setAodShowing(boolean aodShowing) {
- synchronized (mGlobalLock) {
- if (mPolicy.setAodShowing(aodShowing)) {
- mWindowPlacerLocked.performSurfacePlacement();
- }
- }
- }
-
@Override
public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) {
boolean isDown;
@@ -8364,7 +8383,7 @@ public class WindowManagerService extends IWindowManager.Stub
embeddedWindow.getName());
return;
}
- t.requestFocusTransfer(newFocusTarget.mInputWindowHandle.token, targetInputToken,
+ t.requestFocusTransfer(newFocusTarget.mInputChannelToken, targetInputToken,
displayId).apply();
EventLog.writeEvent(LOGTAG_INPUT_FOCUS,
"Transfer focus request " + newFocusTarget,
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 7d54ea95579e..499fbf61a1c3 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -249,7 +249,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
for (int i = 0, n = hops.size(); i < n; ++i) {
final WindowContainerTransaction.HierarchyOp hop = hops.get(i);
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
- if (!wc.isAttached()) {
+ if (wc == null || !wc.isAttached()) {
Slog.e(TAG, "Attempt to operate on detached container: " + wc);
continue;
}
@@ -260,7 +260,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (transition != null) {
transition.collect(wc);
if (hop.isReparent() && hop.getNewParent() != null) {
- transition.collect(WindowContainer.fromBinder(hop.getNewParent()));
+ final WindowContainer parentWc =
+ WindowContainer.fromBinder(hop.getNewParent());
+ if (parentWc == null) {
+ Slog.e(TAG, "Can't resolve parent window from token");
+ continue;
+ }
+ transition.collect(parentWc);
}
}
}
@@ -269,7 +275,12 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
entries = t.getChanges().entrySet().iterator();
while (entries.hasNext()) {
final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next();
- final Task task = WindowContainer.fromBinder(entry.getKey()).asTask();
+ final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
+ if (wc == null || !wc.isAttached()) {
+ Slog.e(TAG, "Attempt to operate on detached container: " + wc);
+ continue;
+ }
+ final Task task = wc.asTask();
final Rect surfaceBounds = entry.getValue().getBoundsChangeSurfaceBounds();
if (task == null || !task.isAttached() || surfaceBounds == null) {
continue;
@@ -423,12 +434,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (hop.isReparent()) {
final boolean isNonOrganizedRootableTask =
- (task.isRootTask() && !task.mCreatedByOrganizer)
- || task.getParent().asTask().mCreatedByOrganizer;
+ task.isRootTask() || task.getParent().asTask().mCreatedByOrganizer;
if (isNonOrganizedRootableTask) {
WindowContainer newParent = hop.getNewParent() == null
? dc.getDefaultTaskDisplayArea()
: WindowContainer.fromBinder(hop.getNewParent());
+ if (newParent == null) {
+ Slog.e(TAG, "Can't resolve parent window from token");
+ return 0;
+ }
if (task.getParent() != newParent) {
if (newParent instanceof TaskDisplayArea) {
// For now, reparenting to displayarea is different from other reparents...
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 5bfa662ea4cb..bb76a0dff78c 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -137,8 +137,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
private volatile String mRequiredAbi;
// Running any services that are foreground?
private volatile boolean mHasForegroundServices;
- // Running any activities that are foreground?
- private volatile boolean mHasForegroundActivities;
// Are there any client services with activities?
private volatile boolean mHasClientActivities;
// Is this process currently showing a non-activity UI that the user is interacting with?
@@ -226,10 +224,12 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
private final BackgroundActivityStartCallback mBackgroundActivityStartCallback;
// The bits used for mActivityStateFlags.
- private static final int ACTIVITY_STATE_FLAG_IS_VISIBLE = 0x10000000;
- private static final int ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED = 0x20000000;
- private static final int ACTIVITY_STATE_FLAG_IS_STOPPING = 0x40000000;
- private static final int ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING = 0x80000000;
+ private static final int ACTIVITY_STATE_FLAG_IS_VISIBLE = 1 << 16;
+ private static final int ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED = 1 << 17;
+ private static final int ACTIVITY_STATE_FLAG_IS_STOPPING = 1 << 18;
+ private static final int ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING = 1 << 19;
+ private static final int ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE = 1 << 20;
+ private static final int ACTIVITY_STATE_FLAG_HAS_RESUMED = 1 << 21;
private static final int ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER = 0x0000ffff;
/**
@@ -281,6 +281,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// configuration will update when display is ready.
if (thread != null) {
setLastReportedConfiguration(getConfiguration());
+ } else {
+ // The process is inactive.
+ mAtm.mVisibleActivityProcessTracker.removeProcess(this);
}
}
}
@@ -349,12 +352,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return mHasForegroundServices;
}
- public void setHasForegroundActivities(boolean hasForegroundActivities) {
- mHasForegroundActivities = hasForegroundActivities;
- }
-
boolean hasForegroundActivities() {
- return mHasForegroundActivities;
+ return mAtm.mTopApp == this || (mActivityStateFlags
+ & (ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED
+ | ACTIVITY_STATE_FLAG_IS_STOPPING)) != 0;
}
public void setHasClientActivities(boolean hasClientActivities) {
@@ -515,29 +516,33 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
}
- boolean areBackgroundActivityStartsAllowed() {
- // allow if any activity in the caller has either started or finished very recently, and
- // it must be started or finished after last stop app switches time.
- final long now = SystemClock.uptimeMillis();
- if (now - mLastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS
- || now - mLastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) {
- // if activity is started and finished before stop app switch time, we should not
- // let app to be able to start background activity even it's in grace period.
- if (mLastActivityLaunchTime > mAtm.getLastStopAppSwitchesTime()
- || mLastActivityFinishTime > mAtm.getLastStopAppSwitchesTime()) {
+ boolean areBackgroundActivityStartsAllowed(boolean appSwitchAllowed) {
+ // If app switching is not allowed, we ignore all the start activity grace period
+ // exception so apps cannot start itself in onPause() after pressing home button.
+ if (appSwitchAllowed) {
+ // allow if any activity in the caller has either started or finished very recently, and
+ // it must be started or finished after last stop app switches time.
+ final long now = SystemClock.uptimeMillis();
+ if (now - mLastActivityLaunchTime < ACTIVITY_BG_START_GRACE_PERIOD_MS
+ || now - mLastActivityFinishTime < ACTIVITY_BG_START_GRACE_PERIOD_MS) {
+ // if activity is started and finished before stop app switch time, we should not
+ // let app to be able to start background activity even it's in grace period.
+ if (mLastActivityLaunchTime > mAtm.getLastStopAppSwitchesTime()
+ || mLastActivityFinishTime > mAtm.getLastStopAppSwitchesTime()) {
+ if (DEBUG_ACTIVITY_STARTS) {
+ Slog.d(TAG, "[WindowProcessController(" + mPid
+ + ")] Activity start allowed: within "
+ + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
+ }
+ return true;
+ }
if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[WindowProcessController(" + mPid
- + ")] Activity start allowed: within "
- + ACTIVITY_BG_START_GRACE_PERIOD_MS + "ms grace period");
+ Slog.d(TAG, "[WindowProcessController(" + mPid + ")] Activity start within "
+ + ACTIVITY_BG_START_GRACE_PERIOD_MS
+ + "ms grace period but also within stop app switch window");
}
- return true;
- }
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[WindowProcessController(" + mPid + ")] Activity start within "
- + ACTIVITY_BG_START_GRACE_PERIOD_MS
- + "ms grace period but also within stop app switch window");
- }
+ }
}
// allow if the proc is instrumenting with background activity starts privs
if (mInstrumentingWithBackgroundActivityStartPrivileges) {
@@ -549,7 +554,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return true;
}
// allow if the caller has an activity in any foreground task
- if (hasActivityInVisibleTask()) {
+ if (appSwitchAllowed && hasActivityInVisibleTask()) {
if (DEBUG_ACTIVITY_STARTS) {
Slog.d(TAG, "[WindowProcessController(" + mPid
+ ")] Activity start allowed: process has activity in foreground task");
@@ -892,16 +897,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
boolean hasResumedActivity() {
- for (int i = mActivities.size() - 1; i >= 0; --i) {
- final ActivityRecord activity = mActivities.get(i);
- if (activity.isState(RESUMED)) {
- return true;
- }
- }
- return false;
+ return (mActivityStateFlags & ACTIVITY_STATE_FLAG_HAS_RESUMED) != 0;
}
-
void updateIntentForHeavyWeightActivity(Intent intent) {
if (mActivities.isEmpty()) {
return;
@@ -1041,10 +1039,14 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// Since there could be more than one activities in a process record, we don't need to
// compute the OomAdj with each of them, just need to find out the activity with the
// "best" state, the order would be visible, pausing, stopping...
- Task.ActivityState best = DESTROYED;
- boolean finishing = true;
+ Task.ActivityState bestInvisibleState = DESTROYED;
+ boolean allStoppingFinishing = true;
boolean visible = false;
int minTaskLayer = Integer.MAX_VALUE;
+ int stateFlags = 0;
+ final boolean wasResumed = hasResumedActivity();
+ final boolean wasAnyVisible = (mActivityStateFlags
+ & (ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE)) != 0;
for (int i = mActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = mActivities.get(i);
if (r.app != this) {
@@ -1057,7 +1059,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
continue;
}
}
+ if (r.isVisible()) {
+ stateFlags |= ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE;
+ }
if (r.mVisibleRequested) {
+ if (r.isState(RESUMED)) {
+ stateFlags |= ACTIVITY_STATE_FLAG_HAS_RESUMED;
+ }
final Task task = r.getTask();
if (task != null && minTaskLayer > 0) {
final int layer = task.mLayerRank;
@@ -1069,29 +1077,39 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// continue the loop, in case there are multiple visible activities in
// this process, we'd find out the one with the minimal layer, thus it'll
// get a higher adj score.
- } else if (best != PAUSING && best != PAUSED) {
+ } else if (!visible && bestInvisibleState != PAUSING) {
if (r.isState(PAUSING, PAUSED)) {
- best = PAUSING;
+ bestInvisibleState = PAUSING;
} else if (r.isState(STOPPING)) {
- best = STOPPING;
+ bestInvisibleState = STOPPING;
// Not "finishing" if any of activity isn't finishing.
- finishing &= r.finishing;
+ allStoppingFinishing &= r.finishing;
}
}
}
- int stateFlags = minTaskLayer & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
+ stateFlags |= minTaskLayer & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
if (visible) {
stateFlags |= ACTIVITY_STATE_FLAG_IS_VISIBLE;
- } else if (best == PAUSING) {
+ } else if (bestInvisibleState == PAUSING) {
stateFlags |= ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED;
- } else if (best == STOPPING) {
+ } else if (bestInvisibleState == STOPPING) {
stateFlags |= ACTIVITY_STATE_FLAG_IS_STOPPING;
- if (finishing) {
+ if (allStoppingFinishing) {
stateFlags |= ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING;
}
}
mActivityStateFlags = stateFlags;
+
+ final boolean anyVisible = (stateFlags
+ & (ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE)) != 0;
+ if (!wasAnyVisible && anyVisible) {
+ mAtm.mVisibleActivityProcessTracker.onAnyActivityVisible(this);
+ } else if (wasAnyVisible && !anyVisible) {
+ mAtm.mVisibleActivityProcessTracker.onAllActivitiesInvisible(this);
+ } else if (wasAnyVisible && !wasResumed && hasResumedActivity()) {
+ mAtm.mVisibleActivityProcessTracker.onActivityResumedWhileVisible(this);
+ }
}
/** Called when the process has some oom related changes and it is going to update oom-adj. */
@@ -1643,6 +1661,32 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
pw.println(prefix + " Configuration=" + getConfiguration());
pw.println(prefix + " OverrideConfiguration=" + getRequestedOverrideConfiguration());
pw.println(prefix + " mLastReportedConfiguration=" + mLastReportedConfiguration);
+
+ final int stateFlags = mActivityStateFlags;
+ if (stateFlags != ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER) {
+ pw.print(prefix + " mActivityStateFlags=");
+ if ((stateFlags & ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE) != 0) {
+ pw.print("W|");
+ }
+ if ((stateFlags & ACTIVITY_STATE_FLAG_IS_VISIBLE) != 0) {
+ pw.print("V|");
+ if ((stateFlags & ACTIVITY_STATE_FLAG_HAS_RESUMED) != 0) {
+ pw.print("R|");
+ }
+ } else if ((stateFlags & ACTIVITY_STATE_FLAG_IS_PAUSING_OR_PAUSED) != 0) {
+ pw.print("P|");
+ } else if ((stateFlags & ACTIVITY_STATE_FLAG_IS_STOPPING) != 0) {
+ pw.print("S|");
+ if ((stateFlags & ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING) != 0) {
+ pw.print("F|");
+ }
+ }
+ final int taskLayer = stateFlags & ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER;
+ if (taskLayer != ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER) {
+ pw.print("taskLayer=" + taskLayer);
+ }
+ pw.println();
+ }
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9234390940f7..04d777299ecc 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -309,7 +309,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/**
* The visibility flag of the window based on policy like {@link WindowManagerPolicy}.
- * Normally set by calling {@link #showLw} and {@link #hideLw}.
+ * Normally set by calling {@link #show} and {@link #hide}.
*
* TODO: b/131253938 This will eventually be split into individual visibility policy flags.
*/
@@ -556,9 +556,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
boolean mWindowRemovalAllowed;
// Input channel and input window handle used by the input dispatcher.
- final InputWindowHandle mInputWindowHandle;
+ final InputWindowHandleWrapper mInputWindowHandle;
InputChannel mInputChannel;
+ /**
+ * The token will be assigned to {@link InputWindowHandle#token} if this window can receive
+ * input event. Note that the token of associated input window handle can be cleared if this
+ * window becomes unable to receive input, but this field will remain until the input channel
+ * is actually disposed.
+ */
+ IBinder mInputChannelToken;
+
// Used to improve performance of toString()
private String mStringNameCache;
private CharSequence mLastTitle;
@@ -686,6 +694,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
private @Nullable InsetsSourceProvider mControllableInsetProvider;
private final InsetsState mRequestedInsetsState = new InsetsState();
+ @Nullable InsetsSourceProvider mPendingPositionChanged;
+
private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
private KeyInterceptionInfo mKeyInterceptionInfo;
@@ -856,6 +866,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
DeathRecipient deathRecipient = new DeathRecipient();
mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
+ mInputWindowHandle = new InputWindowHandleWrapper(new InputWindowHandle(
+ mActivityRecord != null
+ ? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
+ getDisplayId()));
+ mInputWindowHandle.setOwnerPid(s.mPid);
+ mInputWindowHandle.setOwnerUid(s.mUid);
+ mInputWindowHandle.setName(getName());
+ mInputWindowHandle.setPackageName(mAttrs.packageName);
+ mInputWindowHandle.setLayoutParamsType(mAttrs.type);
+ // Check private trusted overlay flag and window type to set trustedOverlay variable of
+ // input window handle.
+ mInputWindowHandle.setTrustedOverlay(
+ ((mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
+ && mOwnerCanAddInternalSystemWindow)
+ || InputMonitor.isTrustedOverlay(mAttrs.type));
if (DEBUG) {
Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
+ " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -871,7 +896,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mIsFloatingLayer = false;
mBaseLayer = 0;
mSubLayer = 0;
- mInputWindowHandle = null;
mWinAnimator = null;
mWpcForDisplayConfigChanges = null;
return;
@@ -919,16 +943,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
mLayer = 0;
- mInputWindowHandle = new InputWindowHandle(
- mActivityRecord != null ? mActivityRecord.mInputApplicationHandle : null,
- getDisplayId());
-
- // Check private trusted overlay flag and window type to set trustedOverlay variable of
- // input window handle.
- mInputWindowHandle.trustedOverlay =
- (mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
- && mOwnerCanAddInternalSystemWindow;
- mInputWindowHandle.trustedOverlay |= InputMonitor.isTrustedOverlay(mAttrs.type);
// Make sure we initial all fields before adding to parentWindow, to prevent exception
// during onDisplayChanged.
@@ -1496,9 +1510,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
super.onDisplayChanged(dc);
// Window was not laid out for this display yet, so make sure mLayoutSeq does not match.
- if (dc != null && mInputWindowHandle.displayId != dc.getDisplayId()) {
+ if (dc != null && mInputWindowHandle.getDisplayId() != dc.getDisplayId()) {
mLayoutSeq = dc.mLayoutSeq - 1;
- mInputWindowHandle.displayId = dc.getDisplayId();
+ mInputWindowHandle.setDisplayId(dc.getDisplayId());
}
}
@@ -1532,8 +1546,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return state;
}
- @Override
- public int getDisplayId() {
+ int getDisplayId() {
final DisplayContent displayContent = getDisplayContent();
if (displayContent == null) {
return Display.INVALID_DISPLAY;
@@ -1717,11 +1730,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
&& !mAnimatingExit && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
}
- @Override
- public boolean isVisibleLw() {
- return isVisible();
- }
-
/**
* Is this window visible, ignoring its app token? It is not visible if there is no surface,
* or we are in the process of running an exit animation that will remove the surface.
@@ -1937,7 +1945,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Unnecessary to redraw a drawn starting window.
return;
}
- } else if (mActivityRecord.startingWindow != null) {
+ } else if (mActivityRecord.mStartingWindow != null) {
// If the activity has an active starting window, there is no need to wait for the
// main window.
return;
@@ -2126,6 +2134,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return getDisplayContent().getBounds().equals(getBounds());
}
+ private boolean matchesRootDisplayAreaBounds() {
+ RootDisplayArea root = getRootDisplayArea();
+ if (root == null || root == getDisplayContent()) {
+ return matchesDisplayBounds();
+ }
+ return root.getBounds().equals(getBounds());
+ }
+
/**
* @return {@code true} if last applied config was reported to the client already, {@code false}
* otherwise.
@@ -2470,7 +2486,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
String name = getName();
mInputChannel = mWmService.mInputManager.createInputChannel(name);
- mInputWindowHandle.token = mInputChannel.getToken();
+ mInputChannelToken = mInputChannel.getToken();
+ mInputWindowHandle.setToken(mInputChannelToken);
+ mWmService.mInputToWindowMap.put(mInputChannelToken, this);
if (outInputChannel != null) {
mInputChannel.copyTo(outInputChannel);
} else {
@@ -2479,7 +2497,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Create fake event receiver that simply reports all events as handled.
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mInputChannel);
}
- mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this);
}
void disposeInputChannel() {
@@ -2487,17 +2504,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mDeadWindowEventReceiver.dispose();
mDeadWindowEventReceiver = null;
}
+ if (mInputChannelToken != null) {
+ // Unregister server channel first otherwise it complains about broken channel.
+ mWmService.mInputManager.removeInputChannel(mInputChannelToken);
+ mWmService.mKeyInterceptionInfoForToken.remove(mInputChannelToken);
+ mWmService.mInputToWindowMap.remove(mInputChannelToken);
+ mInputChannelToken = null;
+ }
- // unregister server channel first otherwise it complains about broken channel
if (mInputChannel != null) {
- mWmService.mInputManager.removeInputChannel(mInputChannel.getToken());
-
mInputChannel.dispose();
mInputChannel = null;
}
- mWmService.mKeyInterceptionInfoForToken.remove(mInputWindowHandle.token);
- mWmService.mInputToWindowMap.remove(mInputWindowHandle.token);
- mInputWindowHandle.token = null;
+ mInputWindowHandle.setToken(null);
}
/** Returns true if the replacement window was removed. */
@@ -2567,11 +2586,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- int getSurfaceTouchableRegion(InputWindowHandle inputWindowHandle, int flags) {
+ int getSurfaceTouchableRegion(Region region, int flags) {
final boolean modal = (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
- final Region region = inputWindowHandle.touchableRegion;
- setTouchableRegionCropIfNeeded(inputWindowHandle);
-
if (modal) {
flags |= FLAG_NOT_TOUCH_MODAL;
if (mActivityRecord != null) {
@@ -2593,7 +2609,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
// Translate to surface based coordinates.
- region.translate(-mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top);
+ final Rect frame = mWindowFrames.mFrame;
+ if (frame.left != 0 || frame.top != 0) {
+ region.translate(-frame.left, -frame.top);
+ }
// TODO(b/139804591): sizecompat layout needs to be reworked. Currently mFrame is post-
// scaling but the existing logic doesn't expect that. The result is that the already-
@@ -2772,13 +2791,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void adjustStartingWindowFlags() {
if (mAttrs.type == TYPE_BASE_APPLICATION && mActivityRecord != null
- && mActivityRecord.startingWindow != null) {
+ && mActivityRecord.mStartingWindow != null) {
// Special handling of starting window over the base
// window of the app: propagate lock screen flags to it,
// to provide the correct semantics while starting.
final int mask = FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD
| FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
- WindowManager.LayoutParams sa = mActivityRecord.startingWindow.mAttrs;
+ WindowManager.LayoutParams sa = mActivityRecord.mStartingWindow.mAttrs;
sa.flags = (sa.flags & ~mask) | (mAttrs.flags & mask);
}
}
@@ -2937,12 +2956,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mWinAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN;
}
- @Override
- public boolean showLw(boolean doAnimation) {
- return showLw(doAnimation, true);
- }
-
- boolean showLw(boolean doAnimation, boolean requestAnim) {
+ /**
+ * Can be called to undo the effect of {@link #hide}, allowing a window to be shown as long
+ * as the client would also like it to be shown.
+ */
+ boolean show(boolean doAnimation, boolean requestAnim) {
if (isLegacyPolicyVisibility() && mLegacyPolicyVisibilityAfterAnim) {
// Already showing.
return false;
@@ -2995,12 +3013,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return true;
}
- @Override
- public boolean hideLw(boolean doAnimation) {
- return hideLw(doAnimation, true);
- }
-
- boolean hideLw(boolean doAnimation, boolean requestAnim) {
+ /** Forces the window to be hidden, regardless of whether the client like it shown. */
+ boolean hide(boolean doAnimation, boolean requestAnim) {
if (doAnimation) {
if (!mToken.okToAnimate()) {
doAnimation = false;
@@ -3052,9 +3066,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
mForceHideNonSystemOverlayWindow = forceHide;
if (forceHide) {
- hideLw(true /* doAnimation */, true /* requestAnim */);
+ hide(true /* doAnimation */, true /* requestAnim */);
} else {
- showLw(true /* doAnimation */, true /* requestAnim */);
+ show(true /* doAnimation */, true /* requestAnim */);
}
}
@@ -3068,9 +3082,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
mHiddenWhileSuspended = hide;
if (hide) {
- hideLw(true, true);
+ hide(true /* doAnimation */, true /* requestAnim */);
} else {
- showLw(true, true);
+ show(true /* doAnimation */, true /* requestAnim */);
}
}
@@ -3084,9 +3098,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// ops modifies they should only be hidden by policy due to the
// lock screen, and the user won't be changing this if locked.
// Plus it will quickly be fixed the next time we do a layout.
- showLw(true, true);
+ show(true /* doAnimation */, true /* requestAnim */);
} else {
- hideLw(true, true);
+ hide(true /* doAnimation */, true /* requestAnim */);
}
}
}
@@ -3140,7 +3154,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
public void hidePermanentlyLw() {
if (!mPermanentlyHidden) {
mPermanentlyHidden = true;
- hideLw(true, true);
+ hide(true /* doAnimation */, true /* requestAnim */);
}
}
@@ -3442,7 +3456,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
break;
case TOUCHABLE_INSETS_REGION: {
outRegion.set(mGivenTouchableRegion);
- outRegion.translate(frame.left, frame.top);
+ if (frame.left != 0 || frame.top != 0) {
+ outRegion.translate(frame.left, frame.top);
+ }
break;
}
}
@@ -3469,22 +3485,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- private void setTouchableRegionCropIfNeeded(InputWindowHandle handle) {
- final Task task = getTask();
- if (task == null || !task.cropWindowsToStackBounds()) {
- handle.setTouchableRegionCrop(null);
- return;
- }
-
- final Task stack = task.getRootTask();
- if (stack == null || inFreeformWindowingMode()) {
- handle.setTouchableRegionCrop(null);
- return;
- }
-
- handle.setTouchableRegionCrop(stack.getSurfaceControl());
- }
-
private void cropRegionToStackBoundsIfNeeded(Region region) {
final Task task = getTask();
if (task == null || !task.cropWindowsToStackBounds()) {
@@ -3780,7 +3780,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/** @return true when the window is in fullscreen mode, but has non-fullscreen bounds set, or
* is transitioning into/out-of fullscreen. */
boolean isLetterboxedAppWindow() {
- return !inMultiWindowMode() && !matchesDisplayBounds()
+ return !inMultiWindowMode() && !matchesRootDisplayAreaBounds()
|| isLetterboxedForDisplayCutout();
}
@@ -4426,11 +4426,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- @Override
- public boolean isInputMethodWindow() {
- return mIsImWindow;
- }
-
// This must be called while inside a transaction.
boolean performShowLocked() {
if (!showToCurrentUser()) {
@@ -4958,7 +4953,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
int relayoutVisibleWindow(int result, int attrChanges) {
- final boolean wasVisible = isVisibleLw();
+ final boolean wasVisible = isVisible();
result |= (!wasVisible || !isDrawn()) ? RELAYOUT_RES_FIRST_TIME : 0;
@@ -5453,8 +5448,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
super.assignLayer(t, layer);
}
- @Override
- public boolean isDimming() {
+ boolean isDimming() {
return mIsDimming;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index d845b123a560..0fd8146082dc 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -488,6 +488,9 @@ class WindowStateAnimator {
mSurfaceFormat = format;
w.setHasSurface(true);
+ // The surface instance is changed. Make sure the input info can be applied to the
+ // new surface, e.g. relaunch activity.
+ w.mInputWindowHandle.forceChange();
ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
" CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x / %s",
@@ -529,7 +532,7 @@ class WindowStateAnimator {
void destroySurfaceLocked() {
final ActivityRecord activity = mWin.mActivityRecord;
if (activity != null) {
- if (mWin == activity.startingWindow) {
+ if (mWin == activity.mStartingWindow) {
activity.startingDisplayed = false;
}
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index aac60b406ca8..da2c005d7332 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -162,9 +162,10 @@ cc_defaults {
"android.frameworks.schedulerservice@1.0",
"android.frameworks.sensorservice@1.0",
"android.frameworks.stats@1.0",
+ "android.system.suspend.control-cpp",
+ "android.system.suspend.control.internal-cpp",
"android.system.suspend@1.0",
"service.incremental",
- "suspend_control_aidl_interface-cpp",
],
static_libs: [
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index c1d5f19fd256..3a001965402f 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -650,7 +650,7 @@ std::shared_ptr<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
base::Result<std::shared_ptr<KeyCharacterMap>> ret =
KeyCharacterMap::loadContents(filenameChars.c_str(), contentsChars.c_str(),
- KeyCharacterMap::FORMAT_OVERLAY);
+ KeyCharacterMap::Format::OVERLAY);
if (ret) {
result = *ret;
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e9d048a69966..3bff4404754a 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -3514,10 +3514,11 @@ static jboolean android_location_GnssConfiguration_set_gnss_pos_protocol_select(
return gnssConfigurationIface->setGlonassPositioningProtocol(gnssPosProtocol);
}
-static jboolean android_location_GnssConfiguration_set_satellite_blacklist(
- JNIEnv* env, jobject, jintArray constellations, jintArray sv_ids) {
+static jboolean android_location_GnssConfiguration_set_satellite_blocklist(JNIEnv* env, jobject,
+ jintArray constellations,
+ jintArray sv_ids) {
if (gnssConfigurationIface == nullptr) {
- ALOGI("IGnssConfiguration interface does not support satellite blacklist.");
+ ALOGI("IGnssConfiguration interface does not support satellite blocklist.");
return JNI_FALSE;
}
return gnssConfigurationIface->setBlocklist(env, constellations, sv_ids);
@@ -3532,7 +3533,7 @@ static jboolean android_location_GnssConfiguration_set_es_extension_sec(
return gnssConfigurationIface->setEsExtensionSec(emergencyExtensionSeconds);
}
-static jint android_location_GnssBatchingProvider_get_batch_size(JNIEnv*, jclass) {
+static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return 0; // batching not supported, size = 0
}
@@ -3544,7 +3545,7 @@ static jint android_location_GnssBatchingProvider_get_batch_size(JNIEnv*, jclass
return static_cast<jint>(result);
}
-static jboolean android_location_GnssBatchingProvider_init_batching(JNIEnv*, jclass) {
+static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jclass) {
if (gnssBatchingIface_V2_0 != nullptr) {
sp<IGnssBatchingCallback_V2_0> gnssBatchingCbIface_V2_0 = new GnssBatchingCallback_V2_0();
auto result = gnssBatchingIface_V2_0->init_2_0(gnssBatchingCbIface_V2_0);
@@ -3558,7 +3559,7 @@ static jboolean android_location_GnssBatchingProvider_init_batching(JNIEnv*, jcl
}
}
-static void android_location_GnssBatchingProvider_cleanup_batching(JNIEnv*, jclass) {
+static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return; // batching not supported
}
@@ -3566,8 +3567,9 @@ static void android_location_GnssBatchingProvider_cleanup_batching(JNIEnv*, jcla
checkHidlReturn(result, "IGnssBatching cleanup() failed.");
}
-static jboolean android_location_GnssBatchingProvider_start_batch(JNIEnv*, jclass,
- jlong periodNanos, jboolean wakeOnFifoFull) {
+static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclass,
+ jlong periodNanos,
+ jboolean wakeOnFifoFull) {
if (gnssBatchingIface == nullptr) {
return JNI_FALSE; // batching not supported
}
@@ -3584,7 +3586,7 @@ static jboolean android_location_GnssBatchingProvider_start_batch(JNIEnv*, jclas
return checkHidlReturn(result, "IGnssBatching start() failed.");
}
-static void android_location_GnssBatchingProvider_flush_batch(JNIEnv*, jclass) {
+static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return; // batching not supported
}
@@ -3592,7 +3594,7 @@ static void android_location_GnssBatchingProvider_flush_batch(JNIEnv*, jclass) {
checkHidlReturn(result, "IGnssBatching flush() failed.");
}
-static jboolean android_location_GnssBatchingProvider_stop_batch(JNIEnv*, jclass) {
+static jboolean android_location_GnssLocationProvider_stop_batch(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return JNI_FALSE; // batching not supported
}
@@ -3670,25 +3672,19 @@ static const JNINativeMethod sLocationProviderMethods[] = {
};
static const JNINativeMethod sMethodsBatching[] = {
- /* name, signature, funcPtr */
- {"native_get_batch_size",
- "()I",
- reinterpret_cast<void *>(android_location_GnssBatchingProvider_get_batch_size)},
- {"native_start_batch",
- "(JZ)Z",
- reinterpret_cast<void *>(android_location_GnssBatchingProvider_start_batch)},
- {"native_flush_batch",
- "()V",
- reinterpret_cast<void *>(android_location_GnssBatchingProvider_flush_batch)},
- {"native_stop_batch",
- "()Z",
- reinterpret_cast<void *>(android_location_GnssBatchingProvider_stop_batch)},
- {"native_init_batching",
- "()Z",
- reinterpret_cast<void *>(android_location_GnssBatchingProvider_init_batching)},
- {"native_cleanup_batching",
- "()V",
- reinterpret_cast<void *>(android_location_GnssBatchingProvider_cleanup_batching)},
+ /* name, signature, funcPtr */
+ {"native_get_batch_size", "()I",
+ reinterpret_cast<void*>(android_location_GnssLocationProvider_get_batch_size)},
+ {"native_start_batch", "(JZ)Z",
+ reinterpret_cast<void*>(android_location_GnssLocationProvider_start_batch)},
+ {"native_flush_batch", "()V",
+ reinterpret_cast<void*>(android_location_GnssLocationProvider_flush_batch)},
+ {"native_stop_batch", "()Z",
+ reinterpret_cast<void*>(android_location_GnssLocationProvider_stop_batch)},
+ {"native_init_batching", "()Z",
+ reinterpret_cast<void*>(android_location_GnssLocationProvider_init_batching)},
+ {"native_cleanup_batching", "()V",
+ reinterpret_cast<void*>(android_location_GnssLocationProvider_cleanup_batching)},
};
static const JNINativeMethod sAntennaInfoMethods[] = {
@@ -3800,8 +3796,8 @@ static const JNINativeMethod sConfigurationMethods[] = {
reinterpret_cast<void*>(android_location_GnssConfiguration_set_gps_lock)},
{"native_set_emergency_supl_pdn", "(I)Z",
reinterpret_cast<void*>(android_location_GnssConfiguration_set_emergency_supl_pdn)},
- {"native_set_satellite_blacklist", "([I[I)Z",
- reinterpret_cast<void*>(android_location_GnssConfiguration_set_satellite_blacklist)},
+ {"native_set_satellite_blocklist", "([I[I)Z",
+ reinterpret_cast<void*>(android_location_GnssConfiguration_set_satellite_blocklist)},
{"native_set_es_extension_sec", "(I)Z",
reinterpret_cast<void*>(android_location_GnssConfiguration_set_es_extension_sec)},
};
@@ -3817,7 +3813,7 @@ static const JNINativeMethod sVisibilityControlMethods[] = {
int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssAntennaInfoProvider",
sAntennaInfoMethods, NELEM(sAntennaInfoMethods));
- jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssBatchingProvider",
+ jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssLocationProvider",
sMethodsBatching, NELEM(sMethodsBatching));
jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssGeofenceProvider",
sGeofenceMethods, NELEM(sGeofenceMethods));
diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
index 0275f3ea32f7..10b248a70e7e 100644
--- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
@@ -215,21 +215,6 @@ static const JNINativeMethod gMethods[] = {
};
int register_android_server_net_NetworkStatsService(JNIEnv* env) {
- jclass netStatsService = env->FindClass("com/android/server/net/NetworkStatsService");
- jfieldID rxBytesId = env->GetStaticFieldID(netStatsService, "TYPE_RX_BYTES", "I");
- jfieldID rxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_RX_PACKETS", "I");
- jfieldID txBytesId = env->GetStaticFieldID(netStatsService, "TYPE_TX_BYTES", "I");
- jfieldID txPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TX_PACKETS", "I");
- jfieldID tcpRxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TCP_RX_PACKETS", "I");
- jfieldID tcpTxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TCP_TX_PACKETS", "I");
-
- env->SetStaticIntField(netStatsService, rxBytesId, RX_BYTES);
- env->SetStaticIntField(netStatsService, rxPacketsId, RX_PACKETS);
- env->SetStaticIntField(netStatsService, txBytesId, TX_BYTES);
- env->SetStaticIntField(netStatsService, txPacketsId, TX_PACKETS);
- env->SetStaticIntField(netStatsService, tcpRxPacketsId, TCP_RX_PACKETS);
- env->SetStaticIntField(netStatsService, tcpTxPacketsId, TCP_TX_PACKETS);
-
return jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsService", gMethods,
NELEM(gMethods));
}
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 91f70729d5b6..63a6eedd9e66 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -24,6 +24,7 @@
#include <android/hardware/power/Mode.h>
#include <android/system/suspend/1.0/ISystemSuspend.h>
#include <android/system/suspend/ISuspendControlService.h>
+#include <android/system/suspend/internal/ISuspendControlServiceInternal.h>
#include <nativehelper/JNIHelp.h>
#include "jni.h"
@@ -133,6 +134,8 @@ void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t
static sp<ISystemSuspend> gSuspendHal = nullptr;
static sp<ISuspendControlService> gSuspendControl = nullptr;
+static sp<system::suspend::internal::ISuspendControlServiceInternal> gSuspendControlInternal =
+ nullptr;
static sp<IWakeLock> gSuspendBlocker = nullptr;
static std::mutex gSuspendMutex;
@@ -157,10 +160,22 @@ sp<ISuspendControlService> getSuspendControl() {
return gSuspendControl;
}
+sp<system::suspend::internal::ISuspendControlServiceInternal> getSuspendControlInternal() {
+ static std::once_flag suspendControlFlag;
+ std::call_once(suspendControlFlag, []() {
+ gSuspendControlInternal =
+ waitForService<system::suspend::internal::ISuspendControlServiceInternal>(
+ String16("suspend_control_internal"));
+ LOG_ALWAYS_FATAL_IF(gSuspendControlInternal == nullptr);
+ });
+ return gSuspendControlInternal;
+}
+
void enableAutoSuspend() {
static bool enabled = false;
if (!enabled) {
- sp<ISuspendControlService> suspendControl = getSuspendControl();
+ sp<system::suspend::internal::ISuspendControlServiceInternal> suspendControl =
+ getSuspendControlInternal();
suspendControl->enableAutosuspend(&enabled);
}
@@ -227,7 +242,7 @@ static jboolean nativeSetPowerMode(JNIEnv* /* env */, jclass /* clazz */, jint m
static bool nativeForceSuspend(JNIEnv* /* env */, jclass /* clazz */) {
bool retval = false;
- getSuspendControl()->forceSuspend(&retval);
+ getSuspendControlInternal()->forceSuspend(&retval);
return retval;
}
diff --git a/services/core/xsd/cec-config/cec-config.xsd b/services/core/xsd/cec-config/cec-config.xsd
index 0801c88c54ad..b59c93cce332 100644
--- a/services/core/xsd/cec-config/cec-config.xsd
+++ b/services/core/xsd/cec-config/cec-config.xsd
@@ -12,6 +12,7 @@
</xs:element>
<xs:complexType name="setting">
<xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="value-type" type="xs:string"/>
<xs:attribute name="user-configurable" type="xs:boolean"/>
<xs:element name="allowed-values" type="value-list" minOccurs="1" maxOccurs="1"/>
<xs:element name="default-value" type="value" minOccurs="1" maxOccurs="1"/>
@@ -23,5 +24,6 @@
</xs:complexType>
<xs:complexType name="value">
<xs:attribute name="string-value" type="xs:string"/>
+ <xs:attribute name="int-value" type="xs:string"/>
</xs:complexType>
</xs:schema>
diff --git a/services/core/xsd/cec-config/schema/current.txt b/services/core/xsd/cec-config/schema/current.txt
index 34faf459d251..75872d4fb8a7 100644
--- a/services/core/xsd/cec-config/schema/current.txt
+++ b/services/core/xsd/cec-config/schema/current.txt
@@ -12,15 +12,19 @@ package com.android.server.hdmi.cec.config {
method public com.android.server.hdmi.cec.config.Value getDefaultValue();
method public String getName();
method public boolean getUserConfigurable();
+ method public String getValueType();
method public void setAllowedValues(com.android.server.hdmi.cec.config.ValueList);
method public void setDefaultValue(com.android.server.hdmi.cec.config.Value);
method public void setName(String);
method public void setUserConfigurable(boolean);
+ method public void setValueType(String);
}
public class Value {
ctor public Value();
+ method public String getIntValue();
method public String getStringValue();
+ method public void setIntValue(String);
method public void setStringValue(String);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 6fea2aaf728b..d29534e8080e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -16,6 +16,7 @@
package com.android.server.devicepolicy;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -36,10 +37,10 @@ import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.pm.UserRestrictionsUtils;
@@ -130,6 +131,7 @@ class ActiveAdmin {
private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn-package";
private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown";
private static final String TAG_COMMON_CRITERIA_MODE = "common-criteria-mode";
+ private static final String TAG_PASSWORD_COMPLEXITY = "password-complexity";
private static final String ATTR_VALUE = "value";
private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
@@ -142,6 +144,9 @@ class ActiveAdmin {
@NonNull
PasswordPolicy mPasswordPolicy = new PasswordPolicy();
+ @DevicePolicyManager.PasswordComplexity
+ int mPasswordComplexity = PASSWORD_COMPLEXITY_NONE;
+
@Nullable
FactoryResetProtectionPolicy mFactoryResetProtectionPolicy = null;
@@ -518,6 +523,10 @@ class ActiveAdmin {
if (mCommonCriteriaMode) {
writeAttributeValueToXml(out, TAG_COMMON_CRITERIA_MODE, mCommonCriteriaMode);
}
+
+ if (mPasswordComplexity != PASSWORD_COMPLEXITY_NONE) {
+ writeAttributeValueToXml(out, TAG_PASSWORD_COMPLEXITY, mPasswordComplexity);
+ }
}
void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException {
@@ -777,6 +786,8 @@ class ActiveAdmin {
} else if (TAG_COMMON_CRITERIA_MODE.equals(tag)) {
mCommonCriteriaMode = Boolean.parseBoolean(
parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_PASSWORD_COMPLEXITY.equals(tag)) {
+ mPasswordComplexity = Integer.parseInt(parser.getAttributeValue(null, ATTR_VALUE));
} else {
Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1112,5 +1123,8 @@ class ActiveAdmin {
pw.print("mCommonCriteriaMode=");
pw.println(mCommonCriteriaMode);
+
+ pw.print("mPasswordComplexity=");
+ pw.println(mPasswordComplexity);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index eff222a2051a..ce61d50df1d9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -15,8 +15,10 @@
*/
package com.android.server.devicepolicy;
+import android.app.admin.DevicePolicySafetyChecker;
import android.app.admin.IDevicePolicyManager;
import android.content.ComponentName;
+import android.util.Slog;
import com.android.server.SystemService;
@@ -30,6 +32,9 @@ import com.android.server.SystemService;
* should be added here to avoid build breakage in downstream branches.
*/
abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
+
+ private static final String TAG = BaseIDevicePolicyManager.class.getSimpleName();
+
/**
* To be called by {@link DevicePolicyManagerService#Lifecycle} during the various boot phases.
*
@@ -55,6 +60,16 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
*/
abstract void handleStopUser(int userId);
+ /**
+ * Sets the {@link DevicePolicySafetyChecker}.
+ *
+ * <p>Currently, it's called only by {@code SystemServer} on
+ * {@link android.content.pm.PackageManager#FEATURE_AUTOMOTIVE automotive builds}
+ */
+ public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
+ Slog.w(TAG, "setDevicePolicySafetyChecker() not implemented by " + getClass());
+ }
+
public void clearSystemUpdatePolicyFreezePeriodRecord() {
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
index fdde4ea36583..d812b8f7fadb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/CertificateMonitor.java
@@ -177,7 +177,7 @@ public class CertificateMonitor {
int parentUserId = userHandle.getIdentifier();
- if (mService.getProfileOwner(userHandle.getIdentifier()) != null) {
+ if (mService.getProfileOwnerAsUser(userHandle.getIdentifier()) != null) {
contentText = resources.getString(R.string.ssl_ca_cert_noti_managed,
mService.getProfileOwnerName(userHandle.getIdentifier()));
smallIconId = R.drawable.stat_sys_certificate_info;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
index 279c678421da..3067d4507162 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceAdminServiceController.java
@@ -26,12 +26,12 @@ import android.content.Context;
import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.os.IBinder;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.server.am.PersistentConnection;
import com.android.server.appbinding.AppBindingUtils;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
index d616ed30772a..15bc93e0419a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
@@ -18,11 +18,11 @@ package com.android.server.devicepolicy;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyManager;
+import android.util.IndentingPrintWriter;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.IndentingPrintWriter;
/**
* Implementation of {@link DevicePolicyCache}, to which {@link DevicePolicyManagerService} pushes
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
index fec8a80a6a76..464d6f5ea835 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
@@ -15,11 +15,10 @@
*/
package com.android.server.devicepolicy;
+import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
import android.util.Slog;
-import com.android.internal.util.IndentingPrintWriter;
-
import java.util.concurrent.TimeUnit;
/**
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3bfcb6def252..9d634bc9e9d5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -60,6 +60,9 @@ import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
import static android.app.admin.DevicePolicyManager.NON_ORG_OWNED_PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
@@ -135,9 +138,11 @@ import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.DevicePolicyManager.PersonalAppsSuspensionReason;
import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.DevicePolicySafetyChecker;
import android.app.admin.DeviceStateCache;
import android.app.admin.FactoryResetProtectionPolicy;
import android.app.admin.NetworkEvent;
@@ -148,6 +153,7 @@ import android.app.admin.SecurityLog.SecurityEvent;
import android.app.admin.StartInstallingUpdateCallback;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
+import android.app.admin.UnsafeStateException;
import android.app.backup.IBackupManager;
import android.app.trust.TrustManager;
import android.app.usage.UsageStatsManagerInternal;
@@ -244,6 +250,7 @@ import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -269,7 +276,6 @@ import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.Preconditions;
import com.android.internal.util.StatLogger;
@@ -567,6 +573,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final boolean mIsWatch;
/**
+ * Whether or not this device is an automotive.
+ */
+ private final boolean mIsAutomotive;
+
+ /**
* Whether this device has the telephony feature.
*/
final boolean mHasTelephonyFeature;
@@ -629,6 +640,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@VisibleForTesting
final TransferOwnershipMetadataManager mTransferOwnershipMetadataManager;
+ @Nullable
+ private DevicePolicySafetyChecker mSafetyChecker;
+
public static final class Lifecycle extends SystemService {
private BaseIDevicePolicyManager mService;
@@ -640,8 +654,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
dpmsClassName = DevicePolicyManagerService.class.getName();
}
try {
- Class serviceClass = Class.forName(dpmsClassName);
- Constructor constructor = serviceClass.getConstructor(Context.class);
+ Class<?> serviceClass = Class.forName(dpmsClassName);
+ Constructor<?> constructor = serviceClass.getConstructor(Context.class);
mService = (BaseIDevicePolicyManager) constructor.newInstance(context);
} catch (Exception e) {
throw new IllegalStateException(
@@ -650,6 +664,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ /** Sets the {@link DevicePolicySafetyChecker}. */
+ public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
+ mService.setDevicePolicySafetyChecker(safetyChecker);
+ }
+
@Override
public void onStart() {
publishBinderService(Context.DEVICE_POLICY_SERVICE, mService);
@@ -948,6 +967,38 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ @Override
+ public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
+ Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as " + safetyChecker.getClass());
+ mSafetyChecker = safetyChecker;
+ }
+
+ /**
+ * Checks if the feature is supported and it's safe to execute the given {@code operation}.
+ *
+ * <p>Typically called at the beginning of each API method as:
+ *
+ * <pre><code>
+ *
+ * if (!canExecute(operation, permission)) return;
+ *
+ * </code></pre>
+ *
+ * @return {@code true} when it's safe to execute, {@code false} when the feature is not
+ * supported or the caller does not have the given {@code requiredPermission}.
+ *
+ * @throws UnsafeStateException if it's not safe to execute the operation.
+ */
+ boolean canExecute(@DevicePolicyOperation int operation, @NonNull String requiredPermission) {
+ if (!mHasFeature && !hasCallingPermission(requiredPermission)) {
+ return false;
+ }
+ if (mSafetyChecker == null || mSafetyChecker.isDevicePolicyOperationSafe(operation)) {
+ return true;
+ }
+ throw mSafetyChecker.newUnsafeStateException(operation);
+ }
+
/**
* Unit test will subclass it to inject mocks.
*/
@@ -1223,10 +1274,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
SystemProperties.set(key, value);
}
+ // TODO (b/137101239): clean up split system user codes
boolean userManagerIsSplitSystemUser() {
return UserManager.isSplitSystemUser();
}
+ boolean userManagerIsHeadlessSystemUserMode() {
+ return UserManager.isHeadlessSystemUserMode();
+ }
+
String getDevicePolicyFilePathForSystemUser() {
return "/data/system/";
}
@@ -1383,6 +1439,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.hasSystemFeature(PackageManager.FEATURE_WATCH);
mHasTelephonyFeature = mInjector.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ mIsAutomotive = mInjector.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
mBackgroundHandler = BackgroundThread.getHandler();
// Needed when mHasFeature == false, because it controls the certificate warning text.
@@ -2925,8 +2983,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
synchronized (getLockObject()) {
final long now = System.currentTimeMillis();
- List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
- userHandle, /* parent */ false);
+ List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle);
final int N = admins.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = admins.get(i);
@@ -3356,7 +3413,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public boolean isSeparateProfileChallengeAllowed(int userHandle) {
enforceSystemCaller("query separate challenge support");
- ComponentName profileOwner = getProfileOwner(userHandle);
+ ComponentName profileOwner = getProfileOwnerAsUser(userHandle);
// Profile challenge is supported on N or newer release.
return profileOwner != null &&
getTargetSdk(profileOwner.getPackageName(), userHandle) > Build.VERSION_CODES.M;
@@ -3378,6 +3435,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final PasswordPolicy passwordPolicy = ap.mPasswordPolicy;
if (passwordPolicy.quality != quality) {
passwordPolicy.quality = quality;
+ ap.mPasswordComplexity = PASSWORD_COMPLEXITY_NONE;
resetInactivePasswordRequirementsIfRPlus(userId, ap);
updatePasswordValidityCheckpointLocked(userId, parent);
updatePasswordQualityCacheForUserGroup(userId);
@@ -3496,8 +3554,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
// Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+ List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+ getProfileParentUserIfRequested(userHandle, parent));
final int N = admins.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = admins.get(i);
@@ -3509,16 +3567,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
- private List<ActiveAdmin> getActiveAdminsForLockscreenPoliciesLocked(
- int userHandle, boolean parent) {
- if (!parent && isSeparateProfileChallengeEnabled(userHandle)) {
+ private List<ActiveAdmin> getActiveAdminsForLockscreenPoliciesLocked(int userHandle) {
+ if (isSeparateProfileChallengeEnabled(userHandle)) {
// If this user has a separate challenge, only return its restrictions.
return getUserDataUnchecked(userHandle).mAdminList;
}
- // Either parent == true, or isSeparateProfileChallengeEnabled == false
- // If parent is true, query the parent user of userHandle by definition,
- // If isSeparateProfileChallengeEnabled is false, userHandle points to a managed profile
- // with unified challenge so also need to query the parent user who owns the credential.
+ // If isSeparateProfileChallengeEnabled is false and userHandle points to a managed profile
+ // we need to query the parent user who owns the credential.
return getActiveAdminsForUserAndItsManagedProfilesLocked(getProfileParentId(userHandle),
(user) -> !mLockPatternUtils.isSeparateProfileChallengeEnabled(user.id));
}
@@ -3609,6 +3664,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private void ensureMinimumQuality(
int userId, ActiveAdmin admin, int minimumQuality, String operation) {
mInjector.binderWithCleanCallingIdentity(() -> {
+ // This check will also take care of the case where the password requirements
+ // are specified as complexity rather than quality: When a password complexity
+ // is set, the quality is reset to "unspecified" which will be below any value
+ // of minimumQuality.
if (admin.mPasswordPolicy.quality < minimumQuality
&& passwordQualityInvocationOrderCheckEnabled(admin.info.getPackageName(),
userId)) {
@@ -3712,8 +3771,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
// Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+ List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+ getProfileParentUserIfRequested(userHandle, parent));
final int N = admins.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = admins.get(i);
@@ -3731,11 +3790,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(admin, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+ Preconditions.checkCallAuthorization(isProfileOwner(caller));
List<String> changedProviders = null;
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ ActiveAdmin activeAdmin = getProfileOwnerLocked(caller);
if (activeAdmin.crossProfileWidgetProviders == null) {
activeAdmin.crossProfileWidgetProviders = new ArrayList<>();
}
@@ -3766,11 +3825,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(admin, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+ Preconditions.checkCallAuthorization(isProfileOwner(caller));
List<String> changedProviders = null;
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ ActiveAdmin activeAdmin = getProfileOwnerLocked(caller);
if (activeAdmin.crossProfileWidgetProviders == null
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return false;
@@ -3801,10 +3860,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(admin, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(admin);
- Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+ Preconditions.checkCallAuthorization(isProfileOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin activeAdmin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ ActiveAdmin activeAdmin = getProfileOwnerLocked(caller);
if (activeAdmin.crossProfileWidgetProviders == null
|| activeAdmin.crossProfileWidgetProviders.isEmpty()) {
return null;
@@ -3830,7 +3889,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
// Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+ List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+ getProfileParentUserIfRequested(userHandle, parent));
final int N = admins.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = admins.get(i);
@@ -4069,8 +4129,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
int maxValue = 0;
- final List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+ final List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+ getProfileParentUserIfRequested(userHandle, parent));
final int N = admins.size();
for (int i = 0; i < N; i++) {
final ActiveAdmin admin = admins.get(i);
@@ -4091,6 +4151,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
*/
@Override
public PasswordMetrics getPasswordMinimumMetrics(@UserIdInt int userHandle) {
+ final CallerIdentity caller = getCallerIdentity();
+ Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
return getPasswordMinimumMetrics(userHandle, false /* parent */);
}
@@ -4103,13 +4165,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
-
ArrayList<PasswordMetrics> adminMetrics = new ArrayList<>();
synchronized (getLockObject()) {
- List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+ List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+ getProfileParentUserIfRequested(userHandle, parent));
for (ActiveAdmin admin : admins) {
adminMetrics.add(admin.mPasswordPolicy.getMinMetrics());
}
@@ -4135,8 +4194,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
int credentialOwner = getCredentialOwner(userHandle, parent);
DevicePolicyData policy = getUserDataUnchecked(credentialOwner);
PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner);
+ final int userToCheck = getProfileParentUserIfRequested(userHandle, parent);
boolean activePasswordSufficientForUserLocked = isActivePasswordSufficientForUserLocked(
- policy.mPasswordValidAtLastCheckpoint, metrics, userHandle, parent);
+ policy.mPasswordValidAtLastCheckpoint, metrics, userToCheck);
return activePasswordSufficientForUserLocked;
}
}
@@ -4175,7 +4235,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
DevicePolicyData policy = getUserDataUnchecked(credentialOwner);
PasswordMetrics metrics = mLockSettingsInternal.getUserPasswordMetrics(credentialOwner);
return isActivePasswordSufficientForUserLocked(
- policy.mPasswordValidAtLastCheckpoint, metrics, targetUser, false);
+ policy.mPasswordValidAtLastCheckpoint, metrics, targetUser);
}
}
@@ -4205,6 +4265,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
for (ActiveAdmin admin : admins) {
adminMetrics.add(admin.mPasswordPolicy.getMinMetrics());
}
+ //TODO: Take complexity into account, would need to take complexity from all admins
+ //in the admins list.
return PasswordMetrics.validatePasswordMetrics(PasswordMetrics.merge(adminMetrics),
PASSWORD_COMPLEXITY_NONE, false, metrics).isEmpty();
}
@@ -4212,7 +4274,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private boolean isActivePasswordSufficientForUserLocked(
boolean passwordValidAtLastCheckpoint, @Nullable PasswordMetrics metrics,
- int userHandle, boolean parent) {
+ int userHandle) {
if (!mInjector.storageManagerIsFileBasedEncryptionEnabled() && (metrics == null)) {
// Before user enters their password for the first time after a reboot, return the
// value of this flag, which tells us whether the password was valid the last time
@@ -4229,7 +4291,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
throw new IllegalStateException("isActivePasswordSufficient called on FBE-locked user");
}
- return isPasswordSufficientForUserWithoutCheckpointLocked(metrics, userHandle, parent);
+ return isPasswordSufficientForUserWithoutCheckpointLocked(metrics, userHandle, false);
}
/**
@@ -4239,31 +4301,34 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
*/
private boolean isPasswordSufficientForUserWithoutCheckpointLocked(
@NonNull PasswordMetrics metrics, @UserIdInt int userId, boolean parent) {
+ final int complexity = getEffectivePasswordComplexityRequirementLocked(userId, parent);
PasswordMetrics minMetrics = getPasswordMinimumMetrics(userId, parent);
final List<PasswordValidationError> passwordValidationErrors =
PasswordMetrics.validatePasswordMetrics(
- minMetrics, PASSWORD_COMPLEXITY_NONE, false, metrics);
+ minMetrics, complexity, false, metrics);
return passwordValidationErrors.isEmpty();
}
@Override
@PasswordComplexity
public int getPasswordComplexity(boolean parent) {
+ final CallerIdentity caller = getNonPrivilegedOrAdminCallerIdentity(null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.GET_USER_PASSWORD_COMPLEXITY_LEVEL)
.setStrings(parent ? CALLED_FROM_PARENT : NOT_CALLED_FROM_PARENT,
mInjector.getPackageManager().getPackagesForUid(
mInjector.binderGetCallingUid()))
.write();
- final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(!parent || (isDeviceOwner(caller)
|| isProfileOwner(caller) || isSystemUid(caller)),
"Only profile owner, device owner and system may call this method.");
enforceUserUnlocked(caller.getUserId());
- mContext.enforceCallingOrSelfPermission(
- REQUEST_PASSWORD_COMPLEXITY,
- "Must have " + REQUEST_PASSWORD_COMPLEXITY + " permission.");
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(REQUEST_PASSWORD_COMPLEXITY)
+ || isDeviceOwner(caller) || isProfileOwner(caller),
+ "Must have " + REQUEST_PASSWORD_COMPLEXITY
+ + " permission, or be a profile owner or device owner.");
synchronized (getLockObject()) {
final int credentialOwner = getCredentialOwner(caller.getUserId(), parent);
@@ -4273,6 +4338,75 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
@Override
+ public void setRequiredPasswordComplexity(int passwordComplexity, boolean calledOnParent) {
+ if (!mHasFeature) {
+ return;
+ }
+ final Set<Integer> allowedModes = Set.of(PASSWORD_COMPLEXITY_NONE, PASSWORD_COMPLEXITY_LOW,
+ PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_COMPLEXITY_HIGH);
+ Preconditions.checkArgument(allowedModes.contains(passwordComplexity),
+ "Provided complexity is not one of the allowed values.");
+
+ final CallerIdentity caller = getAdminCallerIdentity(null);
+ Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
+ Preconditions.checkArgument(!calledOnParent || isProfileOwner(caller));
+
+ synchronized (getLockObject()) {
+ final ActiveAdmin admin = getParentOfAdminIfRequired(
+ getProfileOwnerOrDeviceOwnerLocked(caller), calledOnParent);
+ if (admin.mPasswordComplexity != passwordComplexity) {
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ admin.mPasswordComplexity = passwordComplexity;
+ // Reset the password policy.
+ admin.mPasswordPolicy = new PasswordPolicy();
+ updatePasswordValidityCheckpointLocked(caller.getUserId(), calledOnParent);
+ updatePasswordQualityCacheForUserGroup(caller.getUserId());
+ saveSettingsLocked(caller.getUserId());
+ //TODO: Log password complexity change if security logging is enabled.
+ });
+ }
+ }
+ //TODO: Log metrics.
+ }
+
+ private int getEffectivePasswordComplexityRequirementLocked(@UserIdInt int userHandle,
+ boolean parent) {
+ ensureLocked();
+ List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+ getProfileParentUserIfRequested(userHandle, parent));
+ int maxRequiredComplexity = PASSWORD_COMPLEXITY_NONE;
+ for (ActiveAdmin admin : admins) {
+ final ComponentName adminComponent = admin.info.getComponent();
+ final int adminUser = admin.getUserHandle().getIdentifier();
+ // Password complexity is only taken into account from DO/PO
+ if (isDeviceOwner(adminComponent, adminUser)
+ || isProfileOwner(adminComponent, adminUser)) {
+ maxRequiredComplexity = Math.max(maxRequiredComplexity, admin.mPasswordComplexity);
+ }
+ }
+ return maxRequiredComplexity;
+ }
+
+ @Override
+ public int getRequiredPasswordComplexity(boolean calledOnParent) {
+ if (!mHasFeature) {
+ return PASSWORD_COMPLEXITY_NONE;
+ }
+
+ final CallerIdentity caller = getAdminCallerIdentity(null);
+ Preconditions.checkCallAuthorization(
+ isDeviceOwner(caller) || isProfileOwner(caller));
+
+ Preconditions.checkArgument(!calledOnParent || hasProfileOwner(caller.getUserId()));
+
+ synchronized (getLockObject()) {
+ final ActiveAdmin requiredAdmin = getParentOfAdminIfRequired(
+ getDeviceOrProfileOwnerAdminLocked(caller.getUserId()), calledOnParent);
+ return requiredAdmin.mPasswordComplexity;
+ }
+ }
+
+ @Override
public int getCurrentFailedPasswordAttempts(int userHandle, boolean parent) {
if (!mLockPatternUtils.hasSecureLockScreen()) {
return 0;
@@ -4375,7 +4509,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
ActiveAdmin strictestAdmin = null;
// Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+ List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+ getProfileParentUserIfRequested(userHandle, parent));
final int N = admins.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = admins.get(i);
@@ -4461,15 +4596,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
synchronized (getLockObject()) {
final PasswordMetrics minMetrics = getPasswordMinimumMetrics(userHandle);
final List<PasswordValidationError> validationErrors;
+ final int complexity =
+ getEffectivePasswordComplexityRequirementLocked(userHandle, false);
// TODO: Consider changing validation API to take LockscreenCredential.
if (password.isEmpty()) {
validationErrors = PasswordMetrics.validatePasswordMetrics(
- minMetrics, PASSWORD_COMPLEXITY_NONE, false /* isPin */,
+ minMetrics, complexity, false /* isPin */,
new PasswordMetrics(CREDENTIAL_TYPE_NONE));
} else {
// TODO(b/120484642): remove getBytes() below
validationErrors = PasswordMetrics.validatePassword(
- minMetrics, PASSWORD_COMPLEXITY_NONE, false, password.getBytes());
+ minMetrics, complexity, false, password.getBytes());
}
if (!validationErrors.isEmpty()) {
@@ -4584,7 +4721,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Update the device timeout
final int parentId = getProfileParentId(userId);
final long timeMs = getMaximumTimeToLockPolicyFromAdmins(
- getActiveAdminsForLockscreenPoliciesLocked(parentId, false));
+ getActiveAdminsForLockscreenPoliciesLocked(parentId));
final DevicePolicyData policy = getUserDataUnchecked(parentId);
if (policy.mLastMaximumTimeToLock == timeMs) {
@@ -4606,7 +4743,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final long timeMs;
if (isSeparateProfileChallengeEnabled(userId)) {
timeMs = getMaximumTimeToLockPolicyFromAdmins(
- getActiveAdminsForLockscreenPoliciesLocked(userId, false /* parent */));
+ getActiveAdminsForLockscreenPoliciesLocked(userId));
} else {
timeMs = Long.MAX_VALUE;
}
@@ -4639,7 +4776,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
// Return the strictest policy across all participating admins.
final List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
- userHandle, parent);
+ getProfileParentUserIfRequested(userHandle, parent));
final long timeMs = getMaximumTimeToLockPolicyFromAdmins(admins);
return timeMs == Long.MAX_VALUE ? 0 : timeMs;
}
@@ -4723,7 +4860,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
// Return the strictest policy across all participating admins.
- List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userId, parent);
+ List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+ getProfileParentUserIfRequested(userId, parent));
long strongAuthUnlockTimeout = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
for (int i = 0; i < admins.size(); i++) {
@@ -4749,9 +4887,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void lockNow(int flags, boolean parent) {
- if (!mHasFeature && !hasCallingPermission(permission.LOCK_DEVICE)) {
+ if (!canExecute(DevicePolicyManager.OPERATION_LOCK_NOW, permission.LOCK_DEVICE)) {
return;
}
+
final CallerIdentity caller = getCallerIdentity();
final int callingUserId = caller.getUserId();
@@ -4794,9 +4933,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Require authentication for the device or profile
if (userToLock == UserHandle.USER_ALL) {
- // Power off the display
- mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(),
- PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0);
+ if (mIsAutomotive) {
+ if (VERBOSE_LOG) {
+ Slog.v(LOG_TAG, "lockNow(): not powering off display on automotive"
+ + " build");
+ }
+ } else {
+ // Power off the display
+ mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0);
+ }
mInjector.getIWindowManager().lockNow(null);
} else {
mInjector.getTrustManager().setDeviceLockedForUser(userToLock, true);
@@ -5290,7 +5436,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final UserHandle caller = mInjector.binderGetCallingUserHandle();
// If there is a profile owner, redirect to that; otherwise query the device owner.
- ComponentName aliasChooser = getProfileOwner(caller.getIdentifier());
+ ComponentName aliasChooser = getProfileOwnerAsUser(caller.getIdentifier());
if (aliasChooser == null && caller.isSystem()) {
synchronized (getLockObject()) {
final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
@@ -6143,8 +6289,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
*/
private Set<Integer> updatePasswordExpirationsLocked(int userHandle) {
final ArraySet<Integer> affectedUserIds = new ArraySet<>();
- List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
- userHandle, /* parent */ false);
+ List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle);
for (int i = 0; i < admins.size(); i++) {
ActiveAdmin admin = admins.get(i);
if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
@@ -7148,7 +7293,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
admins = getUserDataUnchecked(userHandle).mAdminList;
} else {
// Otherwise return those set by admins in the user and its profiles.
- admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+ admins = getActiveAdminsForLockscreenPoliciesLocked(
+ getProfileParentUserIfRequested(userHandle, parent));
}
int which = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
@@ -7215,7 +7361,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|| (caller.hasPackage()
&& isCallerDelegate(caller, DELEGATION_KEEP_UNINSTALLED_PACKAGES)));
- // TODO In split system user mode, allow apps on user 0 to query the list
synchronized (getLockObject()) {
return getKeepUninstalledPackagesLocked();
}
@@ -7346,7 +7491,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
public boolean isProfileOwner(ComponentName who, int userId) {
- final ComponentName profileOwner = getProfileOwner(userId);
+ final ComponentName profileOwner = getProfileOwnerAsUser(userId);
return who != null && who.equals(profileOwner);
}
@@ -7357,7 +7502,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
*/
public boolean isProfileOwner(CallerIdentity caller) {
synchronized (getLockObject()) {
- final ComponentName profileOwner = getProfileOwner(caller.getUserId());
+ final ComponentName profileOwner = getProfileOwnerAsUser(caller.getUserId());
// No profile owner.
if (profileOwner == null) {
return false;
@@ -7448,6 +7593,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ private int getDeviceOwnerUserIdUncheckedLocked() {
+ return mOwners.hasDeviceOwner() ? mOwners.getDeviceOwnerUserId() : UserHandle.USER_NULL;
+ }
+
@Override
public int getDeviceOwnerUserId() {
if (!mHasFeature) {
@@ -7456,7 +7605,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
synchronized (getLockObject()) {
- return mOwners.hasDeviceOwner() ? mOwners.getDeviceOwnerUserId() : UserHandle.USER_NULL;
+ return getDeviceOwnerUserIdUncheckedLocked();
}
}
@@ -7958,19 +8107,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public ComponentName getProfileOwnerAsUser(int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasCrossUsersPermission(caller, userHandle));
- return getProfileOwner(userHandle);
- }
-
- @Override
- public ComponentName getProfileOwner(int userHandle) {
- if (!mHasFeature) {
- return null;
- }
synchronized (getLockObject()) {
return mOwners.getProfileOwnerComponent(userHandle);
}
@@ -8002,7 +8146,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
*/
private @Nullable ActiveAdmin getDeviceOrProfileOwnerAdminLocked(int userHandle) {
ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
- if (admin == null && getDeviceOwnerUserId() == userHandle) {
+ if (admin == null && getDeviceOwnerUserIdUncheckedLocked() == userHandle) {
admin = getDeviceOwnerAdminLocked();
}
return admin;
@@ -8013,9 +8157,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return mInjector.binderWithCleanCallingIdentity(() -> {
for (UserInfo userInfo : mUserManager.getProfiles(userHandle)) {
if (userInfo.isManagedProfile()) {
- if (getProfileOwner(userInfo.id) != null
+ if (getProfileOwnerAsUser(userInfo.id) != null
&& isProfileOwnerOfOrganizationOwnedDevice(userInfo.id)) {
- ComponentName who = getProfileOwner(userInfo.id);
+ ComponentName who = getProfileOwnerAsUser(userInfo.id);
return getActiveAdminUncheckedLocked(who, userInfo.id);
}
}
@@ -8062,7 +8206,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkCallAuthorization(canManageUsers(getCallerIdentity()));
- ComponentName profileOwner = getProfileOwner(userHandle);
+ ComponentName profileOwner = getProfileOwnerAsUser(userHandle);
if (profileOwner == null) {
return null;
}
@@ -8366,7 +8510,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
- final ComponentName profileOwner = getProfileOwner(userId);
+ final ComponentName profileOwner = getProfileOwnerAsUser(userId);
if (profileOwner == null) {
return false;
}
@@ -8428,6 +8572,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
});
}
+ private int getProfileParentUserIfRequested(int userHandle, boolean parent) {
+ if (parent) {
+ return getProfileParentId(userHandle);
+ }
+
+ return userHandle;
+ }
+
private int getCredentialOwner(final int userHandle, final boolean parent) {
return mInjector.binderWithCleanCallingIdentity(() -> {
int effectiveUserHandle = userHandle;
@@ -8500,29 +8652,43 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, printWriter)) return;
- IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
- synchronized (getLockObject()) {
+ try (IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ")) {
pw.println("Current Device Policy Manager state:");
pw.increaseIndent();
- mOwners.dump(pw);
- pw.println();
- mDeviceAdminServiceController.dump(pw);
- pw.println();
- dumpDevicePolicyData(pw);
- pw.println();
- mConstants.dump(pw);
- pw.println();
- mStatLogger.dump(pw);
- pw.println();
-
- pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
- pw.println();
- mPolicyCache.dump(pw);
- pw.println();
- mStateCache.dump(pw);
- }
+ dumpImmutableState(pw);
+ synchronized (getLockObject()) {
+ mOwners.dump(pw);
+ pw.println();
+ mDeviceAdminServiceController.dump(pw);
+ pw.println();
+ dumpDevicePolicyData(pw);
+ pw.println();
+ mConstants.dump(pw);
+ pw.println();
+ mStatLogger.dump(pw);
+ pw.println();
+
+ pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
+ pw.println();
+ mPolicyCache.dump(pw);
+ pw.println();
+ mStateCache.dump(pw);
+ }
+ }
+ }
+
+ private void dumpImmutableState(IndentingPrintWriter pw) {
+ pw.println("Immutable state:");
+ pw.increaseIndent();
+ pw.printf("mHasFeature=%b\n", mHasFeature);
+ pw.printf("mIsWatch=%b\n", mIsWatch);
+ pw.printf("mIsAutomotive=%b\n", mIsAutomotive);
+ pw.printf("mHasTelephonyFeature=%b\n", mHasTelephonyFeature);
+ String safetyChecker = mSafetyChecker == null ? "N/A" : mSafetyChecker.getClass().getName();
+ pw.printf("mSafetyChecker=%b\n", safetyChecker);
+ pw.decreaseIndent();
}
private String getEncryptionStatusName(int encryptionStatus) {
@@ -8698,8 +8864,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Search through all admins that use KEYGUARD_DISABLE_TRUST_AGENTS and keep track
// of the options. If any admin doesn't have options, discard options for the rest
// and return null.
- List<ActiveAdmin> admins =
- getActiveAdminsForLockscreenPoliciesLocked(userHandle, parent);
+ List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(
+ getProfileParentUserIfRequested(userHandle, parent));
boolean allAdminsHaveOptions = true;
final int N = admins.size();
for (int i = 0; i < N; i++) {
@@ -9163,7 +9329,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ ActiveAdmin admin = getProfileOwnerLocked(caller);
admin.permittedNotificationListeners = packageList;
saveSettingsLocked(caller.getUserId());
}
@@ -10139,10 +10305,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+ Preconditions.checkCallAuthorization(isProfileOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ ActiveAdmin admin = getProfileOwnerLocked(caller);
if (admin.disableCallerId != disabled) {
admin.disableCallerId = disabled;
saveSettingsLocked(caller.getUserId());
@@ -10162,10 +10328,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+ Preconditions.checkCallAuthorization(isProfileOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ ActiveAdmin admin = getProfileOwnerLocked(caller);
return admin.disableCallerId;
}
}
@@ -10190,10 +10356,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+ Preconditions.checkCallAuthorization(isProfileOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ ActiveAdmin admin = getProfileOwnerLocked(caller);
if (admin.disableContactsSearch != disabled) {
admin.disableContactsSearch = disabled;
saveSettingsLocked(caller.getUserId());
@@ -10213,10 +10379,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+ Preconditions.checkCallAuthorization(isProfileOwner(caller));
synchronized (getLockObject()) {
- ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ ActiveAdmin admin = getProfileOwnerLocked(caller);
return admin.disableContactsSearch;
}
}
@@ -10353,12 +10519,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkCallAuthorization(!isManagedProfile(caller.getUserId()),
"User %d is not allowed to call setSecondaryLockscreenEnabled",
caller.getUserId());
- // Allow testOnly admins to bypass supervision config requirement.
- Preconditions.checkCallAuthorization(isAdminTestOnlyLocked(who, caller.getUserId())
- || isDefaultSupervisor(caller), "Admin %s is not the "
- + "default supervision component", caller.getComponentName());
synchronized (getLockObject()) {
+ // Allow testOnly admins to bypass supervision config requirement.
+ Preconditions.checkCallAuthorization(isAdminTestOnlyLocked(who, caller.getUserId())
+ || isDefaultSupervisor(caller), "Admin %s is not the "
+ + "default supervision component", caller.getComponentName());
DevicePolicyData policy = getUserData(caller.getUserId());
policy.mSecondaryLockscreenEnabled = enabled;
saveSettingsLocked(caller.getUserId());
@@ -11960,6 +12126,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
case DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE:
case DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE:
return checkDeviceOwnerProvisioningPreCondition(callingUserId);
+ // TODO (b/137101239): clean up split system user codes
+ // ACTION_PROVISION_MANAGED_USER and ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE
+ // only supported on split-user systems.
case DevicePolicyManager.ACTION_PROVISION_MANAGED_USER:
return checkManagedUserProvisioningPreCondition(callingUserId);
case DevicePolicyManager.ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE:
@@ -11982,24 +12151,27 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (mOwners.hasProfileOwner(deviceOwnerUserId)) {
return CODE_USER_HAS_PROFILE_OWNER;
}
- if (!mUserManager.isUserRunning(new UserHandle(deviceOwnerUserId))) {
+ // System user is always running in headless system user mode.
+ if (!mInjector.userManagerIsHeadlessSystemUserMode()
+ && !mUserManager.isUserRunning(new UserHandle(deviceOwnerUserId))) {
return CODE_USER_NOT_RUNNING;
}
if (mIsWatch && hasPaired(UserHandle.USER_SYSTEM)) {
return CODE_HAS_PAIRED;
}
+ // TODO (b/137101239): clean up split system user codes
if (isAdb) {
- // if shell command runs after user setup completed check device status. Otherwise, OK.
+ // If shell command runs after user setup completed check device status. Otherwise, OK.
if (mIsWatch || hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
- if (!mInjector.userManagerIsSplitSystemUser()) {
- if (mUserManager.getUserCount() > 1) {
- return CODE_NONSYSTEM_USER_EXISTS;
- }
- if (hasIncompatibleAccountsOrNonAdb) {
- return CODE_ACCOUNTS_NOT_EMPTY;
- }
- } else {
- // STOPSHIP Do proper check in split user mode
+ // In non-headless system user mode, DO can be setup only if
+ // there's no non-system user
+ if (!mInjector.userManagerIsHeadlessSystemUserMode()
+ && !mInjector.userManagerIsSplitSystemUser()
+ && mUserManager.getUserCount() > 1) {
+ return CODE_NONSYSTEM_USER_EXISTS;
+ }
+ if (hasIncompatibleAccountsOrNonAdb) {
+ return CODE_ACCOUNTS_NOT_EMPTY;
}
}
return CODE_OK;
@@ -12009,19 +12181,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (deviceOwnerUserId != UserHandle.USER_SYSTEM) {
return CODE_NOT_SYSTEM_USER;
}
- // In non-split user mode, only provision DO before setup wizard completes
+ // Only provision DO before setup wizard completes
+ // TODO (b/171423186): implement deferred DO setup for headless system user mode
if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
return CODE_USER_SETUP_COMPLETED;
}
- } else {
+ } else {
// STOPSHIP Do proper check in split user mode
}
return CODE_OK;
}
}
- private int checkDeviceOwnerProvisioningPreCondition(@UserIdInt int deviceOwnerUserId) {
+ private int checkDeviceOwnerProvisioningPreCondition(@UserIdInt int callingUserId) {
synchronized (getLockObject()) {
+ final int deviceOwnerUserId = mInjector.userManagerIsHeadlessSystemUserMode()
+ ? UserHandle.USER_SYSTEM
+ : callingUserId;
+ Slog.i(LOG_TAG,
+ String.format("Calling user %d, device owner will be set on user %d",
+ callingUserId, deviceOwnerUserId));
// hasIncompatibleAccountsOrNonAdb doesn't matter since the caller is not adb.
return checkDeviceOwnerProvisioningPreConditionLocked(/* owner unknown */ null,
deviceOwnerUserId, /* isAdb= */ false,
@@ -12029,6 +12208,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
+ // TODO (b/137101239): clean up split system user codes
private int checkManagedProfileProvisioningPreCondition(String packageName,
@UserIdInt int callingUserId) {
if (!hasFeatureManagedUsers()) {
@@ -12039,7 +12219,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
// Managed-profiles cannot be setup on the system user.
return CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER;
}
- if (getProfileOwner(callingUserId) != null) {
+ if (getProfileOwnerAsUser(callingUserId) != null) {
// Managed user cannot have a managed profile.
return CODE_USER_HAS_PROFILE_OWNER;
}
@@ -12117,6 +12297,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
+ // TODO (b/137101239): clean up split system user codes
private int checkManagedUserProvisioningPreCondition(int callingUserId) {
if (!hasFeatureManagedUsers()) {
return CODE_MANAGED_USERS_NOT_SUPPORTED;
@@ -12138,6 +12319,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return CODE_OK;
}
+ // TODO (b/137101239): clean up split system user codes
private int checkManagedShareableDeviceProvisioningPreCondition(int callingUserId) {
if (!mInjector.userManagerIsSplitSystemUser()) {
// ACTION_PROVISION_MANAGED_SHAREABLE_DEVICE only supported on split-user systems.
@@ -12710,13 +12892,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return true;
}
if (userId == UserHandle.USER_SYSTEM) {
- // The system user is always affiliated in a DO device, even if the DO is set on a
- // different user. This could be the case if the DO is set in the primary user
- // of a split user device.
+ // The system user is always affiliated in a DO device,
+ // even if in headless system user mode.
return true;
}
- final ComponentName profileOwner = getProfileOwner(userId);
+ final ComponentName profileOwner = getProfileOwnerAsUser(userId);
if (profileOwner == null) {
return false;
}
@@ -12925,7 +13106,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final int userId = caller.getUserId();
enforceUserUnlocked(userId);
- final ComponentName profileOwner = getProfileOwner(userId);
+ final ComponentName profileOwner = getProfileOwnerAsUser(userId);
if (profileOwner != null && packageName.equals(profileOwner.getPackageName())) {
throw new IllegalArgumentException("Cannot uninstall a package with a profile owner");
}
@@ -14337,7 +14518,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final CallerIdentity caller = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ final ActiveAdmin admin = getProfileOwnerLocked(caller);
admin.mCrossProfileCalendarPackages = packageNames;
saveSettingsLocked(caller.getUserId());
}
@@ -14358,7 +14539,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final CallerIdentity caller = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ final ActiveAdmin admin = getProfileOwnerLocked(caller);
return admin.mCrossProfileCalendarPackages;
}
}
@@ -14421,7 +14602,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final List<String> previousCrossProfilePackages;
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ final ActiveAdmin admin = getProfileOwnerLocked(caller);
previousCrossProfilePackages = admin.mCrossProfilePackages;
if (packageNames.equals(previousCrossProfilePackages)) {
return;
@@ -14453,7 +14634,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final CallerIdentity caller = getCallerIdentity(who);
synchronized (getLockObject()) {
- final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller);
+ final ActiveAdmin admin = getProfileOwnerLocked(caller);
return admin.mCrossProfilePackages;
}
}
@@ -14505,7 +14686,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final List<ActiveAdmin> admins = new ArrayList<>();
int[] users = mUserManager.getProfileIdsWithDisabled(UserHandle.getCallingUserId());
for (int i = 0; i < users.length; i++) {
- final ComponentName componentName = getProfileOwner(users[i]);
+ final ComponentName componentName = getProfileOwnerAsUser(users[i]);
if (componentName != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(componentName, users[i]);
if (admin != null) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java
index c3cb9b035ed2..1215253dacaf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java
@@ -16,9 +16,9 @@
package com.android.server.devicepolicy;
import android.app.admin.DeviceStateCache;
+import android.util.IndentingPrintWriter;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.IndentingPrintWriter;
/**
* Implementation of {@link DeviceStateCache}, to which {@link DevicePolicyManagerService} pushes
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 7649af4ee911..cced359e8d5a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -33,6 +33,7 @@ import android.os.UserManager;
import android.os.UserManagerInternal;
import android.util.ArrayMap;
import android.util.AtomicFile;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -42,7 +43,6 @@ import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.wm.ActivityTaskManagerInternal;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 599ac9344e73..91478a594ad2 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -2341,17 +2341,16 @@ BootClockTsUs IncrementalService::DataLoaderStub::getOldestPendingReadTs() {
return result;
}
- std::vector<incfs::ReadInfo> pendingReads;
- if (mService.mIncFs->waitForPendingReads(control, 0ms, &pendingReads) !=
+ if (mService.mIncFs->waitForPendingReads(control, 0ms, &mLastPendingReads) !=
android::incfs::WaitResult::HaveData ||
- pendingReads.empty()) {
+ mLastPendingReads.empty()) {
return result;
}
LOG(DEBUG) << id() << ": pendingReads: " << control.pendingReads() << ", "
- << pendingReads.size() << ": " << pendingReads.front().bootClockTsUs;
+ << mLastPendingReads.size() << ": " << mLastPendingReads.front().bootClockTsUs;
- for (auto&& pendingRead : pendingReads) {
+ for (auto&& pendingRead : mLastPendingReads) {
result = std::min(result, pendingRead.bootClockTsUs);
}
return result;
@@ -2400,6 +2399,18 @@ void IncrementalService::DataLoaderStub::setHealthListener(
}
}
+static std::string toHexString(const RawMetadata& metadata) {
+ int n = metadata.size();
+ std::string res(n * 2, '\0');
+ // Same as incfs::toString(fileId)
+ static constexpr char kHexChar[] = "0123456789abcdef";
+ for (int i = 0; i < n; ++i) {
+ res[i * 2] = kHexChar[(metadata[i] & 0xf0) >> 4];
+ res[i * 2 + 1] = kHexChar[(metadata[i] & 0x0f)];
+ }
+ return res;
+}
+
void IncrementalService::DataLoaderStub::onDump(int fd) {
dprintf(fd, " dataLoader: {\n");
dprintf(fd, " currentStatus: %d\n", mCurrentStatus);
@@ -2415,6 +2426,15 @@ void IncrementalService::DataLoaderStub::onDump(int fd) {
dprintf(fd, " unhealthyTimeoutMs: %d\n", int(mHealthCheckParams.unhealthyTimeoutMs));
dprintf(fd, " unhealthyMonitoringMs: %d\n",
int(mHealthCheckParams.unhealthyMonitoringMs));
+ dprintf(fd, " lastPendingReads: \n");
+ const auto control = mService.mIncFs->openMount(mHealthPath);
+ for (auto&& pendingRead : mLastPendingReads) {
+ dprintf(fd, " fileId: %s\n", mService.mIncFs->toString(pendingRead.id).c_str());
+ const auto metadata = mService.mIncFs->getMetadata(control, pendingRead.id);
+ dprintf(fd, " metadataHex: %s\n", toHexString(metadata).c_str());
+ dprintf(fd, " blockIndex: %d\n", pendingRead.block);
+ dprintf(fd, " bootClockTsUs: %lld\n", (long long)pendingRead.bootClockTsUs);
+ }
dprintf(fd, " }\n");
const auto& params = mParams;
dprintf(fd, " dataLoaderParams: {\n");
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 4c4b8bd1ba50..eb69470c97a7 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -257,6 +257,7 @@ private:
} mHealthBase = {TimePoint::max(), kMaxBootClockTsUs};
StorageHealthCheckParams mHealthCheckParams;
int mStreamStatus = content::pm::IDataLoaderStatusListener::STREAM_HEALTHY;
+ std::vector<incfs::ReadInfo> mLastPendingReads;
};
using DataLoaderStubPtr = sp<DataLoaderStub>;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 144c466cf9e9..dfe9684779fe 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -166,6 +166,7 @@ public:
FileId getFileId(const Control& control, std::string_view path) const final {
return incfs::getFileId(control, path);
}
+ std::string toString(FileId fileId) const final { return incfs::toString(fileId); }
std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
const Control& control, std::string_view path) const final {
const auto fileId = incfs::getFileId(control, path);
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 4815cafc0995..f2d00735bc44 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -92,6 +92,7 @@ public:
virtual incfs::RawMetadata getMetadata(const Control& control, FileId fileid) const = 0;
virtual incfs::RawMetadata getMetadata(const Control& control, std::string_view path) const = 0;
virtual FileId getFileId(const Control& control, std::string_view path) const = 0;
+ virtual std::string toString(FileId fileId) const = 0;
virtual std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
const Control& control, std::string_view path) const = 0;
virtual ErrorCode link(const Control& control, std::string_view from,
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 867312e0eb2f..9b8cf4084bf1 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -294,6 +294,7 @@ public:
MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, FileId fileid));
MOCK_CONST_METHOD2(getMetadata, RawMetadata(const Control& control, std::string_view path));
MOCK_CONST_METHOD2(getFileId, FileId(const Control& control, std::string_view path));
+ MOCK_CONST_METHOD1(toString, std::string(FileId fileId));
MOCK_CONST_METHOD2(countFilledBlocks,
std::pair<IncFsBlockIndex, IncFsBlockIndex>(const Control& control,
std::string_view path));
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index dfa726f1bfc8..10b3265cd081 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -34,6 +34,7 @@ import android.app.AppCompatCallbacks;
import android.app.ApplicationErrorReport;
import android.app.INotificationManager;
import android.app.SystemServiceRegistry;
+import android.app.admin.DevicePolicySafetyChecker;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ContentResolver;
import android.content.Context;
@@ -101,6 +102,7 @@ import com.android.server.attention.AttentionManagerService;
import com.android.server.audio.AudioService;
import com.android.server.biometrics.AuthService;
import com.android.server.biometrics.BiometricService;
+import com.android.server.biometrics.sensors.BiometricServiceCallback;
import com.android.server.biometrics.sensors.face.FaceService;
import com.android.server.biometrics.sensors.fingerprint.FingerprintService;
import com.android.server.biometrics.sensors.iris.IrisService;
@@ -195,8 +197,10 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
+import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.concurrent.CountDownLatch;
@@ -1468,7 +1472,10 @@ public final class SystemServer implements Dumpable {
}
t.traceEnd();
- if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
+ final DevicePolicyManagerService.Lifecycle dpms;
+ if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
+ dpms = null;
+ } else {
t.traceBegin("StartLockSettingsService");
try {
mSystemServiceManager.startService(LOCK_SETTINGS_SERVICE_CLASS);
@@ -1505,7 +1512,7 @@ public final class SystemServer implements Dumpable {
// Always start the Device Policy Manager, so that the API is compatible with
// API8.
t.traceBegin("StartDevicePolicyManager");
- mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
+ dpms = mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
t.traceEnd();
if (!isWatch) {
@@ -2089,9 +2096,12 @@ public final class SystemServer implements Dumpable {
final boolean hasFeatureFingerprint
= mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
+ final List<BiometricServiceCallback> biometricServiceCallback = new ArrayList<>();
if (hasFeatureFace) {
t.traceBegin("StartFaceSensor");
- mSystemServiceManager.startService(FaceService.class);
+ final FaceService faceService =
+ mSystemServiceManager.startService(FaceService.class);
+ biometricServiceCallback.add(faceService);
t.traceEnd();
}
@@ -2103,13 +2113,20 @@ public final class SystemServer implements Dumpable {
if (hasFeatureFingerprint) {
t.traceBegin("StartFingerprintSensor");
- mSystemServiceManager.startService(FingerprintService.class);
+ final FingerprintService fingerprintService =
+ mSystemServiceManager.startService(FingerprintService.class);
+ biometricServiceCallback.add(fingerprintService);
t.traceEnd();
}
- // Start this service after all biometric services.
+ // Start this service after all biometric sensor services are started.
t.traceBegin("StartBiometricService");
mSystemServiceManager.startService(BiometricService.class);
+ for (BiometricServiceCallback service : biometricServiceCallback) {
+ Slog.d(TAG, "Notifying onBiometricServiceReady for: "
+ + service.getClass().getSimpleName());
+ service.onBiometricServiceReady();
+ }
t.traceEnd();
t.traceBegin("StartAuthService");
@@ -2427,6 +2444,9 @@ public final class SystemServer implements Dumpable {
if (cshs instanceof Dumpable) {
mDumper.addDumpable((Dumpable) cshs);
}
+ if (cshs instanceof DevicePolicySafetyChecker) {
+ dpms.setDevicePolicySafetyChecker((DevicePolicySafetyChecker) cshs);
+ }
t.traceEnd();
}
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 1ccd512a9daf..a52fe12150da 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -22,13 +22,14 @@ java_library_static {
// Version of services.net for usage by the wifi mainline module.
// Note: This is compiled against module_current.
-// TODO(b/145825329): This should be moved to networkstack-client,
+// TODO(b/172457099): This should be moved to networkstack-client,
// with dependencies moved to frameworks/libs/net right.
java_library {
name: "services.net-module-wifi",
srcs: [
":framework-services-net-module-wifi-shared-srcs",
":net-module-utils-srcs",
+ ":net-utils-services-common-srcs",
"java/android/net/ip/IpClientCallbacks.java",
"java/android/net/ip/IpClientManager.java",
"java/android/net/ip/IpClientUtil.java",
@@ -39,6 +40,7 @@ java_library {
"java/android/net/TcpKeepalivePacketData.java",
],
sdk_version: "module_current",
+ min_sdk_version: "30",
libs: [
"unsupportedappusage",
"framework-wifi-util-lib",
@@ -49,7 +51,6 @@ java_library {
"netd_aidl_interface-V3-java",
"netlink-client",
"networkstack-client",
- "net-utils-services-common",
],
apex_available: [
"com.android.wifi",
diff --git a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
index c03a5a7f4bec..e4daddca4564 100644
--- a/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
+++ b/services/people/java/com/android/server/people/data/AbstractProtoDiskReadWriter.java
@@ -185,22 +185,23 @@ abstract class AbstractProtoDiskReadWriter<T> {
* is useful for when device is powering off.
*/
@MainThread
- synchronized void saveImmediately(@NonNull String fileName, @NonNull T data) {
- mScheduledFileDataMap.put(fileName, data);
+ void saveImmediately(@NonNull String fileName, @NonNull T data) {
+ synchronized (this) {
+ mScheduledFileDataMap.put(fileName, data);
+ }
triggerScheduledFlushEarly();
}
@MainThread
- private synchronized void triggerScheduledFlushEarly() {
- if (mScheduledFileDataMap.isEmpty() || mScheduledExecutorService.isShutdown()) {
- return;
- }
- // Cancel existing future.
- if (mScheduledFuture != null) {
-
- // We shouldn't need to interrupt as this method and threaded task
- // #flushScheduledData are both synchronized.
- mScheduledFuture.cancel(true);
+ private void triggerScheduledFlushEarly() {
+ synchronized (this) {
+ if (mScheduledFileDataMap.isEmpty() || mScheduledExecutorService.isShutdown()) {
+ return;
+ }
+ // Cancel existing future.
+ if (mScheduledFuture != null) {
+ mScheduledFuture.cancel(true);
+ }
}
// Submit flush and blocks until it completes. Blocking will prevent the device from
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 19449654f2ec..0d878b401bee 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -28,7 +28,6 @@ import android.os.IBinder.DeathRecipient;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemProperties;
import android.os.UpdateEngine;
import android.os.UpdateEngineCallback;
import android.provider.DeviceConfig;
@@ -227,8 +226,8 @@ public final class ProfcollectForwardingService extends SystemService {
}
// Sample for a fraction of app launches.
- int traceFrequency =
- SystemProperties.getInt("persist.profcollectd.applaunch_trace_freq", 2);
+ int traceFrequency = DeviceConfig.getInt(DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
+ "applaunch_trace_freq", 2);
int randomNum = ThreadLocalRandom.current().nextInt(100);
if (randomNum < traceFrequency) {
try {
diff --git a/services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java
deleted file mode 100644
index fa324e8c60ee..000000000000
--- a/services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java
+++ /dev/null
@@ -1,120 +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.location.gnss;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.platform.test.annotations.Presubmit;
-
-import com.android.server.location.gnss.GnssBatchingProvider.GnssBatchingProviderNative;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-
-/**
- * Unit tests for {@link GnssBatchingProvider}.
- */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class GnssBatchingProviderTest {
-
- private static final long PERIOD_NANOS = (long) 1e9;
- private static final boolean WAKE_ON_FIFO_FULL = true;
- private static final int BATCH_SIZE = 3;
- @Mock
- private GnssBatchingProviderNative mMockNative;
- private GnssBatchingProvider mTestProvider;
-
- /**
- * Mocks native methods and starts GnssBatchingProvider.
- */
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mMockNative.initBatching()).thenReturn(true);
- when(mMockNative.startBatch(anyLong(), anyBoolean())).thenReturn(true);
- when(mMockNative.stopBatch()).thenReturn(true);
- when(mMockNative.getBatchSize()).thenReturn(BATCH_SIZE);
- mTestProvider = new GnssBatchingProvider(mMockNative);
- mTestProvider.enable();
- mTestProvider.start(PERIOD_NANOS, WAKE_ON_FIFO_FULL);
- }
-
- /**
- * Test native start method is called.
- */
- @Test
- public void start_nativeStarted() {
- verify(mMockNative).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL));
- }
-
- /**
- * Verify native stop method is called.
- */
- @Test
- public void stop_nativeStopped() {
- mTestProvider.stop();
- verify(mMockNative).stopBatch();
- }
-
- /**
- * Verify native flush method is called.
- */
- @Test
- public void flush_nativeFlushed() {
- mTestProvider.flush();
- verify(mMockNative).flushBatch();
- }
-
- /**
- * Verify getBatchSize returns value from native batch size method.
- */
- @Test
- public void getBatchSize_nativeGetBatchSize() {
- assertThat(mTestProvider.getBatchSize()).isEqualTo(BATCH_SIZE);
- }
-
- /**
- * Verify resumeIfStarted method will call native start method a second time.
- */
- @Test
- public void started_resume_started() {
- mTestProvider.resumeIfStarted();
- verify(mMockNative, times(2)).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL));
- }
-
- /**
- * Verify that if batching is stopped, resume will not call native start method.
- */
- @Test
- public void stopped_resume_notStarted() {
- mTestProvider.stop();
- mTestProvider.resumeIfStarted();
- verify(mMockNative, times(1)).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL));
- }
-}
diff --git a/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlacklistHelperTest.java b/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlocklistHelperTest.java
index ce89b9bcf5ca..910a6f53fa80 100644
--- a/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlacklistHelperTest.java
+++ b/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlocklistHelperTest.java
@@ -43,101 +43,101 @@ import java.util.Collection;
import java.util.List;
/**
- * Unit tests for {@link GnssSatelliteBlacklistHelper}.
+ * Unit tests for {@link GnssSatelliteBlocklistHelper}.
*/
@RunWith(RobolectricTestRunner.class)
@Presubmit
-public class GnssSatelliteBlacklistHelperTest {
+public class GnssSatelliteBlocklistHelperTest {
private ContentResolver mContentResolver;
@Mock
- private GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback mCallback;
+ private GnssSatelliteBlocklistHelper.GnssSatelliteBlocklistCallback mCallback;
/**
- * Initialize mocks and create GnssSatelliteBlacklistHelper with callback.
+ * Initialize mocks and create GnssSatelliteBlocklistHelper with callback.
*/
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
Context context = RuntimeEnvironment.application;
mContentResolver = context.getContentResolver();
- new GnssSatelliteBlacklistHelper(context, Looper.myLooper(), mCallback);
+ new GnssSatelliteBlocklistHelper(context, Looper.myLooper(), mCallback);
}
/**
- * Blacklist two satellites and verify callback is called.
+ * Blocklist two satellites and verify callback is called.
*/
@Test
- public void blacklistOf2Satellites_callbackIsCalled() {
- String blacklist = "3,0,5,24";
- updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+ public void blocklistOf2Satellites_callbackIsCalled() {
+ String blocklist = "3,0,5,24";
+ updateBlocklistAndVerifyCallbackIsCalled(blocklist);
}
/**
- * Blacklist one satellite with spaces in string and verify callback is called.
+ * Blocklist one satellite with spaces in string and verify callback is called.
*/
@Test
- public void blacklistWithSpaces_callbackIsCalled() {
- String blacklist = "3, 11";
- updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+ public void blocklistWithSpaces_callbackIsCalled() {
+ String blocklist = "3, 11";
+ updateBlocklistAndVerifyCallbackIsCalled(blocklist);
}
/**
- * Pass empty blacklist and verify callback is called.
+ * Pass empty blocklist and verify callback is called.
*/
@Test
- public void emptyBlacklist_callbackIsCalled() {
- String blacklist = "";
- updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+ public void emptyBlocklist_callbackIsCalled() {
+ String blocklist = "";
+ updateBlocklistAndVerifyCallbackIsCalled(blocklist);
}
/**
- * Pass blacklist string with odd number of values and verify callback is not called.
+ * Pass blocklist string with odd number of values and verify callback is not called.
*/
@Test
- public void blacklistWithOddNumberOfValues_callbackIsNotCalled() {
- String blacklist = "3,0,5";
- updateBlacklistAndNotifyContentObserver(blacklist);
- verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+ public void blocklistWithOddNumberOfValues_callbackIsNotCalled() {
+ String blocklist = "3,0,5";
+ updateBlocklistAndNotifyContentObserver(blocklist);
+ verify(mCallback, never()).onUpdateSatelliteBlocklist(any(int[].class), any(int[].class));
}
/**
- * Pass blacklist string with negative value and verify callback is not called.
+ * Pass blocklist string with negative value and verify callback is not called.
*/
@Test
- public void blacklistWithNegativeValue_callbackIsNotCalled() {
- String blacklist = "3,-11";
- updateBlacklistAndNotifyContentObserver(blacklist);
- verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+ public void blocklistWithNegativeValue_callbackIsNotCalled() {
+ String blocklist = "3,-11";
+ updateBlocklistAndNotifyContentObserver(blocklist);
+ verify(mCallback, never()).onUpdateSatelliteBlocklist(any(int[].class), any(int[].class));
}
/**
- * Pass blacklist string with non-digit characters and verify callback is not called.
+ * Pass blocklist string with non-digit characters and verify callback is not called.
*/
@Test
- public void blacklistWithNonDigitCharacter_callbackIsNotCalled() {
- String blacklist = "3,1a,5,11";
- updateBlacklistAndNotifyContentObserver(blacklist);
- verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+ public void blocklistWithNonDigitCharacter_callbackIsNotCalled() {
+ String blocklist = "3,1a,5,11";
+ updateBlocklistAndNotifyContentObserver(blocklist);
+ verify(mCallback, never()).onUpdateSatelliteBlocklist(any(int[].class), any(int[].class));
}
- private void updateBlacklistAndNotifyContentObserver(String blacklist) {
+ private void updateBlocklistAndNotifyContentObserver(String blocklist) {
Settings.Global.putString(mContentResolver,
- Settings.Global.GNSS_SATELLITE_BLACKLIST, blacklist);
- notifyContentObserverFor(Settings.Global.GNSS_SATELLITE_BLACKLIST);
+ Settings.Global.GNSS_SATELLITE_BLOCKLIST, blocklist);
+ notifyContentObserverFor(Settings.Global.GNSS_SATELLITE_BLOCKLIST);
}
- private void updateBlacklistAndVerifyCallbackIsCalled(String blacklist) {
- updateBlacklistAndNotifyContentObserver(blacklist);
+ private void updateBlocklistAndVerifyCallbackIsCalled(String blocklist) {
+ updateBlocklistAndNotifyContentObserver(blocklist);
ArgumentCaptor<int[]> constellationsCaptor = ArgumentCaptor.forClass(int[].class);
ArgumentCaptor<int[]> svIdsCaptor = ArgumentCaptor.forClass(int[].class);
- verify(mCallback).onUpdateSatelliteBlacklist(constellationsCaptor.capture(),
+ verify(mCallback).onUpdateSatelliteBlocklist(constellationsCaptor.capture(),
svIdsCaptor.capture());
int[] constellations = constellationsCaptor.getValue();
int[] svIds = svIdsCaptor.getValue();
- List<Integer> values = GnssSatelliteBlacklistHelper.parseSatelliteBlacklist(blacklist);
+ List<Integer> values = GnssSatelliteBlocklistHelper.parseSatelliteBlocklist(blocklist);
assertThat(values.size()).isEqualTo(constellations.length * 2);
assertThat(svIds.length).isEqualTo(constellations.length);
for (int i = 0; i < constellations.length; i++) {
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt
index 7ae2fe0935de..e17358d38d8c 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt
@@ -17,8 +17,11 @@ import org.junit.runner.RunWith
class FactoryPackageTest : BaseHostJUnit4Test() {
companion object {
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+ private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
private const val DEVICE_SIDE = "PackageManagerServiceDeviceSideTests.apk"
- private const val DEVICE_SIDE_PKG_NAME = "com.android.server.pm.test.deviceside"
@get:ClassRule
val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
@@ -37,8 +40,7 @@ class FactoryPackageTest : BaseHostJUnit4Test() {
@Before
@After
fun removeApk() {
- HostUtils.deleteAllTestPackages(device, preparer)
- device.uninstallPackage(DEVICE_SIDE_PKG_NAME)
+ device.uninstallPackage(TEST_PKG_NAME)
device.deleteFile(filePath.parent.toString())
device.reboot()
}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
index f0b60f48e090..9399030e057c 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
@@ -23,15 +23,6 @@ import org.junit.rules.TemporaryFolder
import java.io.File
import java.io.FileOutputStream
-internal const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
-internal const val VERSION_STUB = "PackageManagerTestAppStub.apk"
-internal const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
-internal const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
-internal const val VERSION_THREE = "PackageManagerTestAppVersion3.apk"
-internal const val VERSION_THREE_INVALID = "PackageManagerTestAppVersion3Invalid.apk"
-internal const val VERSION_FOUR = "PackageManagerTestAppVersion4.apk"
-internal const val VERSION_OVERRIDE = "PackageManagerTestAppOriginalOverride.apk"
-
internal fun SystemPreparer.pushApk(javaResourceName: String, partition: Partition) =
pushResourceFile(javaResourceName, HostUtils.makePathForApk(javaResourceName, partition)
.toString())
@@ -98,25 +89,12 @@ internal fun retryUntilSuccess(block: () -> Boolean) {
internal object HostUtils {
- /**
- * Since most of the tests use the same test APKs, consolidate the logic for deleting them
- * before and after a test runs. This also ensures that a failing test doesn't leave an APK on
- * device that could spill over to another test when developing locally.
- *
- * Iterates all partitions since different tests use different partitions.
- */
- fun deleteAllTestPackages(device: ITestDevice, preparer: SystemPreparer) {
- Partition.values().forEach { partition ->
- device.uninstallPackage(TEST_PKG_NAME)
- preparer.deleteApkFolders(partition, VERSION_ONE, VERSION_TWO, VERSION_THREE,
- VERSION_THREE_INVALID, VERSION_FOUR, VERSION_OVERRIDE)
- }
-
- // TODO: There is an optimization that can be made here by hooking into the SystemPreparer's
- // reboot rule, avoiding a reboot cycle by doing the delete in line the built in @After
- // reboot.
- preparer.reboot()
- }
+ fun getDataDir(device: ITestDevice, pkgName: String) =
+ device.executeShellCommand("dumpsys package $pkgName")
+ .lineSequence()
+ .map(String::trim)
+ .single { it.startsWith("dataDir=") }
+ .removePrefix("dataDir=")
fun makePathForApk(fileName: String, partition: Partition) =
makePathForApk(File(fileName), partition)
@@ -158,35 +136,14 @@ internal object HostUtils {
}
.map(String::trim)
- fun getDataDir(device: ITestDevice, pkgName: String) =
- packageSection(device, pkgName)
- .singleOrNull { it.startsWith("dataDir=") }
- ?.removePrefix("dataDir=")
-
- /** Return all code paths for a package. This will include hidden system package code paths. */
fun getCodePaths(device: ITestDevice, pkgName: String) =
- (packageSection(device, pkgName) +
- packageSection(device, pkgName, "Hidden system packages"))
+ device.executeShellCommand("pm dump $pkgName")
+ .lineSequence()
+ .map(String::trim)
.filter { it.startsWith("codePath=") }
.map { it.removePrefix("codePath=") }
.toList()
- fun getVersionCode(device: ITestDevice, pkgName: String) =
- packageSection(device, pkgName)
- .filter { it.startsWith("versionCode=") }
- .map { it.removePrefix("versionCode=") }
- .map { it.takeWhile { !it.isWhitespace() } }
- .map { it.toInt() }
- .firstOrNull()
-
- fun getPrivateFlags(device: ITestDevice, pkgName: String) =
- packageSection(device, pkgName)
- .filter { it.startsWith("privateFlags=") }
- .map { it.removePrefix("privateFlags=[ ") }
- .map { it.removeSuffix(" ]") }
- .map { it.split(" ") }
- .firstOrNull()
-
private fun userIdLineSequence(device: ITestDevice, pkgName: String) =
packageSection(device, pkgName)
.filter { it.startsWith("User ") }
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
index 85947063dc3a..37c999cbee68 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
@@ -33,6 +33,12 @@ import org.junit.runner.RunWith
class InvalidNewSystemAppTest : BaseHostJUnit4Test() {
companion object {
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+ private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
+ private const val VERSION_THREE_INVALID = "PackageManagerTestAppVersion3Invalid.apk"
+ private const val VERSION_FOUR = "PackageManagerTestAppVersion4.apk"
+
@get:ClassRule
val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
}
@@ -49,7 +55,7 @@ class InvalidNewSystemAppTest : BaseHostJUnit4Test() {
@Before
@After
fun removeApk() {
- HostUtils.deleteAllTestPackages(device, preparer)
+ device.uninstallPackage(TEST_PKG_NAME)
preparer.deleteFile(filePath.parent.toString())
.reboot()
}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
index 0c5816bd4317..4becae66633f 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
@@ -34,6 +34,10 @@ class OriginalPackageMigrationTest : BaseHostJUnit4Test() {
companion object {
private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+ private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
+ private const val VERSION_THREE = "PackageManagerTestAppVersion3.apk"
+ private const val NEW_PKG = "PackageManagerTestAppOriginalOverride.apk"
@get:ClassRule
val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
@@ -50,7 +54,9 @@ class OriginalPackageMigrationTest : BaseHostJUnit4Test() {
@Before
@After
fun deleteApkFolders() {
- HostUtils.deleteAllTestPackages(device, preparer)
+ preparer.deleteApkFolders(Partition.SYSTEM, VERSION_ONE, VERSION_TWO, VERSION_THREE,
+ NEW_PKG)
+ .reboot()
}
@Test
@@ -83,10 +89,10 @@ class OriginalPackageMigrationTest : BaseHostJUnit4Test() {
device.pushFile(file, "${HostUtils.getDataDir(device, TEST_PKG_NAME)}/files/test.txt")
preparer.deleteApkFolders(Partition.SYSTEM, apk)
- .pushApk(VERSION_OVERRIDE, Partition.SYSTEM)
+ .pushApk(NEW_PKG, Partition.SYSTEM)
.reboot()
- assertCodePath(VERSION_OVERRIDE)
+ assertCodePath(NEW_PKG)
// And then reading the data contents back
assertThat(device.pullFileContents(
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemAppScanPriorityTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemAppScanPriorityTest.kt
deleted file mode 100644
index 8d789e03f612..000000000000
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemAppScanPriorityTest.kt
+++ /dev/null
@@ -1,272 +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.pm.test
-
-import com.android.internal.util.test.SystemPreparer
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.ClassRule
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.RuleChain
-import org.junit.rules.TemporaryFolder
-import org.junit.runner.RunWith
-import java.io.File
-
-/**
- * Pushes APKs onto various system partitions to verify that multiple versions result in the
- * highest version being scanned. Also tries to upgrade/replace these APKs which should result
- * in a version upgrade on reboot.
- *
- * This will also verify that APKs under the same folder/file name across different partitions
- * are parsed as separate entities and don't get combined under the same cache entry.
- *
- * Known limitations:
- * - Does not verify that v1 isn't scanned. It's possible to introduce a bug that upgrades the
- * system on every reboot from v1 -> v2, as this isn't easily visible after scan has finished.
- * This would also have to successfully preserve the app data though, which seems unlikely.
- * - This takes a very long time to run. 105 seconds for the first test case, up to 60 seconds for
- * each following case. It's theoretically possible to parallelize these tests so that each
- * method is run by installing all the apps under different names, requiring only 3 reboots to
- * fully verify, rather than 3 * numTestCases.
- */
-@RunWith(DeviceJUnit4ClassRunner::class)
-class SystemAppScanPriorityTest : BaseHostJUnit4Test() {
-
- companion object {
- @get:ClassRule
- var deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
- }
-
- private val tempFolder = TemporaryFolder()
- private val preparer: SystemPreparer = SystemPreparer(tempFolder,
- SystemPreparer.RebootStrategy.FULL, deviceRebootRule) { this.device }
-
- private var firstReboot = true
-
- @Rule
- @JvmField
- val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
-
- @Before
- @After
- fun deleteFiles() {
- HostUtils.deleteAllTestPackages(device, preparer)
- }
-
- @Before
- fun resetFirstReboot() {
- firstReboot = true
- }
-
- @Test
- fun takeHigherPriority() {
- preparer.pushFile(VERSION_ONE, Partition.VENDOR)
- .pushFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.PRODUCT)
- }
-
- @Test
- fun takeLowerPriority() {
- preparer.pushFile(VERSION_TWO, Partition.VENDOR)
- .pushFile(VERSION_ONE, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.VENDOR)
- }
-
- @Test
- fun upgradeToHigherOnLowerPriority() {
- preparer.pushFile(VERSION_ONE, Partition.VENDOR)
- .pushFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.PRODUCT)
-
- preparer.pushFile(VERSION_THREE, Partition.VENDOR)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.VENDOR)
- }
-
- @Test
- fun upgradeToNewerOnHigherPriority() {
- preparer.pushFile(VERSION_ONE, Partition.VENDOR)
- .pushFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.PRODUCT)
-
- preparer.pushFile(VERSION_THREE, Partition.SYSTEM_EXT)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.SYSTEM_EXT)
- }
-
- @Test
- fun replaceNewerOnLowerPriority() {
- preparer.pushFile(VERSION_TWO, Partition.VENDOR)
- .pushFile(VERSION_ONE, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.VENDOR)
-
- preparer.pushFile(VERSION_THREE, Partition.VENDOR)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.VENDOR)
- }
-
- @Test
- fun replaceNewerOnHigherPriority() {
- preparer.pushFile(VERSION_ONE, Partition.VENDOR)
- .pushFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.PRODUCT)
-
- preparer.pushFile(VERSION_THREE, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.PRODUCT)
- }
-
- @Test
- fun fallbackToLowerPriority() {
- preparer.pushFile(VERSION_TWO, Partition.VENDOR)
- .pushFile(VERSION_ONE, Partition.PRODUCT)
- .pushFile(VERSION_THREE, Partition.SYSTEM_EXT)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.SYSTEM_EXT)
-
- preparer.deleteFile(VERSION_THREE, Partition.SYSTEM_EXT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.VENDOR)
- }
-
- @Test
- fun fallbackToHigherPriority() {
- preparer.pushFile(VERSION_THREE, Partition.VENDOR)
- .pushFile(VERSION_ONE, Partition.PRODUCT)
- .pushFile(VERSION_TWO, Partition.SYSTEM_EXT)
- .rebootForTest()
-
- assertVersionAndPartition(3, Partition.VENDOR)
-
- preparer.deleteFile(VERSION_THREE, Partition.VENDOR)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.SYSTEM_EXT)
- }
-
- @Test
- fun removeBoth() {
- preparer.pushFile(VERSION_ONE, Partition.VENDOR)
- .pushFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertVersionAndPartition(2, Partition.PRODUCT)
-
- preparer.deleteFile(VERSION_ONE, Partition.VENDOR)
- .deleteFile(VERSION_TWO, Partition.PRODUCT)
- .rebootForTest()
-
- assertThat(device.getAppPackageInfo(TEST_PKG_NAME)).isNull()
- }
-
- private fun assertVersionAndPartition(versionCode: Int, partition: Partition) {
- assertThat(HostUtils.getVersionCode(device, TEST_PKG_NAME)).isEqualTo(versionCode)
-
- val privateFlags = HostUtils.getPrivateFlags(device, TEST_PKG_NAME)
-
- when (partition) {
- Partition.SYSTEM,
- Partition.SYSTEM_PRIVILEGED -> {
- assertThat(privateFlags).doesNotContain(Partition.VENDOR.toString())
- assertThat(privateFlags).doesNotContain(Partition.PRODUCT.toString())
- assertThat(privateFlags).doesNotContain(Partition.SYSTEM_EXT.toString())
- }
- Partition.VENDOR -> {
- assertThat(privateFlags).contains(Partition.VENDOR.toString())
- assertThat(privateFlags).doesNotContain(Partition.PRODUCT.toString())
- assertThat(privateFlags).doesNotContain(Partition.SYSTEM_EXT.toString())
- }
- Partition.PRODUCT -> {
- assertThat(privateFlags).doesNotContain(Partition.VENDOR.toString())
- assertThat(privateFlags).contains(Partition.PRODUCT.toString())
- assertThat(privateFlags).doesNotContain(Partition.SYSTEM_EXT.toString())
- }
- Partition.SYSTEM_EXT -> {
- assertThat(privateFlags).doesNotContain(Partition.VENDOR.toString())
- assertThat(privateFlags).doesNotContain(Partition.PRODUCT.toString())
- assertThat(privateFlags).contains(Partition.SYSTEM_EXT.toString())
- }
- }.run { /* exhaust */ }
- }
-
- // Following methods don't use HostUtils in order to test cache behavior when using the same
- // name across partitions. Writes all files under the version 1 name.
- private fun makeDevicePath(partition: Partition) =
- partition.baseAppFolder
- .resolve(File(VERSION_ONE).nameWithoutExtension)
- .resolve(VERSION_ONE)
- .toString()
-
- private fun SystemPreparer.pushFile(file: String, partition: Partition) =
- pushResourceFile(file, makeDevicePath(partition))
-
- private fun SystemPreparer.deleteFile(file: String, partition: Partition) =
- deleteFile(makeDevicePath(partition))
-
- /**
- * Custom reboot used to write app data after the first reboot. This can then be verified
- * after each subsequent reboot to ensure no data is lost.
- */
- private fun SystemPreparer.rebootForTest() {
- if (firstReboot) {
- firstReboot = false
- preparer.reboot()
-
- val file = tempFolder.newFile()
- file.writeText("Test")
- pushFile(file, "${HostUtils.getDataDir(device, TEST_PKG_NAME)}/files/test.txt")
- } else {
- val versionBefore = HostUtils.getVersionCode(device, TEST_PKG_NAME)
- preparer.reboot()
- val versionAfter = HostUtils.getVersionCode(device, TEST_PKG_NAME)
-
- if (versionBefore != null && versionAfter != null) {
- val fileContents = device.pullFileContents(
- "${HostUtils.getDataDir(device, TEST_PKG_NAME)}/files/test.txt")
- if (versionAfter < versionBefore) {
- // A downgrade will wipe app data
- assertThat(fileContents).isNull()
- } else {
- // An upgrade or update will preserve app data
- assertThat(fileContents).isEqualTo("Test")
- }
- }
- }
- }
-}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
index 99dff086170d..46120af06550 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
@@ -37,6 +37,9 @@ import java.util.zip.GZIPOutputStream
class SystemStubMultiUserDisableUninstallTest : BaseHostJUnit4Test() {
companion object {
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_STUB = "PackageManagerTestAppStub.apk"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
/**
* How many total users on device to test, including primary. This will clean up any
@@ -87,12 +90,6 @@ class SystemStubMultiUserDisableUninstallTest : BaseHostJUnit4Test() {
savedDevice?.removeUser(it)
}
- savedDevice?.let { device ->
- savedPreparer?.let { preparer ->
- HostUtils.deleteAllTestPackages(device, preparer)
- }
- }
-
savedDevice?.uninstallPackage(TEST_PKG_NAME)
savedDevice?.deleteFile(stubFile.parent.toString())
savedDevice?.deleteFile(deviceCompressedFile.parent.toString())
diff --git a/services/tests/inprocesstests/Android.bp b/services/tests/inprocesstests/Android.bp
new file mode 100644
index 000000000000..6dd059fc919d
--- /dev/null
+++ b/services/tests/inprocesstests/Android.bp
@@ -0,0 +1,12 @@
+android_test {
+ name: "FrameworksInProcessTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.rules",
+ "services.core",
+ "truth-prebuilt",
+ "platform-test-annotations",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/packages/CarSystemUI/samples/sample1/rro/AndroidManifest.xml b/services/tests/inprocesstests/AndroidManifest.xml
index 5c25056f7915..efb4a53aad24 100644
--- a/packages/CarSystemUI/samples/sample1/rro/AndroidManifest.xml
+++ b/services/tests/inprocesstests/AndroidManifest.xml
@@ -15,10 +15,16 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.systemui.rro">
- <overlay
- android:targetPackage="com.android.systemui"
- android:isStatic="false"
- android:resourcesMap="@xml/car_sysui_overlays"
- />
-</manifest> \ No newline at end of file
+ package="com.android.frameworks.inprocesstests" >
+
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android"
+ android:label="Frameworks In-Process Tests"/>
+
+</manifest>
diff --git a/services/tests/inprocesstests/AndroidTest.xml b/services/tests/inprocesstests/AndroidTest.xml
new file mode 100644
index 000000000000..89abe3c0891c
--- /dev/null
+++ b/services/tests/inprocesstests/AndroidTest.xml
@@ -0,0 +1,36 @@
+<?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.
+ -->
+<configuration description="Runs frameworks in-process tests">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="FrameworksInProcessTests.apk"/>
+ </target_preparer>
+
+ <!-- Restart to clear test code from system server -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="teardown-command" value="am restart" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.frameworks.inprocesstests"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="restart" value="false" />
+ </test>
+</configuration>
diff --git a/services/tests/inprocesstests/src/com/android/frameworks/inprocesstests/InstrumentSystemServerTest.java b/services/tests/inprocesstests/src/com/android/frameworks/inprocesstests/InstrumentSystemServerTest.java
new file mode 100644
index 000000000000..47fc73fed521
--- /dev/null
+++ b/services/tests/inprocesstests/src/com/android/frameworks/inprocesstests/InstrumentSystemServerTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworks.inprocesstests;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Process;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+
+public class InstrumentSystemServerTest {
+
+ private static final String TAG = "InstrumentSystemServerTest";
+
+ @Test
+ public void testCodeIsRunningInSystemServer() throws Exception {
+ assertThat(InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())
+ .isEqualTo("android");
+ assertThat(Process.myUid()).isEqualTo(Process.SYSTEM_UID);
+ assertThat(readCmdLine()).isEqualTo("system_server");
+ }
+
+ private static String readCmdLine() throws Exception {
+ BufferedReader in = null;
+ try {
+ in = new BufferedReader(new FileReader("/proc/self/cmdline"));
+ return in.readLine().trim();
+ } finally {
+ in.close();
+ }
+ }
+
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index 736a7be5e39e..ebd4a4c5378f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -27,9 +27,11 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.RescueParty.LEVEL_FACTORY_RESET;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import android.content.ContentResolver;
@@ -79,8 +81,11 @@ public class RescuePartyTest {
private static final String CALLING_PACKAGE2 = "com.package.name2";
private static final String NAMESPACE1 = "namespace1";
private static final String NAMESPACE2 = "namespace2";
+ private static final String NAMESPACE3 = "namespace3";
private static final String PROP_DEVICE_CONFIG_DISABLE_FLAG =
"persist.device_config.configuration.disable_rescue_party";
+ private static final String PROP_DISABLE_FACTORY_RESET_FLAG =
+ "persist.device_config.configuration.disable_rescue_party_factory_reset";
private MockitoSession mSession;
private HashMap<String, String> mSystemSettingsMap;
@@ -183,56 +188,65 @@ public class RescuePartyTest {
@Test
public void testBootLoopDetectionWithExecutionForAllRescueLevels() {
+ RescueParty.onSettingsProviderPublished(mMockContext);
+ verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+ mMonitorCallbackCaptor.capture()));
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
+
noteBoot();
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
+ verifiedTimesMap);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+ // Record DeviceConfig accesses
+ RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+ RemoteCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE2));
+
+ final String[] expectedAllResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
+
noteBoot();
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedAllResetNamespaces,
+ verifiedTimesMap);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
noteBoot();
- verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces,
+ verifiedTimesMap);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
noteBoot();
- verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
assertEquals(LEVEL_FACTORY_RESET,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
}
@Test
public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
- notePersistentAppCrash();
-
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
- assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+ notePersistentAppCrash(1);
- notePersistentAppCrash();
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
+ /*configResetVerifiedTimesMap=*/ null);
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null);
- assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+ notePersistentAppCrash(2);
- notePersistentAppCrash();
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null,
+ /*configResetVerifiedTimesMap=*/ null);
- verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
- assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+ notePersistentAppCrash(3);
- notePersistentAppCrash();
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
+ /*configResetVerifiedTimesMap=*/ null);
- verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
- assertEquals(LEVEL_FACTORY_RESET,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+ notePersistentAppCrash(4);
+ assertTrue(RescueParty.isAttemptingFactoryReset());
}
@Test
@@ -247,6 +261,7 @@ public class RescuePartyTest {
monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE2));
monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE2));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE3));
// Fake DeviceConfig value changes
monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
verify(mMockPackageWatchdog).startObservingHealth(observer,
@@ -255,31 +270,94 @@ public class RescuePartyTest {
verify(mMockPackageWatchdog, times(2)).startObservingHealth(eq(observer),
mPackageListCaptor.capture(),
eq(RescueParty.DEFAULT_OBSERVING_DURATION_MS));
+ monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
+ verify(mMockPackageWatchdog).startObservingHealth(observer,
+ Arrays.asList(CALLING_PACKAGE2), RescueParty.DEFAULT_OBSERVING_DURATION_MS);
assertTrue(mPackageListCaptor.getValue().containsAll(
Arrays.asList(CALLING_PACKAGE1, CALLING_PACKAGE2)));
// Perform and verify scoped resets
final String[] expectedResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
+ final String[] expectedAllResetNamespaces =
+ new String[]{NAMESPACE1, NAMESPACE2, NAMESPACE3};
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
observer.execute(new VersionedPackage(
- CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH);
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, expectedResetNamespaces);
- assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, expectedResetNamespaces,
+ verifiedTimesMap);
observer.execute(new VersionedPackage(
- CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedResetNamespaces);
- assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, expectedResetNamespaces,
+ verifiedTimesMap);
observer.execute(new VersionedPackage(
- CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING);
- verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/null);
- assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
- SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces,
+ verifiedTimesMap);
observer.execute(new VersionedPackage(
- CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH);
- verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
+ assertTrue(RescueParty.isAttemptingFactoryReset());
+ }
+
+ @Test
+ public void testNonDeviceConfigSettingsOnlyResetOncePerLevel() {
+ RescueParty.onSettingsProviderPublished(mMockContext);
+ verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
+ mMonitorCallbackCaptor.capture()));
+
+ // Record DeviceConfig accesses
+ RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
+ RemoteCallback monitorCallback = mMonitorCallbackCaptor.getValue();
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE1));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE1, NAMESPACE2));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE2));
+ monitorCallback.sendResult(getConfigAccessBundle(CALLING_PACKAGE2, NAMESPACE3));
+ // Fake DeviceConfig value changes
+ monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE1));
+ monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE2));
+ monitorCallback.sendResult(getConfigNamespaceUpdateBundle(NAMESPACE3));
+ // Perform and verify scoped resets
+ final String[] expectedPackage1ResetNamespaces = new String[]{NAMESPACE1, NAMESPACE2};
+ final String[] expectedPackage2ResetNamespaces = new String[]{NAMESPACE2, NAMESPACE3};
+ final String[] expectedAllResetNamespaces =
+ new String[]{NAMESPACE1, NAMESPACE2, NAMESPACE3};
+ HashMap<String, Integer> verifiedTimesMap = new HashMap<String, Integer>();
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS,
+ expectedPackage1ResetNamespaces, verifiedTimesMap);
+
+ // Settings.Global & Settings.Secure should still remain the same execution times.
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE2, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, 1);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS,
+ expectedPackage2ResetNamespaces, verifiedTimesMap);
+
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES,
+ expectedPackage1ResetNamespaces, verifiedTimesMap);
+
+ // Settings.Global & Settings.Secure should still remain the same execution times.
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE2, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES,
+ expectedPackage2ResetNamespaces, verifiedTimesMap);
+
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces,
+ verifiedTimesMap);
+
+ // Settings.Global & Settings.Secure should still remain the same execution times.
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE2, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3);
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, expectedAllResetNamespaces,
+ verifiedTimesMap);
+
+ observer.execute(new VersionedPackage(
+ CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
assertTrue(RescueParty.isAttemptingFactoryReset());
}
@@ -288,7 +366,6 @@ public class RescuePartyTest {
for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
noteBoot();
}
- verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
assertTrue(RescueParty.isAttemptingFactoryReset());
}
@@ -298,7 +375,8 @@ public class RescuePartyTest {
RescueParty.onSettingsProviderPublished(mMockContext);
- verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null);
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
+ /*configResetVerifiedTimesMap=*/ null);
assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
}
@@ -322,11 +400,11 @@ public class RescuePartyTest {
SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true));
assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
- PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING), false);
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1), false);
SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
assertTrue(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
- PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING));
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1));
}
@Test
@@ -335,58 +413,49 @@ public class RescuePartyTest {
SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(true));
assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
- PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING), false);
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1), false);
- // Restore the property value initalized in SetUp()
+ // Restore the property value initialized in SetUp()
SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
SystemProperties.set(PROP_DEVICE_CONFIG_DISABLE_FLAG, Boolean.toString(false));
}
@Test
+ public void testDisablingFactoryResetByDeviceConfigFlag() {
+ SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, Boolean.toString(true));
+
+ for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
+ noteBoot();
+ }
+ assertFalse(RescueParty.isAttemptingFactoryReset());
+
+ // Restore the property value initialized in SetUp()
+ SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, "");
+ }
+
+ @Test
public void testHealthCheckLevels() {
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
// Ensure that no action is taken for cases where the failure reason is unknown
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- LEVEL_FACTORY_RESET));
- assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_UNKNOWN),
+ assertEquals(observer.onHealthCheckFailed(null, PackageWatchdog.FAILURE_REASON_UNKNOWN, 1),
PackageHealthObserverImpact.USER_IMPACT_NONE);
- /*
- For the following cases, ensure that the returned user impact corresponds with the user
- impact of the next available rescue level, not the current one.
- */
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- RescueParty.LEVEL_NONE));
+ // Ensure the correct user impact is returned for each mitigation count.
assertEquals(observer.onHealthCheckFailed(null,
- PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 1),
PackageHealthObserverImpact.USER_IMPACT_LOW);
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS));
assertEquals(observer.onHealthCheckFailed(null,
- PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 2),
PackageHealthObserverImpact.USER_IMPACT_LOW);
-
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES));
assertEquals(observer.onHealthCheckFailed(null,
- PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 3),
PackageHealthObserverImpact.USER_IMPACT_HIGH);
-
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS));
assertEquals(observer.onHealthCheckFailed(null,
- PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
- PackageHealthObserverImpact.USER_IMPACT_HIGH);
-
-
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- LEVEL_FACTORY_RESET));
- assertEquals(observer.onHealthCheckFailed(null,
- PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING),
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4),
PackageHealthObserverImpact.USER_IMPACT_HIGH);
}
@@ -419,28 +488,27 @@ public class RescuePartyTest {
assertEquals(observer.onBootLoop(), PackageHealthObserverImpact.USER_IMPACT_HIGH);
}
- @Test
- public void testRescueLevelIncrementsWhenExecuted() {
- RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
- SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(
- RescueParty.LEVEL_NONE));
- observer.execute(sFailingPackage,
- PackageWatchdog.FAILURE_REASON_APP_CRASH);
- assertEquals(SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, -1),
- RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS);
- }
-
- private void verifySettingsResets(int resetMode, String[] resetNamespaces) {
+ private void verifySettingsResets(int resetMode, String[] resetNamespaces,
+ HashMap<String, Integer> configResetVerifiedTimesMap) {
verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null,
resetMode, UserHandle.USER_SYSTEM));
verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(),
eq(resetMode), anyInt()));
// Verify DeviceConfig resets
if (resetNamespaces == null) {
- verify(() -> DeviceConfig.resetToDefaults(resetMode, /*namespace=*/ null));
+ verify(() -> DeviceConfig.resetToDefaults(anyInt(), anyString()), never());
} else {
for (String namespace : resetNamespaces) {
- verify(() -> DeviceConfig.resetToDefaults(resetMode, namespace));
+ int verifiedTimes = 0;
+ if (configResetVerifiedTimesMap != null
+ && configResetVerifiedTimesMap.get(namespace) != null) {
+ verifiedTimes = configResetVerifiedTimesMap.get(namespace);
+ }
+ verify(() -> DeviceConfig.resetToDefaults(RescueParty.DEVICE_CONFIG_RESET_MODE,
+ namespace), times(verifiedTimes + 1));
+ if (configResetVerifiedTimesMap != null) {
+ configResetVerifiedTimesMap.put(namespace, verifiedTimes + 1);
+ }
}
}
}
@@ -449,9 +517,9 @@ public class RescuePartyTest {
RescuePartyObserver.getInstance(mMockContext).executeBootLoopMitigation();
}
- private void notePersistentAppCrash() {
+ private void notePersistentAppCrash(int mitigationCount) {
RescuePartyObserver.getInstance(mMockContext).execute(new VersionedPackage(
- "com.package.name", 1), PackageWatchdog.FAILURE_REASON_APP_CRASH);
+ "com.package.name", 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, mitigationCount);
}
private Bundle getConfigAccessBundle(String callingPackage, String namespace) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index db4aba519a6a..8e4942e1ad5c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -47,6 +47,7 @@ import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_F
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_LONG_TIME;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_SHORT_TIME;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
+import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LAZY_BATCHING;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LISTENER_TIMEOUT;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MAX_INTERVAL;
import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_FUTURITY;
@@ -62,6 +63,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -365,7 +367,7 @@ public class AlarmManagerServiceTest {
}
private void setIdleUntilAlarm(int type, long triggerTime, PendingIntent pi) {
- setTestAlarm(type, triggerTime, pi, 0, FLAG_IDLE_UNTIL, TEST_CALLING_UID);
+ setTestAlarm(type, triggerTime, pi, 0, FLAG_IDLE_UNTIL | FLAG_STANDALONE, TEST_CALLING_UID);
}
private void setWakeFromIdle(int type, long triggerTime, PendingIntent pi) {
@@ -410,6 +412,12 @@ public class AlarmManagerServiceTest {
mService.mConstants.onPropertiesChanged(mDeviceConfigProperties);
}
+ private void setDeviceConfigBoolean(String key, boolean val) {
+ mDeviceConfigKeys.add(key);
+ doReturn(val).when(mDeviceConfigProperties).getBoolean(eq(key), anyBoolean());
+ mService.mConstants.onPropertiesChanged(mDeviceConfigProperties);
+ }
+
/**
* Lowers quotas to make testing feasible. Careful while calling as this will replace any
* existing settings for the calling test.
@@ -1382,6 +1390,35 @@ public class AlarmManagerServiceTest {
}
}
+ @Test
+ public void alarmStoreMigration() {
+ setDeviceConfigBoolean(KEY_LAZY_BATCHING, false);
+ final int numAlarms = 10;
+ final PendingIntent[] pis = new PendingIntent[numAlarms];
+ for (int i = 0; i < numAlarms; i++) {
+ pis[i] = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 1, pis[i]);
+ }
+
+ final ArrayList<Alarm> alarmsBefore = mService.mAlarmStore.asList();
+ assertEquals(numAlarms, alarmsBefore.size());
+ for (int i = 0; i < numAlarms; i++) {
+ final PendingIntent pi = pis[i];
+ assertTrue(i + "th PendingIntent missing: ",
+ alarmsBefore.removeIf(a -> a.matches(pi, null)));
+ }
+
+ setDeviceConfigBoolean(KEY_LAZY_BATCHING, true);
+
+ final ArrayList<Alarm> alarmsAfter = mService.mAlarmStore.asList();
+ assertEquals(numAlarms, alarmsAfter.size());
+ for (int i = 0; i < numAlarms; i++) {
+ final PendingIntent pi = pis[i];
+ assertTrue(i + "th PendingIntent missing: ",
+ alarmsAfter.removeIf(a -> a.matches(pi, null)));
+ }
+ }
+
@After
public void tearDown() {
if (mMockingSession != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
index c4fc61a5aa6e..42fa3d480046 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmStoreTest.java
@@ -16,6 +16,9 @@
package com.android.server.alarm;
+import static android.app.AlarmManager.ELAPSED_REALTIME;
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+
import static com.android.server.alarm.Constants.TEST_CALLING_PACKAGE;
import static com.android.server.alarm.Constants.TEST_CALLING_UID;
@@ -23,35 +26,50 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.platform.test.annotations.Presubmit;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
import java.util.ArrayList;
@Presubmit
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
public class AlarmStoreTest {
- private AlarmStore mAlarmStore;
- @Before
- public void setUp() {
- mAlarmStore = new BatchingAlarmStore(null);
+ @Parameter
+ public AlarmStore mAlarmStore;
+
+ @Parameters
+ public static Object[] stores() {
+ return new AlarmStore[]{
+ new LazyAlarmStore(),
+ new BatchingAlarmStore(),
+ };
}
private static Alarm createAlarm(long whenElapsed, long windowLength) {
- return createAlarm(AlarmManager.ELAPSED_REALTIME, whenElapsed, windowLength, 0);
+ return createAlarm(ELAPSED_REALTIME, whenElapsed, windowLength, 0);
}
private static Alarm createWakeupAlarm(long whenElapsed, long windowLength, int flags) {
- return createAlarm(AlarmManager.ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength, flags);
+ return createAlarm(ELAPSED_REALTIME_WAKEUP, whenElapsed, windowLength, flags);
+ }
+
+ private static Alarm createAlarmClock(long whenElapsed) {
+ final AlarmManager.AlarmClockInfo info = new AlarmManager.AlarmClockInfo(whenElapsed,
+ mock(PendingIntent.class));
+ return new Alarm(ELAPSED_REALTIME_WAKEUP, whenElapsed, whenElapsed, 0, 0,
+ mock(PendingIntent.class), null, null, null, 0, info, TEST_CALLING_UID,
+ TEST_CALLING_PACKAGE);
}
private static Alarm createAlarm(int type, long whenElapsed, long windowLength, int flags) {
@@ -206,4 +224,21 @@ public class AlarmStoreTest {
});
assertEquals(7, mAlarmStore.getNextDeliveryTime());
}
+
+ @Test
+ public void alarmClockRemovalListener() {
+ final Runnable onRemoved = mock(Runnable.class);
+ mAlarmStore.setAlarmClockRemovalListener(onRemoved);
+
+ final Alarm simpleAlarm = createAlarm(5, 0);
+ final Alarm alarmClock = createAlarmClock(10);
+
+ addAlarmsToStore(simpleAlarm, alarmClock);
+
+ mAlarmStore.remove(simpleAlarm::equals);
+ verifyZeroInteractions(onRemoved);
+
+ mAlarmStore.remove(alarmClock::equals);
+ verify(onRemoved).run();
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 6a6fb82897bb..dbdee979b6a4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -42,6 +42,8 @@ import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.server.LocalServices;
import com.android.server.lights.LightsManager;
+import com.google.common.truth.Truth;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -190,6 +192,102 @@ public class LocalDisplayAdapterTest {
16000);
}
+ private static class DisplayModeWrapper {
+ public SurfaceControl.DisplayConfig config;
+ public float[] expectedAlternativeRefreshRates;
+
+ DisplayModeWrapper(SurfaceControl.DisplayConfig config,
+ float[] expectedAlternativeRefreshRates) {
+ this.config = config;
+ this.expectedAlternativeRefreshRates = expectedAlternativeRefreshRates;
+ }
+ }
+
+ /**
+ * Updates the <code>display</code> using the given <code>modes</code> and then checks if the
+ * <code>expectedAlternativeRefreshRates</code> are present for each of the
+ * <code>modes</code>.
+ */
+ private void testAlternativeRefreshRatesCommon(FakeDisplay display, DisplayModeWrapper[] modes)
+ throws InterruptedException {
+ // Update the display.
+ SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[modes.length];
+ for (int i = 0; i < modes.length; i++) {
+ configs[i] = modes[i].config;
+ }
+ display.configs = configs;
+ setUpDisplay(display);
+ mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+ assertThat(mListener.changedDisplays.size()).isGreaterThan(0);
+
+ // Verify the supported modes are updated accordingly.
+ DisplayDevice displayDevice =
+ mListener.changedDisplays.get(mListener.changedDisplays.size() - 1);
+ displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
+ Display.Mode[] supportedModes = displayDevice.getDisplayDeviceInfoLocked().supportedModes;
+ assertThat(supportedModes.length).isEqualTo(configs.length);
+
+ for (int i = 0; i < modes.length; i++) {
+ assertModeIsSupported(supportedModes, configs[i],
+ modes[i].expectedAlternativeRefreshRates);
+ }
+ }
+
+ @Test
+ public void testAfterDisplayChange_AlternativeRefreshRatesAreUpdated() throws Exception {
+ FakeDisplay display = new FakeDisplay(PORT_A);
+ setUpDisplay(display);
+ updateAvailableDisplays();
+ mAdapter.registerLocked();
+ waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+ testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(1920, 1080, 60f, 0), new float[]{24f, 50f}),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(1920, 1080, 50f, 0), new float[]{24f, 60f}),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(1920, 1080, 24f, 0), new float[]{50f, 60f}),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(3840, 2160, 60f, 0), new float[]{24f, 50f}),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(3840, 2160, 50f, 0), new float[]{24f, 60f}),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(3840, 2160, 24f, 0), new float[]{50f, 60f}),
+ });
+
+ testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(1920, 1080, 60f, 0), new float[]{50f}),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(1920, 1080, 50f, 0), new float[]{60f}),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(1920, 1080, 24f, 1), new float[0]),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(3840, 2160, 60f, 2), new float[0]),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(3840, 2160, 50f, 3), new float[]{24f}),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(3840, 2160, 24f, 3), new float[]{50f}),
+ });
+
+ testAlternativeRefreshRatesCommon(display, new DisplayModeWrapper[] {
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(1920, 1080, 60f, 0), new float[0]),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(1920, 1080, 50f, 1), new float[0]),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(1920, 1080, 24f, 2), new float[0]),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(3840, 2160, 60f, 3), new float[0]),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(3840, 2160, 50f, 4), new float[0]),
+ new DisplayModeWrapper(
+ createFakeDisplayConfig(3840, 2160, 24f, 5), new float[0]),
+ });
+ }
+
@Test
public void testAfterDisplayChange_DisplayModesAreUpdated() throws Exception {
SurfaceControl.DisplayConfig displayConfig = createFakeDisplayConfig(1920, 1080, 60f);
@@ -419,6 +517,23 @@ public class LocalDisplayAdapterTest {
x -> x.matches(mode.width, mode.height, mode.refreshRate))).isTrue();
}
+ private void assertModeIsSupported(Display.Mode[] supportedModes,
+ SurfaceControl.DisplayConfig mode, float[] alternativeRefreshRates) {
+ float[] sortedAlternativeRates =
+ Arrays.copyOf(alternativeRefreshRates, alternativeRefreshRates.length);
+ Arrays.sort(sortedAlternativeRates);
+
+ String message = "Expected " + mode + " with alternativeRefreshRates = "
+ + Arrays.toString(alternativeRefreshRates) + " to be in list of supported modes = "
+ + Arrays.toString(supportedModes);
+ Truth.assertWithMessage(message)
+ .that(Arrays.stream(supportedModes)
+ .anyMatch(x -> x.matches(mode.width, mode.height, mode.refreshRate)
+ && Arrays.equals(x.getAlternativeRefreshRates(), sortedAlternativeRates)))
+ .isTrue();
+ }
+
+
private static class FakeDisplay {
public final DisplayAddress.Physical address;
public final IBinder token = new Binder();
@@ -492,12 +607,18 @@ public class LocalDisplayAdapterTest {
private static SurfaceControl.DisplayConfig createFakeDisplayConfig(int width, int height,
float refreshRate) {
+ return createFakeDisplayConfig(width, height, refreshRate, 0);
+ }
+
+ private static SurfaceControl.DisplayConfig createFakeDisplayConfig(int width, int height,
+ float refreshRate, int configGroup) {
final SurfaceControl.DisplayConfig config = new SurfaceControl.DisplayConfig();
config.width = width;
config.height = height;
config.refreshRate = refreshRate;
config.xDpi = 100;
config.yDpi = 100;
+ config.configGroup = configGroup;
return config;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
index 5c2b8ce4b432..b9551999cacb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
@@ -27,17 +27,18 @@ import android.content.res.Resources;
import android.os.Binder;
import android.os.IBinder;
import android.view.SurfaceControl;
-import android.view.SurfaceControl.DisplayPrimaries;
import android.view.SurfaceControl.CieXyz;
+import android.view.SurfaceControl.DisplayPrimaries;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.R;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.R;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -190,6 +191,7 @@ public class DisplayWhiteBalanceTintControllerTest {
* Matrix should match the precalculated one for given cct and display primaries.
*/
@Test
+ @Ignore
public void displayWhiteBalance_validateTransformMatrix() {
DisplayPrimaries displayPrimaries = new DisplayPrimaries();
displayPrimaries.red = new CieXyz();
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 043ca9e02873..dcbf8c02edf9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -38,6 +38,7 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.IActivityManager;
+import android.app.UiModeManager;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.app.usage.UsageStatsManagerInternal;
@@ -147,6 +148,8 @@ public class JobSchedulerServiceTest {
JobSchedulerService.sSystemClock = Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
JobSchedulerService.sElapsedRealtimeClock =
Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC);
+ // Called by DeviceIdlenessTracker
+ when(mContext.getSystemService(UiModeManager.class)).thenReturn(mock(UiModeManager.class));
mService = new TestJobSchedulerService(mContext);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 79542084ac36..77fef1274415 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -1430,8 +1430,8 @@ public class QuotaControllerTest {
createTimingSession(now - (HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
mQuotaController.saveTimingSession(0, "com.android.test",
createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
- mQuotaController.incrementJobCount(0, "com.android.test", 5);
synchronized (mQuotaController.mLock) {
+ mQuotaController.incrementJobCountLocked(0, "com.android.test", 5);
assertTrue(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
}
}
@@ -1445,8 +1445,8 @@ public class QuotaControllerTest {
createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
mQuotaController.saveTimingSession(0, "com.android.test.spam",
createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount));
- mQuotaController.incrementJobCount(0, "com.android.test.spam", jobCount);
synchronized (mQuotaController.mLock) {
+ mQuotaController.incrementJobCountLocked(0, "com.android.test.spam", jobCount);
assertFalse(mQuotaController.isWithinQuotaLocked(
0, "com.android.test.spam", WORKING_INDEX));
}
@@ -1471,8 +1471,8 @@ public class QuotaControllerTest {
createTimingSession(now - (30 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
mQuotaController.saveTimingSession(0, "com.android.test",
createTimingSession(now - (5 * MINUTE_IN_MILLIS), 4 * MINUTE_IN_MILLIS, 5));
- mQuotaController.incrementJobCount(0, "com.android.test", 5);
synchronized (mQuotaController.mLock) {
+ mQuotaController.incrementJobCountLocked(0, "com.android.test", 5);
assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
}
}
@@ -1486,8 +1486,8 @@ public class QuotaControllerTest {
createTimingSession(now - (HOUR_IN_MILLIS), 15 * MINUTE_IN_MILLIS, 25));
mQuotaController.saveTimingSession(0, "com.android.test",
createTimingSession(now - (5 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, jobCount));
- mQuotaController.incrementJobCount(0, "com.android.test", jobCount);
synchronized (mQuotaController.mLock) {
+ mQuotaController.incrementJobCountLocked(0, "com.android.test", jobCount);
assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test", WORKING_INDEX));
}
}
@@ -1637,9 +1637,10 @@ public class QuotaControllerTest {
mQuotaController.saveTimingSession(0, "com.android.test",
createTimingSession(now - ((10 - i) * MINUTE_IN_MILLIS), 30 * SECOND_IN_MILLIS,
2));
- mQuotaController.incrementJobCount(0, "com.android.test", 2);
synchronized (mQuotaController.mLock) {
+ mQuotaController.incrementJobCountLocked(0, "com.android.test", 2);
+
assertEquals("Rare has incorrect quota status with " + (i + 1) + " sessions",
i < 2,
mQuotaController.isWithinQuotaLocked(0, "com.android.test", RARE_INDEX));
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
index d260e4dce79a..b55da07b0618 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -31,6 +31,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
import static com.android.server.location.LocationUtils.createLocation;
+import static com.android.server.location.LocationUtils.createLocationResult;
import static com.android.server.location.listeners.RemoteListenerRegistration.IN_PROCESS_EXECUTOR;
import static com.google.common.truth.Truth.assertThat;
@@ -40,10 +41,12 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.after;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -52,6 +55,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.MockitoAnnotations.initMocks;
+import static org.testng.Assert.assertThrows;
import android.content.Context;
import android.location.ILocationCallback;
@@ -60,6 +64,7 @@ import android.location.Location;
import android.location.LocationManagerInternal;
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.LocationRequest;
+import android.location.LocationResult;
import android.location.util.identity.CallerIdentity;
import android.os.Bundle;
import android.os.ICancellationSignal;
@@ -85,11 +90,12 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
@@ -152,7 +158,7 @@ public class LocationProviderManagerTest {
mPassive = new PassiveLocationProviderManager(mContext, mInjector);
mPassive.startManager();
- mPassive.setRealProvider(new PassiveProvider(mContext));
+ mPassive.setRealProvider(new PassiveLocationProvider(mContext));
mProvider = new TestProvider(PROPERTIES, IDENTITY);
mProvider.setProviderAllowed(true);
@@ -308,7 +314,7 @@ public class LocationProviderManagerTest {
@Test
public void testGetLastLocation_ClearOnMockRemoval() {
- MockProvider mockProvider = new MockProvider(PROPERTIES, IDENTITY);
+ MockLocationProvider mockProvider = new MockLocationProvider(PROPERTIES, IDENTITY);
mockProvider.setAllowed(true);
mManager.setMockProvider(mockProvider);
@@ -339,13 +345,9 @@ public class LocationProviderManagerTest {
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
- Location loc = createLocation(NAME, mRandom);
+ LocationResult loc = createLocationResult(NAME, mRandom);
mProvider.setProviderLocation(loc);
-
- ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
- verify(listener).onLocationChanged(locationCaptor.capture(),
- nullable(IRemoteCallback.class));
- assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ verify(listener).onLocationChanged(eq(loc), nullable(IRemoteCallback.class));
}
@Test
@@ -358,8 +360,6 @@ public class LocationProviderManagerTest {
@Test
public void testRegisterListener() throws Exception {
- ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
-
ILocationListener listener = createMockLocationListener();
mManager.registerLocationRequest(
new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build(),
@@ -367,17 +367,15 @@ public class LocationProviderManagerTest {
PERMISSION_FINE,
listener);
- Location loc = createLocation(NAME, mRandom);
+ LocationResult loc = createLocationResult(NAME, mRandom);
mProvider.setProviderLocation(loc);
- verify(listener, times(1)).onLocationChanged(locationCaptor.capture(),
- nullable(IRemoteCallback.class));
- assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ verify(listener).onLocationChanged(eq(loc), nullable(IRemoteCallback.class));
mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, false);
- loc = createLocation(NAME, mRandom);
+ loc = createLocationResult(NAME, mRandom);
mProvider.setProviderLocation(loc);
- verify(listener, times(1)).onLocationChanged(any(Location.class),
+ verify(listener, times(1)).onLocationChanged(any(LocationResult.class),
nullable(IRemoteCallback.class));
mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
@@ -385,25 +383,21 @@ public class LocationProviderManagerTest {
mProvider.setAllowed(false);
verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, false);
- loc = createLocation(NAME, mRandom);
+ loc = createLocationResult(NAME, mRandom);
mProvider.setProviderLocation(loc);
- verify(listener, times(1)).onLocationChanged(any(Location.class),
+ verify(listener, times(1)).onLocationChanged(any(LocationResult.class),
nullable(IRemoteCallback.class));
mProvider.setAllowed(true);
verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, true);
- loc = createLocation(NAME, mRandom);
+ loc = createLocationResult(NAME, mRandom);
mProvider.setProviderLocation(loc);
- verify(listener, times(2)).onLocationChanged(locationCaptor.capture(),
- nullable(IRemoteCallback.class));
- assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ verify(listener).onLocationChanged(eq(loc), nullable(IRemoteCallback.class));
}
@Test
public void testRegisterListener_SameProcess() throws Exception {
- ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
-
CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
"attribution");
@@ -414,11 +408,10 @@ public class LocationProviderManagerTest {
PERMISSION_FINE,
listener);
- Location loc = createLocation(NAME, mRandom);
+ LocationResult loc = createLocationResult(NAME, mRandom);
mProvider.setProviderLocation(loc);
- verify(listener, timeout(TIMEOUT_MS).times(1)).onLocationChanged(locationCaptor.capture(),
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onLocationChanged(eq(loc),
nullable(IRemoteCallback.class));
- assertThat(locationCaptor.getValue()).isEqualTo(loc);
}
@Test
@@ -432,7 +425,7 @@ public class LocationProviderManagerTest {
mManager.unregisterLocationRequest(listener);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
- verify(listener, never()).onLocationChanged(any(Location.class),
+ verify(listener, never()).onLocationChanged(any(LocationResult.class),
nullable(IRemoteCallback.class));
mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
@@ -463,7 +456,7 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(createLocation(NAME, mRandom));
mManager.unregisterLocationRequest(listener);
blocker.countDown();
- verify(listener, after(TIMEOUT_MS).never()).onLocationChanged(any(Location.class),
+ verify(listener, after(TIMEOUT_MS).never()).onLocationChanged(any(LocationResult.class),
nullable(IRemoteCallback.class));
}
@@ -483,7 +476,7 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(createLocation(NAME, mRandom));
mProvider.setProviderLocation(createLocation(NAME, mRandom));
- verify(listener, times(5)).onLocationChanged(any(Location.class),
+ verify(listener, times(5)).onLocationChanged(any(LocationResult.class),
nullable(IRemoteCallback.class));
}
@@ -498,7 +491,7 @@ public class LocationProviderManagerTest {
mInjector.getAlarmHelper().incrementAlarmTime(5000);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
- verify(listener, never()).onLocationChanged(any(Location.class),
+ verify(listener, never()).onLocationChanged(any(LocationResult.class),
nullable(IRemoteCallback.class));
}
@@ -514,7 +507,7 @@ public class LocationProviderManagerTest {
Thread.sleep(25);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
- verify(listener, never()).onLocationChanged(any(Location.class),
+ verify(listener, never()).onLocationChanged(any(LocationResult.class),
nullable(IRemoteCallback.class));
}
@@ -530,8 +523,8 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(createLocation(NAME, mRandom));
mProvider.setProviderLocation(createLocation(NAME, mRandom));
- verify(listener, times(1)).onLocationChanged(any(Location.class),
- nullable(IRemoteCallback.class));
+ verify(listener, times(1)).onLocationChanged(
+ any(LocationResult.class), nullable(IRemoteCallback.class));
}
@Test
@@ -547,8 +540,8 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(loc);
mProvider.setProviderLocation(loc);
- verify(listener, times(1)).onLocationChanged(any(Location.class),
- nullable(IRemoteCallback.class));
+ verify(listener, times(1)).onLocationChanged(
+ any(LocationResult.class), nullable(IRemoteCallback.class));
}
@Test
@@ -562,7 +555,7 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(createLocation(NAME, mRandom));
- verify(listener, never()).onLocationChanged(any(Location.class),
+ verify(listener, never()).onLocationChanged(any(LocationResult.class),
nullable(IRemoteCallback.class));
}
@@ -592,7 +585,7 @@ public class LocationProviderManagerTest {
verify(mWakeLock, never()).release();
blocker.countDown();
- verify(listener, timeout(TIMEOUT_MS)).onLocationChanged(any(Location.class),
+ verify(listener, timeout(TIMEOUT_MS)).onLocationChanged(any(LocationResult.class),
nullable(IRemoteCallback.class));
verify(mWakeLock).acquire(anyLong());
verify(mWakeLock, timeout(TIMEOUT_MS)).release();
@@ -610,7 +603,7 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(createLocation(NAME, mRandom));
mProvider.setProviderLocation(createLocation(NAME, mRandom));
verify(listener, times(1))
- .onLocationChanged(any(Location.class), nullable(IRemoteCallback.class));
+ .onLocationChanged(any(LocationResult.class), nullable(IRemoteCallback.class));
}
@Test
@@ -627,13 +620,11 @@ public class LocationProviderManagerTest {
mProvider.setProviderLocation(createLocation(NAME, mRandom));
mProvider.setProviderLocation(createLocation(NAME, mRandom));
verify(listener, times(1))
- .onLocationChanged(any(Location.class), nullable(IRemoteCallback.class));
+ .onLocationChanged(any(LocationResult.class), nullable(IRemoteCallback.class));
}
@Test
public void testGetCurrentLocation() throws Exception {
- ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
-
ILocationCallback listener = createMockGetCurrentLocationListener();
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
mManager.getCurrentLocation(request, IDENTITY, PERMISSION_FINE, listener);
@@ -641,9 +632,7 @@ public class LocationProviderManagerTest {
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
mProvider.setProviderLocation(createLocation(NAME, mRandom));
-
- verify(listener, times(1)).onLocation(locationCaptor.capture());
- assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ verify(listener, times(1)).onLocation(loc);
}
@Test
@@ -655,7 +644,6 @@ public class LocationProviderManagerTest {
cancellationSignal.cancel();
mProvider.setProviderLocation(createLocation(NAME, mRandom));
-
verify(listener, never()).onLocation(nullable(Location.class));
}
@@ -686,17 +674,13 @@ public class LocationProviderManagerTest {
@Test
public void testGetCurrentLocation_LastLocation() throws Exception {
- ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
-
Location loc = createLocation(NAME, mRandom);
mProvider.setProviderLocation(loc);
ILocationCallback listener = createMockGetCurrentLocationListener();
LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
mManager.getCurrentLocation(request, IDENTITY, PERMISSION_FINE, listener);
-
- verify(listener, times(1)).onLocation(locationCaptor.capture());
- assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ verify(listener, times(1)).onLocation(eq(loc));
}
@Test
@@ -710,6 +694,32 @@ public class LocationProviderManagerTest {
}
@Test
+ public void testFlush() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ mManager.registerLocationRequest(
+ new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build(),
+ IDENTITY,
+ PERMISSION_FINE,
+ listener);
+
+ mManager.flush(listener, 99);
+
+ LocationResult loc = createLocationResult(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ mProvider.completeFlushes();
+
+ InOrder inOrder = inOrder(listener);
+ inOrder.verify(listener).onLocationChanged(eq(loc), any(IRemoteCallback.class));
+ inOrder.verify(listener).onFlushComplete(99);
+ }
+
+ @Test
+ public void testFlush_UnknownKey() {
+ assertThrows(IllegalArgumentException.class,
+ () -> mManager.flush(createMockLocationListener(), 0));
+ }
+
+ @Test
public void testLocationMonitoring() {
assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
IDENTITY.getPackageName())).isFalse();
@@ -791,7 +801,8 @@ public class LocationProviderManagerTest {
.build();
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
- verify(listener1).onLocationChanged(any(Location.class), nullable(IRemoteCallback.class));
+ verify(listener1).onLocationChanged(any(LocationResult.class),
+ nullable(IRemoteCallback.class));
assertThat(mProvider.getRequest().isActive()).isFalse();
@@ -941,7 +952,8 @@ public class LocationProviderManagerTest {
private ILocationListener createMockLocationListener() {
return spy(new ILocationListener.Stub() {
@Override
- public void onLocationChanged(Location location, IRemoteCallback onCompleteCallback) {
+ public void onLocationChanged(LocationResult location,
+ IRemoteCallback onCompleteCallback) {
if (onCompleteCallback != null) {
try {
onCompleteCallback.sendResult(null);
@@ -952,6 +964,10 @@ public class LocationProviderManagerTest {
}
@Override
+ public void onFlushComplete(int requestCode) {
+ }
+
+ @Override
public void onProviderEnabledChanged(String provider, boolean enabled) {
}
});
@@ -969,6 +985,8 @@ public class LocationProviderManagerTest {
private ProviderRequest mProviderRequest = ProviderRequest.EMPTY_REQUEST;
+ private final ArrayList<Runnable> mFlushCallbacks = new ArrayList<>();
+
TestProvider(ProviderProperties properties, CallerIdentity identity) {
super(DIRECT_EXECUTOR, identity);
setProperties(properties);
@@ -979,7 +997,18 @@ public class LocationProviderManagerTest {
}
public void setProviderLocation(Location l) {
- reportLocation(new Location(l));
+ reportLocation(LocationResult.create(new Location(l)));
+ }
+
+ public void setProviderLocation(LocationResult l) {
+ reportLocation(l);
+ }
+
+ public void completeFlushes() {
+ for (Runnable r : mFlushCallbacks) {
+ r.run();
+ }
+ mFlushCallbacks.clear();
}
public ProviderRequest getRequest() {
@@ -992,6 +1021,11 @@ public class LocationProviderManagerTest {
}
@Override
+ protected void onFlush(Runnable callback) {
+ mFlushCallbacks.add(callback);
+ }
+
+ @Override
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationUtils.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationUtils.java
index decb3a6e334a..593e62a76f41 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationUtils.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationUtils.java
@@ -17,8 +17,10 @@
package com.android.server.location;
import android.location.Location;
+import android.location.LocationResult;
import android.os.SystemClock;
+import java.util.Arrays;
import java.util.Random;
public final class LocationUtils {
@@ -38,6 +40,19 @@ public final class LocationUtils {
MIN_ACCURACY + random.nextFloat() * (MAX_ACCURACY - MIN_ACCURACY));
}
+ public static LocationResult createLocationResult(String provider, Random random) {
+ return LocationResult.wrap(createLocation(provider, random));
+ }
+
+ public static LocationResult createLocationResult(String provider, Random random,
+ int numLocations) {
+ Location[] locations = new Location[numLocations];
+ for (int i = 0; i < numLocations; i++) {
+ locations[i] = createLocation(provider, random);
+ }
+ return LocationResult.create(Arrays.asList(locations));
+ }
+
public static Location createLocation(String provider, double latitude, double longitude,
float accuracy) {
Location location = new Location(provider);
@@ -48,4 +63,9 @@ public final class LocationUtils {
location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
return location;
}
+
+ public static LocationResult createLocationResult(String provider, double latitude,
+ double longitude, float accuracy) {
+ return LocationResult.wrap(createLocation(provider, latitude, longitude, accuracy));
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java
index 374fc777546f..28fd70aea22f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java
@@ -21,12 +21,14 @@ import static com.android.internal.location.ProviderRequest.EMPTY_REQUEST;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.location.Criteria;
import android.location.Location;
+import android.location.LocationResult;
import android.location.util.identity.CallerIdentity;
import android.platform.test.annotations.Presubmit;
@@ -50,7 +52,7 @@ public class MockableLocationProviderTest {
private ProviderListenerCapture mListener;
private AbstractLocationProvider mRealProvider;
- private MockProvider mMockProvider;
+ private MockLocationProvider mMockProvider;
private MockableLocationProvider mProvider;
@@ -60,7 +62,7 @@ public class MockableLocationProviderTest {
mListener = new ProviderListenerCapture(lock);
mRealProvider = spy(new FakeProvider());
- mMockProvider = spy(new MockProvider(new ProviderProperties(
+ mMockProvider = spy(new MockLocationProvider(new ProviderProperties(
false,
false,
false,
@@ -117,6 +119,20 @@ public class MockableLocationProviderTest {
}
@Test
+ public void testFlush() {
+ Runnable listener = mock(Runnable.class);
+ mProvider.flush(listener);
+ verify(mRealProvider).onFlush(listener);
+ verify(listener).run();
+
+ listener = mock(Runnable.class);
+ mProvider.setMockProvider(mMockProvider);
+ mProvider.flush(listener);
+ verify(mMockProvider).onFlush(listener);
+ verify(listener).run();
+ }
+
+ @Test
public void testSendExtraCommand() {
mProvider.sendExtraCommand(0, 0, "command", null);
verify(mRealProvider, times(1)).onExtraCommand(0, 0, "command", null);
@@ -158,15 +174,15 @@ public class MockableLocationProviderTest {
@Test
public void testReportLocation() {
- Location realLocation = new Location("real");
- Location mockLocation = new Location("mock");
+ LocationResult realLocation = LocationResult.create(new Location("real"));
+ LocationResult mockLocation = LocationResult.create(new Location("mock"));
mRealProvider.reportLocation(realLocation);
- assertThat(mListener.getNextLocation()).isEqualTo(realLocation);
+ assertThat(mListener.getNextLocationResult()).isEqualTo(realLocation);
mProvider.setMockProvider(mMockProvider);
mRealProvider.reportLocation(realLocation);
mMockProvider.reportLocation(mockLocation);
- assertThat(mListener.getNextLocation()).isEqualTo(mockLocation);
+ assertThat(mListener.getNextLocationResult()).isEqualTo(mockLocation);
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
index 879b76793863..1df2854028e7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
@@ -23,7 +23,6 @@ import static android.location.LocationManager.GPS_PROVIDER;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
@@ -48,13 +47,11 @@ import android.location.GnssMeasurementsEvent;
import android.location.GnssNavigationMessage;
import android.location.GnssRequest;
import android.location.GnssSingleSatCorrection;
-import android.location.IBatchedLocationCallback;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
import android.location.IGnssStatusListener;
import android.location.INetInitiatedListener;
-import android.location.Location;
import android.location.LocationManagerInternal;
import android.os.Handler;
import android.os.IBinder;
@@ -99,7 +96,6 @@ public class GnssManagerServiceTest {
@Mock private LocationManagerInternal mLocationManagerInternal;
@Mock private GnssNative.GnssNativeInitNative mGnssInitNative;
@Mock private GnssLocationProvider mMockGnssLocationProvider;
- @Mock private GnssBatchingProvider mMockGnssBatchingProvider;
@Mock private GnssLocationProvider.GnssSystemInfoProvider mMockGnssSystemInfoProvider;
@Mock private GnssCapabilitiesProvider mMockGnssCapabilitiesProvider;
@Mock private GnssMeasurementCorrectionsProvider mMockGnssMeasurementCorrectionsProvider;
@@ -148,8 +144,6 @@ public class GnssManagerServiceTest {
// Setup GnssLocationProvider to return providers
when(mMockGnssLocationProvider.getGnssStatusProvider()).thenReturn(
mTestGnssStatusProvider);
- when(mMockGnssLocationProvider.getGnssBatchingProvider()).thenReturn(
- mMockGnssBatchingProvider);
when(mMockGnssLocationProvider.getGnssCapabilitiesProvider()).thenReturn(
mMockGnssCapabilitiesProvider);
when(mMockGnssLocationProvider.getGnssSystemInfoProvider()).thenReturn(
@@ -165,10 +159,6 @@ public class GnssManagerServiceTest {
when(mMockGnssLocationProvider.getGnssAntennaInfoProvider()).thenReturn(
mTestGnssAntennaInfoProvider);
- // Setup GnssBatching provider
- when(mMockGnssBatchingProvider.start(anyLong(), anyBoolean())).thenReturn(true);
- when(mMockGnssBatchingProvider.stop()).thenReturn(true);
-
// Create GnssManagerService
mGnssManagerService = new GnssManagerService(mMockContext, mInjector,
mMockGnssLocationProvider);
@@ -204,12 +194,6 @@ public class GnssManagerServiceTest {
return mockListener;
}
- private IBatchedLocationCallback createMockBatchedLocationCallback() {
- IBatchedLocationCallback mockedCallback = mock(IBatchedLocationCallback.class);
- overrideAsBinder(mockedCallback);
- return mockedCallback;
- }
-
private IGnssNavigationMessageListener createMockGnssNavigationMessageListener() {
IGnssNavigationMessageListener mockListener = mock(IGnssNavigationMessageListener.class);
overrideAsBinder(mockListener);
@@ -359,174 +343,6 @@ public class GnssManagerServiceTest {
}
@Test
- public void getGnssBatchSizeWithoutPermissionsTest() {
- disableLocationPermissions();
-
- assertThrows(SecurityException.class,
- () -> mGnssManagerService.getGnssBatchSize());
- }
-
- @Test
- public void getGnssBatchSizeWithPermissionsTest() {
- final int gnssBatchSize = 10;
- when(mMockGnssBatchingProvider.getBatchSize()).thenReturn(gnssBatchSize);
- enableLocationPermissions();
-
- assertThat(mGnssManagerService.getGnssBatchSize()).isEqualTo(
- gnssBatchSize);
- }
-
- @Test
- public void startGnssBatchWithoutPermissionsTest() {
- final long periodNanos = 100L;
- final boolean wakeOnFifoFull = true;
-
- disableLocationPermissions();
-
- assertThrows(SecurityException.class,
- () -> mGnssManagerService.startGnssBatch(periodNanos, wakeOnFifoFull,
- TEST_PACKAGE, null));
- verify(mMockGnssBatchingProvider, times(0)).start(periodNanos, wakeOnFifoFull);
- }
-
- @Test
- public void startGnssBatchWithPermissionsTest() {
- final long periodNanos = 100L;
- final boolean wakeOnFifoFull = true;
-
- enableLocationPermissions();
-
- assertThat(mGnssManagerService.startGnssBatch(periodNanos, wakeOnFifoFull,
- TEST_PACKAGE, null))
- .isEqualTo(
- true);
- verify(mMockGnssBatchingProvider, times(1)).start(100L, true);
- }
-
- @Test
- public void addGnssBatchCallbackWithoutPermissionsTest() throws RemoteException {
- IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
- List<Location> mockLocationList = new ArrayList<>();
-
- disableLocationPermissions();
-
- assertThrows(SecurityException.class, () -> mGnssManagerService.setGnssBatchingCallback(
- mockBatchedLocationCallback, TEST_PACKAGE, null));
-
- mGnssManagerService.onReportLocation(mockLocationList);
-
- verify(mockBatchedLocationCallback, times(0)).onLocationBatch(mockLocationList);
- }
-
- @Test
- public void addGnssBatchCallbackWithPermissionsTest() throws RemoteException {
- IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
- List<Location> mockLocationList = new ArrayList<>();
-
- enableLocationPermissions();
-
- assertThat(mGnssManagerService.setGnssBatchingCallback(
- mockBatchedLocationCallback, TEST_PACKAGE, null))
- .isEqualTo(true);
-
- mGnssManagerService.onReportLocation(mockLocationList);
-
- verify(mockBatchedLocationCallback, times(1)).onLocationBatch(mockLocationList);
- }
-
- @Test
- public void replaceGnssBatchCallbackTest() throws RemoteException {
- IBatchedLocationCallback mockBatchedLocationCallback1 = createMockBatchedLocationCallback();
- IBatchedLocationCallback mockBatchedLocationCallback2 = createMockBatchedLocationCallback();
- List<Location> mockLocationList = new ArrayList<>();
-
- enableLocationPermissions();
-
- assertThat(mGnssManagerService.setGnssBatchingCallback(
- mockBatchedLocationCallback1, TEST_PACKAGE, null))
- .isEqualTo(true);
- assertThat(mGnssManagerService.setGnssBatchingCallback(
- mockBatchedLocationCallback2, TEST_PACKAGE, null))
- .isEqualTo(true);
-
- mGnssManagerService.onReportLocation(mockLocationList);
-
- verify(mockBatchedLocationCallback1, times(0)).onLocationBatch(mockLocationList);
- verify(mockBatchedLocationCallback2, times(1)).onLocationBatch(mockLocationList);
- }
-
- @Test
- public void flushGnssBatchWithoutPermissionsTest() {
- disableLocationPermissions();
-
- assertThrows(SecurityException.class,
- () -> mGnssManagerService.flushGnssBatch());
- verify(mMockGnssBatchingProvider, times(0)).flush();
- }
-
- @Test
- public void flushGnssBatchWithPermissionsTest() {
- enableLocationPermissions();
- mGnssManagerService.flushGnssBatch();
-
- verify(mMockGnssBatchingProvider, times(1)).flush();
- }
-
- @Test
- public void removeGnssBatchingCallbackWithoutPermissionsTest() throws RemoteException {
- IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
- List<Location> mockLocationList = new ArrayList<>();
-
- enableLocationPermissions();
-
- mGnssManagerService.setGnssBatchingCallback(mockBatchedLocationCallback,
- TEST_PACKAGE, null);
-
- disableLocationPermissions();
-
- assertThrows(SecurityException.class,
- () -> mGnssManagerService.removeGnssBatchingCallback());
-
- enableLocationPermissions();
- mGnssManagerService.onReportLocation(mockLocationList);
-
- verify(mockBatchedLocationCallback, times(1)).onLocationBatch(mockLocationList);
- }
-
- @Test
- public void removeGnssBatchingCallbackWithPermissionsTest() throws RemoteException {
- IBatchedLocationCallback mockBatchedLocationCallback = createMockBatchedLocationCallback();
- List<Location> mockLocationList = new ArrayList<>();
-
- enableLocationPermissions();
-
- mGnssManagerService.setGnssBatchingCallback(mockBatchedLocationCallback,
- TEST_PACKAGE, null);
-
- mGnssManagerService.removeGnssBatchingCallback();
-
- mGnssManagerService.onReportLocation(mockLocationList);
-
- verify(mockBatchedLocationCallback, times(0)).onLocationBatch(mockLocationList);
- }
-
- @Test
- public void stopGnssBatchWithoutPermissionsTest() {
- disableLocationPermissions();
-
- assertThrows(SecurityException.class, () -> mGnssManagerService.stopGnssBatch());
- verify(mMockGnssBatchingProvider, times(0)).stop();
- }
-
- @Test
- public void stopGnssBatchWithPermissionsTest() {
- enableLocationPermissions();
-
- assertThat(mGnssManagerService.stopGnssBatch()).isEqualTo(true);
- verify(mMockGnssBatchingProvider, times(1)).stop();
- }
-
- @Test
public void registerGnssStatusCallbackWithoutPermissionsTest() throws RemoteException {
final int timeToFirstFix = 20000;
IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
index 2f1a20b2cbb1..7a1a76278bcc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
@@ -34,6 +34,11 @@ public class FakeProvider extends AbstractLocationProvider {
protected void onSetRequest(ProviderRequest request) {}
@Override
+ protected void onFlush(Runnable callback) {
+ callback.run();
+ }
+
+ @Override
protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {}
@Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java b/services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java
index 5e5ed11bd0e7..c0c45e41d4b1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java
@@ -18,18 +18,17 @@ package com.android.server.location.test;
import static com.google.common.truth.Truth.assertThat;
-import android.location.Location;
+import android.location.LocationResult;
import com.android.server.location.AbstractLocationProvider;
import java.util.LinkedList;
-import java.util.List;
public class ProviderListenerCapture implements AbstractLocationProvider.Listener {
private final Object mLock;
private final LinkedList<AbstractLocationProvider.State> mNewStates = new LinkedList<>();
- private final LinkedList<Location> mLocations = new LinkedList<>();
+ private final LinkedList<LocationResult> mLocations = new LinkedList<>();
public ProviderListenerCapture(Object lock) {
mLock = lock;
@@ -47,15 +46,12 @@ public class ProviderListenerCapture implements AbstractLocationProvider.Listene
}
@Override
- public void onReportLocation(Location location) {
+ public void onReportLocation(LocationResult locationResult) {
assertThat(Thread.holdsLock(mLock)).isTrue();
- mLocations.add(location);
+ mLocations.add(locationResult);
}
- public Location getNextLocation() {
+ public LocationResult getNextLocationResult() {
return mLocations.poll();
}
-
- @Override
- public void onReportLocation(List<Location> locations) {}
}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 26fd0a21f10f..b9aa554aa0ac 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -85,6 +85,8 @@
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.ACCESS_VIBRATOR_STATE"/>
<uses-permission android:name="android.permission.VIBRATE_ALWAYS_ON"/>
+ <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE"/>
+ <uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java b/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java
index f9dd7dc86ad5..80373ac66109 100644
--- a/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java
+++ b/services/tests/servicestests/src/android/location/timezone/LocationTimeZoneEventTest.java
@@ -23,8 +23,6 @@ import static org.junit.Assert.assertNotEquals;
import static java.util.Collections.singletonList;
-import android.os.UserHandle;
-
import org.junit.Test;
import java.util.List;
@@ -35,10 +33,6 @@ public class LocationTimeZoneEventTest {
private static final List<String> ARBITRARY_TIME_ZONE_IDS = singletonList("Europe/London");
- private static final UserHandle ARBITRARY_USER_HANDLE = UserHandle.SYSTEM;
- private static final UserHandle ARBITRARY_USER_HANDLE2 =
- UserHandle.of(ARBITRARY_USER_HANDLE.getIdentifier() + 1);
-
@Test(expected = RuntimeException.class)
public void testSetInvalidEventType() {
new LocationTimeZoneEvent.Builder().setEventType(Integer.MAX_VALUE);
@@ -47,7 +41,6 @@ public class LocationTimeZoneEventTest {
@Test(expected = RuntimeException.class)
public void testBuildUnsetEventType() {
new LocationTimeZoneEvent.Builder()
- .setUserHandle(ARBITRARY_USER_HANDLE)
.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS)
.build();
@@ -56,7 +49,6 @@ public class LocationTimeZoneEventTest {
@Test(expected = RuntimeException.class)
public void testInvalidTimeZoneIds() {
new LocationTimeZoneEvent.Builder()
- .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS)
@@ -66,7 +58,6 @@ public class LocationTimeZoneEventTest {
@Test
public void testEquals() {
LocationTimeZoneEvent.Builder builder1 = new LocationTimeZoneEvent.Builder()
- .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
{
@@ -75,7 +66,6 @@ public class LocationTimeZoneEventTest {
}
LocationTimeZoneEvent.Builder builder2 = new LocationTimeZoneEvent.Builder()
- .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
{
@@ -85,22 +75,6 @@ public class LocationTimeZoneEventTest {
assertEquals(two, one);
}
- builder1.setUserHandle(ARBITRARY_USER_HANDLE2);
- {
- LocationTimeZoneEvent one = builder1.build();
- LocationTimeZoneEvent two = builder2.build();
- assertNotEquals(one, two);
- assertNotEquals(two, one);
- }
-
- builder2.setUserHandle(ARBITRARY_USER_HANDLE2);
- {
- LocationTimeZoneEvent one = builder1.build();
- LocationTimeZoneEvent two = builder2.build();
- assertEquals(one, two);
- assertEquals(two, one);
- }
-
builder1.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS + 1);
{
LocationTimeZoneEvent one = builder1.build();
@@ -153,7 +127,6 @@ public class LocationTimeZoneEventTest {
@Test
public void testParcelable() {
LocationTimeZoneEvent.Builder builder = new LocationTimeZoneEvent.Builder()
- .setUserHandle(ARBITRARY_USER_HANDLE)
.setEventType(LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE)
.setElapsedRealtimeNanos(ARBITRARY_ELAPSED_REALTIME_NANOS);
assertRoundTripParcelable(builder.build());
diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
index d5483ffa5445..83a597dfad5c 100644
--- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java
@@ -35,8 +35,8 @@ import android.os.RemoteException;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.R;
-import com.android.server.location.ComprehensiveCountryDetector;
-import com.android.server.location.CustomCountryDetectorTestClass;
+import com.android.server.location.countrydetector.ComprehensiveCountryDetector;
+import com.android.server.location.countrydetector.CustomCountryDetectorTestClass;
import com.google.common.truth.Expect;
@@ -53,7 +53,7 @@ import org.mockito.junit.MockitoJUnitRunner;
public class CountryDetectorServiceTest {
private static final String VALID_CUSTOM_TEST_CLASS =
- "com.android.server.location.CustomCountryDetectorTestClass";
+ "com.android.server.location.countrydetector.CustomCountryDetectorTestClass";
private static final String INVALID_CUSTOM_TEST_CLASS =
"com.android.server.location.MissingCountryDetectorTestClass";
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java
index 538e2d51e88f..0e787853f617 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/GestureManifoldTest.java
@@ -26,6 +26,7 @@ import android.accessibilityservice.AccessibilityService;
import android.content.Context;
import android.graphics.Point;
import android.graphics.PointF;
+import android.os.Handler;
import android.view.MotionEvent;
import androidx.test.InstrumentationRegistry;
@@ -56,7 +57,8 @@ public class GestureManifoldTest {
// Construct a testable GestureManifold.
mResultListener = mock(GestureManifold.Listener.class);
mState = new TouchState();
- mManifold = new GestureManifold(context, mResultListener, mState);
+ Handler handler = new Handler(context.getMainLooper());
+ mManifold = new GestureManifold(context, mResultListener, mState, handler);
// Play the role of touch explorer in updating the shared state.
when(mResultListener.onGestureStarted()).thenReturn(onGestureStarted());
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index dda81ffded4f..89bd625c8289 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -16,6 +16,7 @@
package com.android.server.accessibility.gestures;
+import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_HOVER_ENTER;
import static android.view.MotionEvent.ACTION_HOVER_EXIT;
@@ -33,7 +34,7 @@ import static com.android.server.accessibility.gestures.TouchState.STATE_GESTURE
import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_EXPLORING;
import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
+import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.graphics.PointF;
@@ -127,10 +128,9 @@ public class TouchExplorerTest {
mContext = InstrumentationRegistry.getContext();
mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
AccessibilityManagerService ams = new AccessibilityManagerService(mContext);
- GestureManifold detector = mock(GestureManifold.class);
mCaptor = new EventCaptor();
mHandler = new TestHandler();
- mTouchExplorer = new TouchExplorer(mContext, ams, detector, mHandler);
+ mTouchExplorer = new TouchExplorer(mContext, ams, null, mHandler);
mTouchExplorer.setNext(mCaptor);
}
@@ -174,6 +174,42 @@ public class TouchExplorerTest {
}
/**
+ * Test the case where the event location is correct when clicking after the following
+ * situation happened: entering the delegate state through doubleTapAndHold gesture and
+ * receiving a cancel event to return the clear state.
+ */
+ @Test
+ public void testClick_afterCanceledDoubleTapAndHold_eventLocationIsCorrect() {
+ // Generates the click position by this click operation, otherwise the offset used
+ // while delegating could not be set.
+ send(downEvent(DEFAULT_X + 10, DEFAULT_Y + 10));
+ // Waits for transition to touch exploring state.
+ mHandler.fastForward(2 * USER_INTENT_TIMEOUT);
+ send(upEvent());
+
+ // Simulates detecting the doubleTapAndHold gesture and enters the delegate state.
+ final MotionEvent sendEvent =
+ fromTouchscreen(downEvent(DEFAULT_X + 100, DEFAULT_Y + 100));
+ mTouchExplorer.onDoubleTapAndHold(sendEvent, sendEvent, 0);
+ assertState(STATE_DELEGATING);
+
+ send(cancelEvent());
+
+ // Generates the click operation, and checks the event location of the ACTION_HOVER_ENTER
+ // event is correct.
+ send(downEvent());
+ // Waits for transition to touch exploring state.
+ mHandler.fastForward(2 * USER_INTENT_TIMEOUT);
+ send(upEvent());
+
+ final List<MotionEvent> events = getCapturedEvents();
+ assertTrue(events.stream().anyMatch(
+ motionEvent -> motionEvent.getActionMasked() == ACTION_HOVER_ENTER
+ && motionEvent.getX() == DEFAULT_X
+ && motionEvent.getY() == DEFAULT_Y));
+ }
+
+ /**
* Test the case where ACTION_POINTER_DOWN is followed by a number of ACTION_MOVE events that do
* not change the coordinates.
*/
@@ -234,8 +270,8 @@ public class TouchExplorerTest {
// Wait for the views responding to hover enter/move events.
mHandler.fastForward(oneThirdUserIntentTimeout);
// Simulate receiving the a11y exit event sent by the first view.
- AccessibilityEvent a11yExitEvent = AccessibilityEvent.obtain(
- AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+ AccessibilityEvent a11yExitEvent =
+ AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
mTouchExplorer.onAccessibilityEvent(a11yExitEvent);
// Wait for running the hover exit event runnable. After it, touch-exploration end event
@@ -326,6 +362,39 @@ public class TouchExplorerTest {
assertCapturedEventsNoHistory();
}
+ @Test
+ public void testCanceledGesture_shouldDoNothing() {
+ mTouchExplorer.setMultiFingerGesturesEnabled(true);
+ mTouchExplorer.setTwoFingerPassthroughEnabled(true);
+ // Start a three-finger swipe.
+ send(downEvent());
+ send(pointerDownEvent());
+ send(thirdPointerDownEvent());
+ moveEachPointers(mLastEvent, p(0, 200), p(0, 200), p(0, 200));
+ send(mLastEvent);
+ assertState(STATE_GESTURE_DETECTING);
+ mHandler.fastForward(2 * (int) Swipe.MAX_TIME_TO_CONTINUE_SWIPE_MS);
+ // Lift the third finger but keep the other two going.
+ send(thirdPointerUpEvent());
+ // Manually construct the next move event. Using moveEachPointers() will batch the move
+ // event onto the pointer up event which will mean that the move event still has a pointer
+ // count of 3.
+ // Todo: refactor to avoid using batching as there is no special reason to do it that way.
+ float[] x = new float[2];
+ float[] y = new float[2];
+ x[0] = mLastEvent.getX(0) + 100;
+ x[1] = mLastEvent.getX(1) + 100;
+ y[0] = mLastEvent.getY(0) + 100;
+ y[1] = mLastEvent.getY(1) + 100;
+ send(manyPointerEvent(ACTION_MOVE, x, y));
+ // Ensure that no two-finger passthrough is being executed.
+ assertState(STATE_GESTURE_DETECTING);
+ assertNoCapturedEvents();
+ send(pointerUpEvent());
+ send(upEvent());
+ mTouchExplorer.setMultiFingerGesturesEnabled(false);
+ }
+
private static MotionEvent fromTouchscreen(MotionEvent ev) {
ev.setSource(InputDevice.SOURCE_TOUCHSCREEN);
return ev;
@@ -376,8 +445,7 @@ public class TouchExplorerTest {
throw new IllegalArgumentException("Illegal state: " + state);
}
} catch (Throwable t) {
- throw new RuntimeException(
- "Failed to go to state " + stateToString(state), t);
+ throw new RuntimeException("Failed to go to state " + stateToString(state), t);
}
}
@@ -427,6 +495,10 @@ public class TouchExplorerTest {
TouchState.getStateSymbolicName(mTouchExplorer.getState().getState()));
}
+ private void assertNoCapturedEvents() {
+ assertEquals(0, getCapturedEvents().size());
+ }
+
private void assertCapturedEvents(int... actionsInOrder) {
final int eventCount = actionsInOrder.length;
assertEquals(eventCount, getCapturedEvents().size());
@@ -449,6 +521,19 @@ public class TouchExplorerTest {
return ((EventCaptor) mCaptor).mEvents;
}
+ private MotionEvent cancelEvent() {
+ mLastDownTime = SystemClock.uptimeMillis();
+ return fromTouchscreen(
+ MotionEvent.obtain(mLastDownTime, mLastDownTime, ACTION_CANCEL,
+ DEFAULT_X, DEFAULT_Y, 0));
+ }
+
+ private MotionEvent downEvent(float x, float y) {
+ mLastDownTime = SystemClock.uptimeMillis();
+ return fromTouchscreen(
+ MotionEvent.obtain(mLastDownTime, mLastDownTime, ACTION_DOWN, x, y, 0));
+ }
+
private MotionEvent downEvent() {
mLastDownTime = SystemClock.uptimeMillis();
return fromTouchscreen(
@@ -572,8 +657,8 @@ public class TouchExplorerTest {
}
/**
- * A {@link android.os.Handler} that doesn't process messages until {@link
- * #fastForward(int)} is invoked.
+ * A {@link android.os.Handler} that doesn't process messages until {@link #fastForward(int)} is
+ * invoked.
*
* @see com.android.server.testutils.TestHandler
*/
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index e82ff344d4cc..aed590b8b7e0 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -74,11 +75,16 @@ public class MagnificationControllerTest {
private static final int MODE_FULLSCREEN =
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
- @Mock private AccessibilityManagerService mService;
- @Mock private MagnificationController.TransitionCallBack mTransitionCallBack;
- @Mock private Context mContext;
- @Mock private FullScreenMagnificationController mScreenMagnificationController;
- @Captor private ArgumentCaptor<MagnificationAnimationCallback> mCallbackArgumentCaptor;
+ @Mock
+ private AccessibilityManagerService mService;
+ @Mock
+ private MagnificationController.TransitionCallBack mTransitionCallBack;
+ @Mock
+ private Context mContext;
+ @Mock
+ private FullScreenMagnificationController mScreenMagnificationController;
+ @Captor
+ private ArgumentCaptor<MagnificationAnimationCallback> mCallbackArgumentCaptor;
private MockWindowMagnificationConnection mMockConnection;
private WindowMagnificationManager mWindowMagnificationManager;
@@ -96,7 +102,8 @@ public class MagnificationControllerTest {
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, DEFAULT_SCALE,
CURRENT_USER_ID);
mWindowMagnificationManager = Mockito.spy(
- new WindowMagnificationManager(mContext, CURRENT_USER_ID));
+ new WindowMagnificationManager(mContext, CURRENT_USER_ID,
+ mock(WindowMagnificationManager.Callback.class)));
mMockConnection = new MockWindowMagnificationConnection(true);
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mMagnificationController = new MagnificationController(mService, new Object(), mContext,
@@ -261,6 +268,19 @@ public class MagnificationControllerTest {
assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
}
+ @Test
+ public void onPerformScaleAction_magnifierEnabled_handleScaleChange() throws RemoteException {
+ final float newScale = 4.0f;
+ setMagnificationEnabled(MODE_WINDOW);
+
+ mMagnificationController.onPerformScaleAction(TEST_DISPLAY, newScale);
+
+ verify(mWindowMagnificationManager).setScale(eq(TEST_DISPLAY), eq(newScale));
+ verify(mWindowMagnificationManager).persistScale(eq(TEST_DISPLAY));
+ verify(mService).onMagnificationScaleChanged(eq(TEST_DISPLAY),
+ eq(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
+ }
+
private void setMagnificationEnabled(int mode) throws RemoteException {
setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
index a10e0ba5020c..41b6e987f819 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java
@@ -70,7 +70,8 @@ public class WindowMagnificationGestureHandlerTest {
@Before
public void setUp() throws RemoteException {
mContext = InstrumentationRegistry.getContext();
- mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0);
+ mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0,
+ mock(WindowMagnificationManager.Callback.class));
mMockConnection = new MockWindowMagnificationConnection();
mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler(
mContext, mWindowMagnificationManager, mock(ScaleChangedListener.class),
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index d5be3ede40d2..f26c86c69587 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -16,7 +16,6 @@
package com.android.server.accessibility.magnification;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
@@ -76,6 +75,8 @@ public class WindowMagnificationManagerTest {
private StatusBarManagerInternal mMockStatusBarManagerInternal;
@Mock
private MagnificationAnimationCallback mAnimationCallback;
+ @Mock
+ private WindowMagnificationManager.Callback mMockCallback;
private MockContentResolver mResolver;
private WindowMagnificationManager mWindowMagnificationManager;
@@ -86,7 +87,8 @@ public class WindowMagnificationManagerTest {
LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal);
mResolver = new MockContentResolver();
mMockConnection = new MockWindowMagnificationConnection();
- mWindowMagnificationManager = new WindowMagnificationManager(mContext, CURRENT_USER_ID);
+ mWindowMagnificationManager = new WindowMagnificationManager(mContext, CURRENT_USER_ID,
+ mMockCallback);
when(mContext.getContentResolver()).thenReturn(mResolver);
doAnswer((InvocationOnMock invocation) -> {
@@ -300,6 +302,17 @@ public class WindowMagnificationManagerTest {
}
@Test
+ public void onPerformScaleAction_magnifierEnabled_notifyAction() throws RemoteException {
+ final float newScale = 4.0f;
+ mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
+ mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, NaN, NaN);
+
+ mMockConnection.getConnectionCallback().onPerformScaleAction(TEST_DISPLAY, newScale);
+
+ verify(mMockCallback).onPerformScaleAction(eq(TEST_DISPLAY), eq(newScale));
+ }
+
+ @Test
public void binderDied_windowMagnifierIsEnabled_resetState() throws RemoteException {
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3f, NaN, NaN);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index e8c969741fc2..6b000f39aba2 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -24,12 +24,16 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.NonNull;
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustManager;
import android.content.Context;
@@ -39,6 +43,9 @@ import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
+import android.hardware.biometrics.SensorProperties;
+import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -79,7 +86,8 @@ public class AuthSessionTest {
private IBinder mToken;
// Assume all tests can be done with the same set of sensors for now.
- private List<BiometricSensor> mSensors;
+ @NonNull private List<BiometricSensor> mSensors;
+ @NonNull private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProps;
@Before
public void setUp() throws Exception {
@@ -88,11 +96,12 @@ public class AuthSessionTest {
mRandom = new Random();
mToken = new Binder();
mSensors = new ArrayList<>();
+ mFingerprintSensorProps = new ArrayList<>();
}
@Test
public void testNewAuthSession_eligibleSensorsSetToStateUnknown() throws RemoteException {
- setupFingerprint(0 /* id */);
+ setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_REAR);
setupFace(1 /* id */, false /* confirmationAlwaysRequired */);
final AuthSession session = createAuthSession(mSensors,
@@ -110,10 +119,9 @@ public class AuthSessionTest {
}
@Test
- public void testStartNewAuthSession()
- throws RemoteException {
+ public void testStartNewAuthSession() throws RemoteException {
setupFace(0 /* id */, false /* confirmationAlwaysRequired */);
- setupFingerprint(1 /* id */);
+ setupFingerprint(1 /* id */, FingerprintSensorProperties.TYPE_REAR);
final boolean requireConfirmation = true;
final long operationId = 123;
@@ -175,6 +183,60 @@ public class AuthSessionTest {
}
}
+ @Test
+ public void testUdfpsAuth_sensorStartsAfterDialogAnimationCompletes() throws RemoteException {
+ // For UDFPS-only setups, ensure that the sensor does not start auth until after the
+ // BiometricPrompt UI is finished animating. Otherwise, the UDFPS affordance will be
+ // shown before the BiometricPrompt is shown.
+ setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
+
+ final long operationId = 123;
+ final int userId = 10;
+ final int callingUid = 100;
+ final int callingPid = 1000;
+ final int callingUserId = 10000;
+
+ final AuthSession session = createAuthSession(mSensors,
+ false /* checkDevicePolicyManager */,
+ Authenticators.BIOMETRIC_STRONG,
+ operationId,
+ userId,
+ callingUid,
+ callingPid,
+ callingUserId);
+ assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size());
+
+ for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
+ assertEquals(BiometricSensor.STATE_UNKNOWN, sensor.getSensorState());
+ assertEquals(0, sensor.getCookie());
+ }
+
+ session.goToInitialState();
+
+ final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie();
+ session.onCookieReceived(cookie1);
+ for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
+ if (cookie1 == sensor.getCookie()) {
+ assertEquals(BiometricSensor.STATE_COOKIE_RETURNED, sensor.getSensorState());
+ } else {
+ assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
+ }
+ }
+ assertTrue(session.allCookiesReceived());
+
+ // UDFPS does not start even if all cookies are received
+ assertEquals(AuthSession.STATE_AUTH_STARTED, session.getState());
+ verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(),
+ anyBoolean(), anyBoolean(), anyInt(), any(), anyLong());
+
+ // Notify AuthSession that the UI is shown. Then, UDFPS sensor should be started.
+ session.onDialogAnimatedIn();
+ assertEquals(AuthSession.STATE_AUTH_STARTED_UI_SHOWING, session.getState());
+ assertEquals(BiometricSensor.STATE_AUTHENTICATING,
+ session.mPreAuthInfo.eligibleSensors.get(0).getSensorState());
+
+ }
+
private PreAuthInfo createPreAuthInfo(List<BiometricSensor> sensors, int userId,
PromptInfo promptInfo, boolean checkDevicePolicyManager) throws RemoteException {
return PreAuthInfo.create(mTrustManager,
@@ -197,11 +259,10 @@ public class AuthSessionTest {
final PreAuthInfo preAuthInfo = createPreAuthInfo(sensors, userId, promptInfo,
checkDevicePolicyManager);
-
return new AuthSession(mContext, mStatusBarService, mSysuiReceiver, mKeyStore,
mRandom, mClientDeathReceiver, preAuthInfo, mToken, operationId, userId,
mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo, callingUid,
- callingPid, callingUserId, false /* debugEnabled */);
+ callingPid, callingUserId, false /* debugEnabled */, mFingerprintSensorProps);
}
private PromptInfo createPromptInfo(@Authenticators.Types int authenticators) {
@@ -210,8 +271,8 @@ public class AuthSessionTest {
return promptInfo;
}
-
- private void setupFingerprint(int id) throws RemoteException {
+ private void setupFingerprint(int id, @FingerprintSensorProperties.SensorType int type)
+ throws RemoteException {
IBiometricAuthenticator fingerprintAuthenticator = mock(IBiometricAuthenticator.class);
when(fingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true);
when(fingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
@@ -229,6 +290,12 @@ public class AuthSessionTest {
return false; // fingerprint does not support confirmation
}
});
+
+ mFingerprintSensorProps.add(new FingerprintSensorPropertiesInternal(id,
+ SensorProperties.STRENGTH_STRONG,
+ 5 /* maxEnrollmentsPerUser */,
+ type,
+ false /* resetLockoutRequiresHardwareAuthToken */));
}
private void setupFace(int id, boolean confirmationAlwaysRequired) throws RemoteException {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 3b6059406785..435c7008ca59 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -1456,16 +1456,6 @@ public class BiometricServiceTest {
mFingerprintAuthenticator);
}
- @Test(expected = IllegalStateException.class)
- public void testRegistrationWithUnknownId_throwsIllegalStateException() throws Exception {
- mBiometricService = new BiometricService(mContext, mInjector);
- mBiometricService.onStart();
-
- mBiometricService.mImpl.registerAuthenticator(
- 100 /* id */, 2 /* modality */, 15 /* strength */,
- mFingerprintAuthenticator);
- }
-
@Test(expected = IllegalArgumentException.class)
public void testRegistrationWithNullAuthenticator_throwsIllegalArgumentException()
throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index c890c52f2181..24e7d7d19e8d 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -20,20 +20,27 @@ import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.IBiometricService;
+import android.os.Binder;
+import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.sensors.BiometricScheduler.Operation;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -44,8 +51,10 @@ import org.mockito.MockitoAnnotations;
public class BiometricSchedulerTest {
private static final String TAG = "BiometricSchedulerTest";
+ private static final int TEST_SENSOR_ID = 1;
private BiometricScheduler mScheduler;
+ private IBinder mToken;
@Mock
private Context mContext;
@@ -55,6 +64,7 @@ public class BiometricSchedulerTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mToken = new Binder();
mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */,
mBiometricService);
}
@@ -63,8 +73,8 @@ public class BiometricSchedulerTest {
public void testClientDuplicateFinish_ignoredBySchedulerAndDoesNotCrash() {
final ClientMonitor.LazyDaemon<Object> nonNullDaemon = () -> mock(Object.class);
- final ClientMonitor<Object> client1 = new TestClientMonitor(mContext, nonNullDaemon);
- final ClientMonitor<Object> client2 = new TestClientMonitor(mContext, nonNullDaemon);
+ final ClientMonitor<Object> client1 = new TestClientMonitor(mContext, mToken, nonNullDaemon);
+ final ClientMonitor<Object> client2 = new TestClientMonitor(mContext, mToken, nonNullDaemon);
mScheduler.scheduleClientMonitor(client1);
mScheduler.scheduleClientMonitor(client2);
@@ -80,8 +90,8 @@ public class BiometricSchedulerTest {
final ClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> null;
final ClientMonitor.LazyDaemon<Object> lazyDaemon2 = () -> daemon2;
- final TestClientMonitor client1 = new TestClientMonitor(mContext, lazyDaemon1);
- final TestClientMonitor client2 = new TestClientMonitor(mContext, lazyDaemon2);
+ final TestClientMonitor client1 = new TestClientMonitor(mContext, mToken, lazyDaemon1);
+ final TestClientMonitor client2 = new TestClientMonitor(mContext, mToken, lazyDaemon2);
final ClientMonitor.Callback callback1 = mock(ClientMonitor.Callback.class);
final ClientMonitor.Callback callback2 = mock(ClientMonitor.Callback.class);
@@ -110,16 +120,18 @@ public class BiometricSchedulerTest {
}
@Test
- public void testRemovesOnlyBiometricPromptOperation_whenNullHal() {
+ public void testRemovesOnlyBiometricPromptOperation_whenNullHal() throws Exception {
// Second non-BiometricPrompt client has a valid daemon
final Object daemon2 = mock(Object.class);
final ClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> null;
final ClientMonitor.LazyDaemon<Object> lazyDaemon2 = () -> daemon2;
- final TestClientMonitor client1 =
- new TestBiometricPromptClientMonitor(mContext, lazyDaemon1);
- final TestClientMonitor client2 = new TestClientMonitor(mContext, lazyDaemon2);
+ final ClientMonitorCallbackConverter listener1 = mock(ClientMonitorCallbackConverter.class);
+
+ final BiometricPromptClientMonitor client1 =
+ new BiometricPromptClientMonitor(mContext, mToken, lazyDaemon1, listener1);
+ final TestClientMonitor client2 = new TestClientMonitor(mContext, mToken, lazyDaemon2);
final ClientMonitor.Callback callback1 = mock(ClientMonitor.Callback.class);
final ClientMonitor.Callback callback2 = mock(ClientMonitor.Callback.class);
@@ -139,8 +151,10 @@ public class BiometricSchedulerTest {
// Simulate that the BiometricPrompt client's sensor is ready
mScheduler.startPreparedClient(client1.getCookie());
- assertTrue(client1.wasUnableToStart());
- verify(callback1).onClientFinished(eq(client1), eq(false) /* success */);
+ // Client 1 cleans up properly
+ verify(listener1).onError(eq(TEST_SENSOR_ID), anyInt(),
+ eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED), eq(0));
+ verify(callback1).onClientFinished(eq(client1), eq(true) /* success */);
verify(callback1, never()).onClientStarted(any());
// Client 2 was able to start
@@ -149,10 +163,45 @@ public class BiometricSchedulerTest {
verify(callback2).onClientStarted(eq(client2));
}
- private static class TestBiometricPromptClientMonitor extends TestClientMonitor {
- public TestBiometricPromptClientMonitor(@NonNull Context context,
- @NonNull LazyDaemon<Object> lazyDaemon) {
- super(context, lazyDaemon, 1 /* cookie */);
+ @Test
+ public void testCancelNotInvoked_whenOperationWaitingForCookie() {
+ final ClientMonitor.LazyDaemon<Object> lazyDaemon1 = () -> mock(Object.class);
+ final BiometricPromptClientMonitor client1 = new BiometricPromptClientMonitor(mContext,
+ mToken, lazyDaemon1, mock(ClientMonitorCallbackConverter.class));
+ final ClientMonitor.Callback callback1 = mock(ClientMonitor.Callback.class);
+
+ // Schedule a BiometricPrompt authentication request
+ mScheduler.scheduleClientMonitor(client1, callback1);
+
+ assertEquals(Operation.STATE_WAITING_FOR_COOKIE, mScheduler.mCurrentOperation.state);
+ assertEquals(client1, mScheduler.mCurrentOperation.clientMonitor);
+ assertEquals(0, mScheduler.mPendingOperations.size());
+
+ // Request it to be canceled. The operation can be canceled immediately, and the scheduler
+ // should go back to idle, since in this case the framework has not even requested the HAL
+ // to authenticate yet.
+ mScheduler.cancelAuthentication(mToken);
+ assertNull(mScheduler.mCurrentOperation);
+ }
+
+ private static class BiometricPromptClientMonitor extends AuthenticationClient<Object> {
+
+ public BiometricPromptClientMonitor(@NonNull Context context, @NonNull IBinder token,
+ @NonNull LazyDaemon<Object> lazyDaemon, ClientMonitorCallbackConverter listener) {
+ super(context, lazyDaemon, token, listener, 0 /* targetUserId */, 0 /* operationId */,
+ false /* restricted */, TAG, 1 /* cookie */, false /* requireConfirmation */,
+ TEST_SENSOR_ID, true /* isStrongBiometric */, 0 /* statsModality */,
+ 0 /* statsClient */, null /* taskStackListener */, mock(LockoutTracker.class));
+ }
+
+ @Override
+ protected void stopHalOperation() {
+
+ }
+
+ @Override
+ protected void startHalOperation() {
+
}
}
@@ -160,16 +209,15 @@ public class BiometricSchedulerTest {
private boolean mUnableToStart;
private boolean mStarted;
- public TestClientMonitor(@NonNull Context context, @NonNull LazyDaemon<Object> lazyDaemon) {
- super(context, lazyDaemon, null /* token */, null /* listener */, 0 /* userId */,
- TAG, 0 /* cookie */, 0 /* sensorId */, 0 /* statsModality */,
- 0 /* statsAction */, 0 /* statsClient */);
+ public TestClientMonitor(@NonNull Context context, @NonNull IBinder token,
+ @NonNull LazyDaemon<Object> lazyDaemon) {
+ this(context, token, lazyDaemon, 0 /* cookie */);
}
- public TestClientMonitor(@NonNull Context context, @NonNull LazyDaemon<Object> lazyDaemon,
- int cookie) {
- super(context, lazyDaemon, null /* token */, null /* listener */, 0 /* userId */,
- TAG, cookie, 0 /* sensorId */, 0 /* statsModality */,
+ public TestClientMonitor(@NonNull Context context, @NonNull IBinder token,
+ @NonNull LazyDaemon<Object> lazyDaemon, int cookie) {
+ super(context, lazyDaemon, token /* token */, null /* listener */, 0 /* userId */,
+ TAG, cookie, TEST_SENSOR_ID, 0 /* statsModality */,
0 /* statsAction */, 0 /* statsClient */);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java
index b73a783af299..35fc7f09c057 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/Face10Test.java
@@ -16,22 +16,28 @@
package com.android.server.biometrics.sensors.face;
+import static org.mockito.Mockito.when;
+
import android.content.Context;
import android.hardware.biometrics.BiometricManager;
import android.os.Binder;
import android.os.IBinder;
+import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
+import com.android.server.biometrics.sensors.face.hidl.Face10;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+
@Presubmit
@SmallTest
public class Face10Test {
@@ -41,9 +47,11 @@ public class Face10Test {
@Mock
private Context mContext;
+ @Mock
+ private UserManager mUserManager;
private LockoutResetDispatcher mLockoutResetDispatcher;
- private Face10 mFace10;
+ private com.android.server.biometrics.sensors.face.hidl.Face10 mFace10;
private IBinder mBinder;
private static void waitForIdle() {
@@ -54,6 +62,9 @@ public class Face10Test {
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ when(mUserManager.getAliveUsers()).thenReturn(new ArrayList<>());
+
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
mFace10 = new Face10(mContext, SENSOR_ID, BiometricManager.Authenticators.BIOMETRIC_STRONG,
mLockoutResetDispatcher, false /* supportsSelfIllumination */,
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 8d7bc16fcf56..c0c82d53b4f0 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -25,6 +25,7 @@ import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID;
import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
+import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
@@ -674,6 +675,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testRemoveActiveAdmin_fromDifferentUserWithINTERACT_ACROSS_USERS_FULL() {
mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
// Add admin1.
@@ -2748,6 +2750,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
// Check that the system user is unaffiliated.
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
@@ -4363,6 +4366,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testGetBindDeviceAdminTargetUsers() throws Exception {
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
+
// Setup device owner.
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -6263,6 +6268,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testGetAllCrossProfilePackages_notSet_returnsEmpty() throws Exception {
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1);
mContext.packageName = admin1.getPackageName();
@@ -6275,6 +6281,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testGetAllCrossProfilePackages_notSet_dpmsReinitialized_returnsEmpty()
throws Exception {
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1);
mContext.packageName = admin1.getPackageName();
@@ -6287,6 +6294,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testGetAllCrossProfilePackages_whenSet_returnsCombinedSet() throws Exception {
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1);
final Set<String> packages = Sets.newSet("TEST_PACKAGE", "TEST_COMMON_PACKAGE");
mContext.packageName = admin1.getPackageName();
@@ -6303,6 +6311,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testGetAllCrossProfilePackages_whenSet_dpmsReinitialized_returnsCombinedSet()
throws Exception {
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
addManagedProfile(admin1, mServiceContext.binder.callingUid, admin1);
final Set<String> packages = Sets.newSet("TEST_PACKAGE", "TEST_COMMON_PACKAGE");
mContext.packageName = admin1.getPackageName();
@@ -6483,6 +6492,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
@Test
public void testSetAccountTypesWithManagementDisabledOnOrgOwnedManagedProfile()
throws Exception {
+ mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS);
+
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
@@ -6680,6 +6691,140 @@ public class DevicePolicyManagerTest extends DpmTestBase {
.isEqualTo(DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT);
}
+ @Test
+ public void testSetRequiredPasswordComplexity_UnauthorizedCallersOnDO() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ setupDeviceOwner();
+ // DO must be able to set it.
+ dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
+ // But not on the parent DPM.
+ assertExpectException(IllegalArgumentException.class, null,
+ () -> parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW));
+ // Another package must not be allowed to set password complexity.
+ mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
+ assertExpectException(SecurityException.class, null,
+ () -> dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW));
+ }
+
+ @Test
+ public void testSetRequiredPasswordComplexity_UnauthorizedCallersOnPO() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ setupProfileOwner();
+ // PO must be able to set it.
+ dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
+ // And on the parent profile DPM instance.
+ parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
+ // Another package must not be allowed to set password complexity.
+ mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
+ assertExpectException(SecurityException.class, null,
+ () -> dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW));
+ }
+
+ @Test
+ public void testSetRequiredPasswordComplexity_validValuesOnly() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ setupProfileOwner();
+
+ // Cannot set value other than password_complexity none/low/medium/high
+ assertExpectException(IllegalArgumentException.class, null, () ->
+ dpm.setRequiredPasswordComplexity(-1));
+ assertExpectException(IllegalArgumentException.class, null, () ->
+ dpm.setRequiredPasswordComplexity(7));
+ assertExpectException(IllegalArgumentException.class, null, () ->
+ dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH + 1));
+
+ final Set<Integer> allowedModes = Set.of(PASSWORD_COMPLEXITY_NONE, PASSWORD_COMPLEXITY_LOW,
+ PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_COMPLEXITY_HIGH);
+ for (int complexity : allowedModes) {
+ // Ensure exception is not thrown.
+ dpm.setRequiredPasswordComplexity(complexity);
+ }
+ }
+
+ @Test
+ public void testSetRequiredPasswordComplexity_setAndGet() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ setupProfileOwner();
+
+ final Set<Integer> allowedModes = Set.of(PASSWORD_COMPLEXITY_NONE, PASSWORD_COMPLEXITY_LOW,
+ PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_COMPLEXITY_HIGH);
+ for (int complexity : allowedModes) {
+ dpm.setRequiredPasswordComplexity(complexity);
+ assertThat(dpm.getRequiredPasswordComplexity()).isEqualTo(complexity);
+ }
+ }
+
+ @Test
+ public void testSetRequiredPasswordComplexityOnParent_setAndGet() throws Exception {
+ final int managedProfileUserId = 15;
+ final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
+
+ addManagedProfile(admin1, managedProfileAdminUid, admin1);
+ mContext.binder.callingUid = managedProfileAdminUid;
+
+ final Set<Integer> allowedModes = Set.of(PASSWORD_COMPLEXITY_NONE, PASSWORD_COMPLEXITY_LOW,
+ PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_COMPLEXITY_HIGH);
+ for (int complexity : allowedModes) {
+ dpm.getParentProfileInstance(admin1).setRequiredPasswordComplexity(complexity);
+ assertThat(dpm.getParentProfileInstance(admin1).getRequiredPasswordComplexity())
+ .isEqualTo(complexity);
+ assertThat(dpm.getRequiredPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE);
+ }
+ }
+
+ @Test
+ public void testSetRequiredPasswordComplexity_isSufficient() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ mContext.packageName = admin1.getPackageName();
+ setupDeviceOwner();
+
+ dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
+ assertThat(dpm.getRequiredPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
+ when(getServices().packageManager.getPackagesForUid(
+ DpmMockContext.CALLER_SYSTEM_USER_UID)).thenReturn(new String[0]);
+ mServiceContext.permissions.add(permission.REQUEST_PASSWORD_COMPLEXITY);
+ assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE);
+
+ reset(mContext.spiedContext);
+ PasswordMetrics passwordMetricsNoSymbols = computeForPassword("1234".getBytes());
+ setActivePasswordState(passwordMetricsNoSymbols);
+ assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_LOW);
+ assertThat(dpm.isActivePasswordSufficient()).isFalse();
+
+ reset(mContext.spiedContext);
+ passwordMetricsNoSymbols = computeForPassword("84125312943a".getBytes());
+ setActivePasswordState(passwordMetricsNoSymbols);
+ assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
+ // using isActivePasswordSufficient
+ assertThat(dpm.isActivePasswordSufficient()).isTrue();
+ }
+
+ @Test
+ public void testSetRequiredPasswordComplexity_resetBySettingQuality() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ setupProfileOwner();
+
+ // Test that calling setPasswordQuality resets complexity to none.
+ dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
+ assertThat(dpm.getRequiredPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
+ dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
+ assertThat(dpm.getRequiredPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE);
+ }
+
+ @Test
+ public void testSetRequiredPasswordComplexity_overridesQuality() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ setupProfileOwner();
+
+ // Test that calling setRequiredPasswordComplexity resets password quality.
+ dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
+ assertThat(dpm.getPasswordQuality(admin1)).isEqualTo(
+ DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
+ dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
+ assertThat(dpm.getPasswordQuality(admin1)).isEqualTo(
+ DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+ }
+
private void setUserUnlocked(int userHandle, boolean unlocked) {
when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index 9b182a71f419..95aac60f65ff 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -19,8 +19,13 @@ package com.android.server.devicestate;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertThrows;
+import android.hardware.devicestate.IDeviceStateManagerCallback;
+import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -28,11 +33,14 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import javax.annotation.Nullable;
+
/**
* Unit tests for {@link DeviceStateManagerService}.
* <p/>
* Run with <code>atest DeviceStateManagerServiceTest</code>.
*/
+@Presubmit
@RunWith(AndroidJUnit4.class)
public final class DeviceStateManagerServiceTest {
private static final int DEFAULT_DEVICE_STATE = 0;
@@ -48,7 +56,6 @@ public final class DeviceStateManagerServiceTest {
mProvider = new TestDeviceStateProvider();
mPolicy = new TestDeviceStatePolicy(mProvider);
mService = new DeviceStateManagerService(InstrumentationRegistry.getContext(), mPolicy);
- mService.onStart();
}
@Test
@@ -187,6 +194,38 @@ public final class DeviceStateManagerServiceTest {
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE);
}
+ @Test
+ public void registerCallback() throws RemoteException {
+ TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ mService.getBinderService().registerCallback(callback);
+
+ mProvider.notifyRequestState(OTHER_DEVICE_STATE);
+ assertNotNull(callback.getLastNotifiedValue());
+ assertEquals(callback.getLastNotifiedValue().intValue(), OTHER_DEVICE_STATE);
+
+ mProvider.notifyRequestState(DEFAULT_DEVICE_STATE);
+ assertEquals(callback.getLastNotifiedValue().intValue(), DEFAULT_DEVICE_STATE);
+
+ mPolicy.blockConfigure();
+ mProvider.notifyRequestState(OTHER_DEVICE_STATE);
+ // The callback should not have been notified of the state change as the policy is still
+ // pending callback.
+ assertEquals(callback.getLastNotifiedValue().intValue(), DEFAULT_DEVICE_STATE);
+
+ mPolicy.resumeConfigure();
+ // Now that the policy is finished processing the callback should be notified of the state
+ // change.
+ assertEquals(callback.getLastNotifiedValue().intValue(), OTHER_DEVICE_STATE);
+ }
+
+ @Test
+ public void registerCallback_emitsInitialValue() throws RemoteException {
+ TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ mService.getBinderService().registerCallback(callback);
+ assertNotNull(callback.getLastNotifiedValue());
+ assertEquals(callback.getLastNotifiedValue().intValue(), DEFAULT_DEVICE_STATE);
+ }
+
private static final class TestDeviceStatePolicy implements DeviceStatePolicy {
private final DeviceStateProvider mProvider;
private int mLastDeviceStateRequestedToConfigure = INVALID_DEVICE_STATE;
@@ -262,4 +301,19 @@ public final class DeviceStateManagerServiceTest {
mListener.onStateChanged(state);
}
}
+
+ private static final class TestDeviceStateManagerCallback extends
+ IDeviceStateManagerCallback.Stub {
+ Integer mLastNotifiedValue;
+
+ @Override
+ public void onDeviceStateChanged(int deviceState) {
+ mLastNotifiedValue = deviceState;
+ }
+
+ @Nullable
+ Integer getLastNotifiedValue() {
+ return mLastNotifiedValue;
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 13b019897600..026db42d4d7a 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -460,6 +460,7 @@ public class DisplayManagerServiceTest {
* Tests that collection of display color sampling results are sensible.
*/
@Test
+ @FlakyTest(bugId = 172555744)
public void testDisplayedContentSampling() {
DisplayManagerService displayManager =
new DisplayManagerService(mContext, mShortMockedInjector);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index 8af7332e24ed..6debc893ea1b 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -74,6 +74,8 @@ public class ActiveSourceActionTest {
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
+ HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
+
mHdmiControlService = new HdmiControlService(mContextSpy) {
@Override
AudioManager getAudioManager() {
@@ -104,6 +106,11 @@ public class ActiveSourceActionTest {
void writeStringSystemProperty(String key, String value) {
// do nothing
}
+
+ @Override
+ HdmiCecConfig getHdmiCecConfig() {
+ return hdmiCecConfig;
+ }
};
Looper looper = mTestLooper.getLooper();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index 37a75e3822aa..a19336eeb5ea 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -76,6 +76,8 @@ public class ArcInitiationActionFromAvrTest {
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
+ HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
+
HdmiControlService hdmiControlService =
new HdmiControlService(mContextSpy) {
@Override
@@ -106,6 +108,11 @@ public class ArcInitiationActionFromAvrTest {
Looper getServiceLooper() {
return mTestLooper.getLooper();
}
+
+ @Override
+ HdmiCecConfig getHdmiCecConfig() {
+ return hdmiCecConfig;
+ }
};
mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index 6027c3e4eeab..cd6977524943 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -77,6 +77,8 @@ public class ArcTerminationActionFromAvrTest {
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
+ HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
+
HdmiControlService hdmiControlService =
new HdmiControlService(mContextSpy) {
@Override
@@ -107,6 +109,11 @@ public class ArcTerminationActionFromAvrTest {
Looper getServiceLooper() {
return mTestLooper.getLooper();
}
+
+ @Override
+ HdmiCecConfig getHdmiCecConfig() {
+ return hdmiCecConfig;
+ }
};
Looper looper = mTestLooper.getLooper();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
new file mode 100644
index 000000000000..52899faf0ed7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -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.server.hdmi;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.util.Slog;
+
+import com.android.server.hdmi.cec.config.CecSettings;
+import com.android.server.hdmi.cec.config.XmlParser;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+
+/**
+ * Fake class which loads default system configuration with user-configurable
+ * settings (useful for testing).
+ */
+final class FakeHdmiCecConfig extends HdmiCecConfig {
+ private static final String TAG = "FakeHdmiCecConfig";
+
+ private static final String SYSTEM_CONFIG_XML =
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value string-value=\"to_tv\" />"
+ + " <value string-value=\"broadcast\" />"
+ + " <value string-value=\"none\" />"
+ + " </allowed-values>"
+ + " <default-value string-value=\"to_tv\" />"
+ + " </setting>"
+ + " <setting name=\"hdmi_cec_version\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0x05\" />"
+ + " <value int-value=\"0x06\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"0x05\" />"
+ + " </setting>"
+ + "</cec-settings>";
+
+ FakeHdmiCecConfig(@NonNull Context context) {
+ super(context, new StorageAdapter(), parseFromString(SYSTEM_CONFIG_XML), null);
+ }
+
+ private static CecSettings parseFromString(@NonNull String configXml) {
+ CecSettings config = null;
+ try {
+ config = XmlParser.read(
+ new ByteArrayInputStream(configXml.getBytes()));
+ } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
+ Slog.e(TAG, "Encountered an error while reading/parsing CEC config strings", e);
+ }
+ return config;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index ae9c6188619f..dd74f22c78b7 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -17,6 +17,8 @@ package com.android.server.hdmi;
import static com.google.common.truth.Truth.assertThat;
+import static junit.framework.Assert.assertTrue;
+
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
@@ -77,14 +79,16 @@ public final class HdmiCecConfigTest {
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
- + " <value string-value=\"0\" />"
- + " <value string-value=\"1\" />"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ " </allowed-values>"
- + " <default-value string-value=\"1\" />"
+ + " <default-value int-value=\"1\" />"
+ " </setting>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"false\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -123,14 +127,16 @@ public final class HdmiCecConfigTest {
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
- + " <value string-value=\"0\" />"
- + " <value string-value=\"1\" />"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ " </allowed-values>"
- + " <default-value string-value=\"1\" />"
+ + " <default-value int-value=\"1\" />"
+ " </setting>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -152,14 +158,16 @@ public final class HdmiCecConfigTest {
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
- + " <value string-value=\"0\" />"
- + " <value string-value=\"1\" />"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ " </allowed-values>"
- + " <default-value string-value=\"1\" />"
+ + " <default-value int-value=\"1\" />"
+ " </setting>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -172,6 +180,7 @@ public final class HdmiCecConfigTest {
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"false\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -186,31 +195,132 @@ public final class HdmiCecConfigTest {
}
@Test
- public void getAllowedValues_NoMasterXml() {
+ public void isStringValueType_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.isStringValueType("foo"));
+ }
+
+ @Test
+ public void isStringValueType_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.isStringValueType("foo"));
+ }
+
+ @Test
+ public void isStringValueType_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value string-value=\"to_tv\" />"
+ + " <value string-value=\"broadcast\" />"
+ + " <value string-value=\"none\" />"
+ + " </allowed-values>"
+ + " <default-value string-value=\"to_tv\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertTrue(hdmiCecConfig.isStringValueType(
+ HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
+ }
+
+ @Test
+ public void isIntValueType_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.isIntValueType("foo"));
+ }
+
+ @Test
+ public void isIntValueType_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.isIntValueType("foo"));
+ }
+
+ @Test
+ public void isIntValueType_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertTrue(hdmiCecConfig.isIntValueType(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
+ }
+
+ @Test
+ public void getAllowedStringValues_NoMasterXml() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter, null, null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getAllowedValues("foo"));
+ () -> hdmiCecConfig.getAllowedStringValues("foo"));
}
@Test
- public void getAllowedValues_InvalidSetting() {
+ public void getAllowedStringValues_InvalidSetting() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getAllowedValues("foo"));
+ () -> hdmiCecConfig.getAllowedStringValues("foo"));
}
@Test
- public void getAllowedValues_BasicSanity() {
+ public void getAllowedStringValues_InvalidValueType() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getAllowedStringValues(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
+ }
+
+ @Test
+ public void getAllowedStringValues_BasicSanity() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -220,7 +330,7 @@ public final class HdmiCecConfigTest {
+ " <default-value string-value=\"to_tv\" />"
+ " </setting>"
+ "</cec-settings>", null);
- assertThat(hdmiCecConfig.getAllowedValues(
+ assertThat(hdmiCecConfig.getAllowedStringValues(
HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP))
.containsExactly(HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST,
@@ -228,31 +338,32 @@ public final class HdmiCecConfigTest {
}
@Test
- public void getDefaultValue_NoMasterXml() {
+ public void getAllowedIntValues_NoMasterXml() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter, null, null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getDefaultValue("foo"));
+ () -> hdmiCecConfig.getAllowedIntValues("foo"));
}
@Test
- public void getDefaultValue_InvalidSetting() {
+ public void getAllowedIntValues_InvalidSetting() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getDefaultValue("foo"));
+ () -> hdmiCecConfig.getAllowedIntValues("foo"));
}
@Test
- public void getDefaultValue_BasicSanity() {
+ public void getAllowedIntValues_InvalidValueType() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -262,32 +373,242 @@ public final class HdmiCecConfigTest {
+ " <default-value string-value=\"to_tv\" />"
+ " </setting>"
+ "</cec-settings>", null);
- assertThat(hdmiCecConfig.getDefaultValue(
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getAllowedIntValues(
+ HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
+ }
+
+ @Test
+ public void getAllowedIntValues_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getAllowedIntValues(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
+ .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ }
+
+ @Test
+ public void getAllowedIntValues_HexValues() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0x00\" />"
+ + " <value int-value=\"0x01\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"0x01\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getAllowedIntValues(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
+ .containsExactly(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ }
+
+ @Test
+ public void getDefaultStringValue_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getDefaultStringValue("foo"));
+ }
+
+ @Test
+ public void getDefaultStringValue_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getDefaultStringValue("foo"));
+ }
+
+ @Test
+ public void getDefaultStringValue_InvalidValueType() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getDefaultStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
+ }
+
+ @Test
+ public void getDefaultStringValue_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value string-value=\"to_tv\" />"
+ + " <value string-value=\"broadcast\" />"
+ + " <value string-value=\"none\" />"
+ + " </allowed-values>"
+ + " <default-value string-value=\"to_tv\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getDefaultStringValue(
HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP))
.isEqualTo(HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
}
@Test
- public void getValue_NoMasterXml() {
+ public void getDefaultIntValue_NoMasterXml() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter, null, null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getValue("foo"));
+ () -> hdmiCecConfig.getDefaultIntValue("foo"));
}
@Test
- public void getValue_InvalidSetting() {
+ public void getDefaultIntValue_InvalidSetting() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.getValue("foo"));
+ () -> hdmiCecConfig.getDefaultIntValue("foo"));
+ }
+
+ @Test
+ public void getDefaultIntValue_InvalidValueType() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value string-value=\"to_tv\" />"
+ + " <value string-value=\"broadcast\" />"
+ + " <value string-value=\"none\" />"
+ + " </allowed-values>"
+ + " <default-value string-value=\"to_tv\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getDefaultIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
}
@Test
- public void getValue_GlobalSetting_BasicSanity() {
+ public void getDefaultIntValue_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getDefaultIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
+ .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ }
+
+ @Test
+ public void getDefaultIntValue_HexValue() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0x00\" />"
+ + " <value int-value=\"0x01\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"0x01\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getDefaultIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
+ .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ }
+
+ @Test
+ public void getStringValue_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getStringValue("foo"));
+ }
+
+ @Test
+ public void getStringValue_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getStringValue("foo"));
+ }
+
+ @Test
+ public void getStringValue_InvalidType() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
+ }
+
+ @Test
+ public void getStringValue_GlobalSetting_BasicSanity() {
when(mStorageAdapter.retrieveGlobalSetting(mContext,
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV))
@@ -297,6 +618,7 @@ public final class HdmiCecConfigTest {
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -306,13 +628,13 @@ public final class HdmiCecConfigTest {
+ " <default-value string-value=\"to_tv\" />"
+ " </setting>"
+ "</cec-settings>", null);
- assertThat(hdmiCecConfig.getValue(
+ assertThat(hdmiCecConfig.getStringValue(
HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP))
.isEqualTo(HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
}
@Test
- public void getValue_SystemProperty_BasicSanity() {
+ public void getStringValue_SystemProperty_BasicSanity() {
when(mStorageAdapter.retrieveSystemProperty(
HdmiCecConfig.SYSPROP_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
HdmiProperties.power_state_change_on_active_source_lost_values
@@ -324,6 +646,7 @@ public final class HdmiCecConfigTest {
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"power_state_change_on_active_source_lost\""
+ + " value-type=\"string\""
+ " user-configurable=\"false\">"
+ " <allowed-values>"
+ " <value string-value=\"none\" />"
@@ -332,38 +655,155 @@ public final class HdmiCecConfigTest {
+ " <default-value string-value=\"none\" />"
+ " </setting>"
+ "</cec-settings>", null);
- assertThat(hdmiCecConfig.getValue(
+ assertThat(hdmiCecConfig.getStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST))
.isEqualTo(HdmiProperties.power_state_change_on_active_source_lost_values
.STANDBY_NOW.name().toLowerCase());
}
@Test
- public void setValue_NoMasterXml() {
+ public void getIntValue_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getIntValue("foo"));
+ }
+
+ @Test
+ public void getIntValue_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getIntValue("foo"));
+ }
+
+ @Test
+ public void getIntValue_InvalidType() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value string-value=\"to_tv\" />"
+ + " <value string-value=\"broadcast\" />"
+ + " <value string-value=\"none\" />"
+ + " </allowed-values>"
+ + " <default-value string-value=\"to_tv\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP));
+ }
+
+ @Test
+ public void getIntValue_GlobalSetting_BasicSanity() {
+ when(mStorageAdapter.retrieveGlobalSetting(mContext,
+ Global.HDMI_CONTROL_ENABLED,
+ Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED)))
+ .thenReturn(Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
+ .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ }
+
+ @Test
+ public void getIntValue_GlobalSetting_HexValue() {
+ when(mStorageAdapter.retrieveGlobalSetting(mContext,
+ Global.HDMI_CONTROL_ENABLED,
+ Integer.toHexString(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED)))
+ .thenReturn(Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0x0\" />"
+ + " <value int-value=\"0x1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"0x1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED))
+ .isEqualTo(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ }
+
+ @Test
+ public void getIntValue_SystemProperty_BasicSanity() {
+ when(mStorageAdapter.retrieveSystemProperty(
+ HdmiCecConfig.SYSPROP_SYSTEM_AUDIO_MODE_MUTING,
+ Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_ENABLED)))
+ .thenReturn(Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED));
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"system_audio_mode_muting\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThat(hdmiCecConfig.getIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING))
+ .isEqualTo(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
+ }
+
+ @Test
+ public void setStringValue_NoMasterXml() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter, null, null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setValue("foo", "bar"));
+ () -> hdmiCecConfig.setStringValue("foo", "bar"));
}
@Test
- public void setValue_InvalidSetting() {
+ public void setStringValue_InvalidSetting() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setValue("foo", "bar"));
+ () -> hdmiCecConfig.setStringValue("foo", "bar"));
}
@Test
- public void setValue_NotConfigurable() {
+ public void setStringValue_NotConfigurable() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"false\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -374,18 +814,19 @@ public final class HdmiCecConfigTest {
+ " </setting>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setValue(
+ () -> hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST));
}
@Test
- public void setValue_InvalidValue() {
+ public void setStringValue_InvalidValue() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -396,18 +837,19 @@ public final class HdmiCecConfigTest {
+ " </setting>"
+ "</cec-settings>", null);
assertThrows(IllegalArgumentException.class,
- () -> hdmiCecConfig.setValue(
+ () -> hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
"bar"));
}
@Test
- public void setValue_GlobalSetting_BasicSanity() {
+ public void setStringValue_GlobalSetting_BasicSanity() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"send_standby_on_sleep\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"to_tv\" />"
@@ -417,7 +859,7 @@ public final class HdmiCecConfigTest {
+ " <default-value string-value=\"to_tv\" />"
+ " </setting>"
+ "</cec-settings>", null);
- hdmiCecConfig.setValue(HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
+ hdmiCecConfig.setStringValue(HdmiControlManager.CEC_SETTING_NAME_SEND_STANDBY_ON_SLEEP,
HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
verify(mStorageAdapter).storeGlobalSetting(mContext,
Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
@@ -425,12 +867,13 @@ public final class HdmiCecConfigTest {
}
@Test
- public void setValue_SystemProperty_BasicSanity() {
+ public void setStringValue_SystemProperty_BasicSanity() {
HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
mContext, mStorageAdapter,
"<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ "<cec-settings>"
+ " <setting name=\"power_state_change_on_active_source_lost\""
+ + " value-type=\"string\""
+ " user-configurable=\"true\">"
+ " <allowed-values>"
+ " <value string-value=\"none\" />"
@@ -439,7 +882,7 @@ public final class HdmiCecConfigTest {
+ " <default-value string-value=\"none\" />"
+ " </setting>"
+ "</cec-settings>", null);
- hdmiCecConfig.setValue(
+ hdmiCecConfig.setStringValue(
HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
HdmiProperties.power_state_change_on_active_source_lost_values
.STANDBY_NOW.name().toLowerCase());
@@ -448,4 +891,137 @@ public final class HdmiCecConfigTest {
HdmiProperties.power_state_change_on_active_source_lost_values
.STANDBY_NOW.name().toLowerCase());
}
+
+ @Test
+ public void setIntValue_NoMasterXml() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter, null, null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.setIntValue("foo", 0));
+ }
+
+ @Test
+ public void setIntValue_InvalidSetting() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.setIntValue("foo", 0));
+ }
+
+ @Test
+ public void setIntValue_NotConfigurable() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"false\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
+ }
+
+ @Test
+ public void setIntValue_InvalidValue() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ assertThrows(IllegalArgumentException.class,
+ () -> hdmiCecConfig.setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ 123));
+ }
+
+ @Test
+ public void setIntValue_GlobalSetting_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ hdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ verify(mStorageAdapter).storeGlobalSetting(mContext,
+ Global.HDMI_CONTROL_ENABLED,
+ Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
+ }
+
+ @Test
+ public void setIntValue_GlobalSetting_HexValue() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"hdmi_cec_enabled\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0x0\" />"
+ + " <value int-value=\"0x1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"0x1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ hdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+ verify(mStorageAdapter).storeGlobalSetting(mContext,
+ Global.HDMI_CONTROL_ENABLED,
+ Integer.toString(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED));
+ }
+
+ @Test
+ public void setIntValue_SystemProperty_BasicSanity() {
+ HdmiCecConfig hdmiCecConfig = HdmiCecConfig.createFromStrings(
+ mContext, mStorageAdapter,
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
+ + "<cec-settings>"
+ + " <setting name=\"system_audio_mode_muting\""
+ + " value-type=\"int\""
+ + " user-configurable=\"true\">"
+ + " <allowed-values>"
+ + " <value int-value=\"0\" />"
+ + " <value int-value=\"1\" />"
+ + " </allowed-values>"
+ + " <default-value int-value=\"1\" />"
+ + " </setting>"
+ + "</cec-settings>", null);
+ hdmiCecConfig.setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
+ HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED);
+ verify(mStorageAdapter).storeSystemProperty(
+ HdmiCecConfig.SYSPROP_SYSTEM_AUDIO_MODE_MUTING,
+ Integer.toString(HdmiControlManager.SYSTEM_AUDIO_MODE_MUTING_DISABLED));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index 81c3be5f9f75..0a3d545da0a9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -32,6 +32,7 @@ import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
import static junit.framework.Assert.assertEquals;
import android.content.Context;
+import android.hardware.hdmi.HdmiControlManager;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.Looper;
import android.os.test.TestLooper;
@@ -78,7 +79,7 @@ public class HdmiCecControllerTest {
}
private HdmiCecController mHdmiCecController;
- private int mCecVersion = Constants.VERSION_1_4;
+ private int mCecVersion = HdmiControlManager.HDMI_CEC_VERSION_1_4_b;
private int mLogicalAddress = 16;
private AllocateAddressCallback mCallback =
new AllocateAddressCallback() {
@@ -202,7 +203,7 @@ public class HdmiCecControllerTest {
@Test
public void testAllocateLogicalAddress_PlaybackNonPreferred_2_0_BackupOne() {
- mCecVersion = Constants.VERSION_2_0;
+ mCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS);
@@ -214,7 +215,7 @@ public class HdmiCecControllerTest {
@Test
public void testAllocateLogicalAddress_PlaybackNonPreferred_2_0_BackupTwo() {
- mCecVersion = Constants.VERSION_2_0;
+ mCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS);
@@ -245,7 +246,7 @@ public class HdmiCecControllerTest {
@Test
public void testAllocateLogicalAddress_PlaybackNonPreferred_2_0_AllOccupied() {
- mCecVersion = Constants.VERSION_2_0;
+ mCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0;
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 433f6e7938e2..25530940e964 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -96,6 +96,9 @@ public class HdmiCecLocalDeviceAudioSystemTest {
mMyLooper = mTestLooper.getLooper();
PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
mIThermalServiceMock, new Handler(mMyLooper));
+
+ HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
+
mHdmiControlService =
new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@Override
@@ -184,6 +187,11 @@ public class HdmiCecLocalDeviceAudioSystemTest {
PowerManager getPowerManager() {
return powerManager;
}
+
+ @Override
+ HdmiCecConfig getHdmiCecConfig() {
+ return hdmiCecConfig;
+ }
};
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 440befcb3368..9646b5d2ec2c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.hdmi.IHdmiControlCallback;
import android.os.Handler;
@@ -68,8 +69,10 @@ public class HdmiCecLocalDevicePlaybackTest {
private boolean mWokenUp;
private boolean mStandby;
- @Mock private IPowerManager mIPowerManagerMock;
- @Mock private IThermalService mIThermalServiceMock;
+ @Mock
+ private IPowerManager mIPowerManagerMock;
+ @Mock
+ private IThermalService mIThermalServiceMock;
@Before
public void setUp() {
@@ -79,41 +82,48 @@ public class HdmiCecLocalDevicePlaybackTest {
mMyLooper = mTestLooper.getLooper();
PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
mIThermalServiceMock, new Handler(mMyLooper));
- mHdmiControlService =
- new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
- @Override
- void wakeUp() {
- mWokenUp = true;
- }
-
- @Override
- void standby() {
- mStandby = true;
- }
-
- @Override
- boolean isControlEnabled() {
- return true;
- }
-
- @Override
- boolean isPlaybackDevice() {
- return true;
- }
+ HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
- @Override
- void writeStringSystemProperty(String key, String value) {
- // do nothing
- }
+ mHdmiControlService =
+ new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+ @Override
+ void wakeUp() {
+ mWokenUp = true;
+ }
+
+ @Override
+ void standby() {
+ mStandby = true;
+ }
+
+ @Override
+ boolean isControlEnabled() {
+ return true;
+ }
+
+ @Override
+ boolean isPlaybackDevice() {
+ return true;
+ }
+
+ @Override
+ void writeStringSystemProperty(String key, String value) {
+ // do nothing
+ }
+
+ @Override
+ boolean isPowerStandby() {
+ return false;
+ }
@Override
- boolean isPowerStandby() {
- return false;
+ PowerManager getPowerManager() {
+ return powerManager;
}
@Override
- PowerManager getPowerManager() {
- return powerManager;
+ HdmiCecConfig getHdmiCecConfig() {
+ return hdmiCecConfig;
}
};
@@ -229,8 +239,8 @@ public class HdmiCecLocalDevicePlaybackTest {
public void handleRoutingChange_WakeUpAndSendActiveSource() {
mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
HdmiProperties
- .playback_device_action_on_routing_control_values
- .WAKE_UP_AND_SEND_ACTIVE_SOURCE;
+ .playback_device_action_on_routing_control_values
+ .WAKE_UP_AND_SEND_ACTIVE_SOURCE;
mWokenUp = false;
@@ -252,8 +262,8 @@ public class HdmiCecLocalDevicePlaybackTest {
public void handleRoutingInformation_WakeUpAndSendActiveSource() {
mHdmiCecLocalDevicePlayback.mPlaybackDeviceActionOnRoutingControl =
HdmiProperties
- .playback_device_action_on_routing_control_values
- .WAKE_UP_AND_SEND_ACTIVE_SOURCE;
+ .playback_device_action_on_routing_control_values
+ .WAKE_UP_AND_SEND_ACTIVE_SOURCE;
mWokenUp = false;
@@ -645,12 +655,97 @@ public class HdmiCecLocalDevicePlaybackTest {
}
@Test
+ public void handleOnInitializeCecComplete_ByEnableCec() {
+ mHdmiCecLocalDevicePlayback.onInitializeCecComplete(
+ mHdmiControlService.INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(mPlaybackLogicalAddress,
+ ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
+ }
+
+ @Test
+ public void handleOnInitializeCecComplete_ByBootUp() {
+ mHdmiCecLocalDevicePlayback.onInitializeCecComplete(
+ mHdmiControlService.INITIATED_BY_BOOT_UP);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(mPlaybackLogicalAddress,
+ ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
+ }
+
+ @Test
+ public void handleOnInitializeCecComplete_ByScreenOn() {
+ mHdmiCecLocalDevicePlayback.onInitializeCecComplete(
+ mHdmiControlService.INITIATED_BY_SCREEN_ON);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(mPlaybackLogicalAddress,
+ ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
+ }
+
+ @Test
+ public void handleOnInitializeCecComplete_ByWakeUpMessage() {
+ mHdmiCecLocalDevicePlayback.onInitializeCecComplete(
+ mHdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(mPlaybackLogicalAddress,
+ ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
+ }
+
+ @Test
+ public void handleOnInitializeCecComplete_ByHotplug() {
+ mHdmiCecLocalDevicePlayback.onInitializeCecComplete(
+ mHdmiControlService.INITIATED_BY_HOTPLUG);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage activeSource =
+ HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress);
+ HdmiCecMessage textViewOn =
+ HdmiCecMessageBuilder.buildTextViewOn(mPlaybackLogicalAddress,
+ ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(textViewOn);
+ }
+
+ @Test
public void handleActiveSource_ActiveSource_None() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+ HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
mStandby = false;
HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
- mPlaybackPhysicalAddress);
+ mPlaybackPhysicalAddress);
assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
mTestLooper.dispatchAll();
assertThat(mStandby).isFalse();
@@ -664,7 +759,7 @@ public class HdmiCecLocalDevicePlaybackTest {
@Test
public void handleActiveSource_notActiveSource_None() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
+ HdmiProperties.power_state_change_on_active_source_lost_values.NONE;
mStandby = false;
HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
@@ -680,10 +775,10 @@ public class HdmiCecLocalDevicePlaybackTest {
@Test
public void handleActiveSource_ActiveSource_StandbyNow() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+ HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
mStandby = false;
HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress,
- mPlaybackPhysicalAddress);
+ mPlaybackPhysicalAddress);
assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
mTestLooper.dispatchAll();
assertThat(mStandby).isFalse();
@@ -693,7 +788,7 @@ public class HdmiCecLocalDevicePlaybackTest {
@Test
public void handleActiveSource_notActiveSource_StandbyNow() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+ HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
mStandby = false;
HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue();
@@ -951,7 +1046,7 @@ public class HdmiCecLocalDevicePlaybackTest {
@Test
public void handleSetStreamPath_otherDevice_StandbyNow() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+ HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
mStandby = false;
@@ -965,7 +1060,7 @@ public class HdmiCecLocalDevicePlaybackTest {
@Test
public void handleSetStreamPath_otherDevice_StandbyNow_InactiveSource() {
mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost =
- HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
+ HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW;
mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000,
"HdmiCecLocalDevicePlaybackTest");
mStandby = false;
@@ -1044,4 +1139,46 @@ public class HdmiCecLocalDevicePlaybackTest {
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(systemAudioModeRequest);
}
+
+ @Test
+ public void getActiveSource_noActiveSource() {
+ mHdmiControlService.setActiveSource(Constants.ADDR_UNREGISTERED,
+ Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getActiveSource()).isNull();
+ }
+
+ @Test
+ public void getActiveSource_localPlaybackIsActiveSource() {
+ mHdmiControlService.setActiveSource(mHdmiCecLocalDevicePlayback.mAddress,
+ mHdmiControlService.getPhysicalAddress(), "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getActiveSource()).isEqualTo(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo());
+ }
+
+ @Test
+ public void getActiveSource_deviceInNetworkIsActiveSource() {
+ HdmiDeviceInfo externalDevice = new HdmiDeviceInfo(Constants.ADDR_PLAYBACK_3, 0x3000, 0,
+ Constants.ADDR_PLAYBACK_1, 0, "Test Device");
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(externalDevice);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlService.setActiveSource(externalDevice.getLogicalAddress(),
+ externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getActiveSource()).isEqualTo(externalDevice);
+ }
+
+ @Test
+ public void getActiveSource_unknownDeviceIsActiveSource() {
+ HdmiDeviceInfo externalDevice = new HdmiDeviceInfo(Constants.ADDR_PLAYBACK_3, 0x3000, 0,
+ Constants.ADDR_PLAYBACK_1, 0, "Test Device");
+
+ mHdmiControlService.setActiveSource(externalDevice.getLogicalAddress(),
+ externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getActiveSource().getPhysicalAddress()).isEqualTo(
+ externalDevice.getPhysicalAddress());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index e54f2c9e6b2e..2f49fb79c3dc 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -42,6 +42,8 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
@SmallTest
@Presubmit
@@ -80,6 +82,21 @@ public class HdmiCecLocalDeviceTest {
@Override
protected void setPreferredAddress(int addr) {}
+
+ @Override
+ protected int getRcProfile() {
+ return 0;
+ }
+
+ @Override
+ protected List<Integer> getRcFeatures() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ protected List<Integer> getDeviceFeatures() {
+ return Collections.emptyList();
+ }
}
private MyHdmiCecLocalDevice mHdmiLocalDevice;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index bf4851b927b1..12414d99d991 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.Handler;
@@ -71,6 +72,9 @@ public class HdmiCecLocalDeviceTvTest {
mMyLooper = mTestLooper.getLooper();
PowerManager powerManager = new PowerManager(context, mIPowerManagerMock,
mIThermalServiceMock, new Handler(mMyLooper));
+
+ HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
+
mHdmiControlService =
new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
@Override
@@ -92,6 +96,11 @@ public class HdmiCecLocalDeviceTvTest {
PowerManager getPowerManager() {
return powerManager;
}
+
+ @Override
+ HdmiCecConfig getHdmiCecConfig() {
+ return hdmiCecConfig;
+ }
};
mHdmiCecLocalDeviceTv = new HdmiCecLocalDeviceTv(mHdmiControlService);
@@ -136,4 +145,51 @@ public class HdmiCecLocalDeviceTvTest {
ADDR_PLAYBACK_1);
assertThat(mNativeWrapper.getResultMessages()).contains(givePhysicalAddress);
}
+
+ @Test
+ public void getActiveSource_noActiveSource() {
+ mHdmiControlService.setActiveSource(Constants.ADDR_UNREGISTERED,
+ Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
+ mHdmiCecLocalDeviceTv.setActivePath(HdmiDeviceInfo.PATH_INVALID);
+
+ assertThat(mHdmiControlService.getActiveSource()).isNull();
+ }
+
+ @Test
+ public void getActiveSource_deviceInNetworkIsActiveSource() {
+ HdmiDeviceInfo externalDevice = new HdmiDeviceInfo(Constants.ADDR_PLAYBACK_3, 0x1000, 0,
+ Constants.ADDR_PLAYBACK_1, 0, "Test Device");
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(externalDevice);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlService.setActiveSource(externalDevice.getLogicalAddress(),
+ externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getActiveSource()).isEqualTo(externalDevice);
+ }
+
+ @Test
+ public void getActiveSource_unknownLogicalAddressInNetworkIsActiveSource() {
+ HdmiDeviceInfo externalDevice = new HdmiDeviceInfo(0x1000, 1);
+
+ mHdmiControlService.setActiveSource(Constants.ADDR_UNREGISTERED,
+ externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
+ mHdmiCecLocalDeviceTv.setActivePath(0x1000);
+
+ assertThat(mHdmiControlService.getActiveSource()).isEqualTo(
+ externalDevice);
+ }
+
+ @Test
+ public void getActiveSource_unknownDeviceIsActiveSource() {
+ HdmiDeviceInfo externalDevice = new HdmiDeviceInfo(Constants.ADDR_PLAYBACK_3, 0x1000, 0,
+ Constants.ADDR_PLAYBACK_1, 0, "Test Device");
+
+ mHdmiControlService.setActiveSource(externalDevice.getLogicalAddress(),
+ externalDevice.getPhysicalAddress(), "HdmiControlServiceTest");
+ mHdmiCecLocalDeviceTv.setActivePath(0x1000);
+
+ assertThat(mHdmiControlService.getActiveSource().getPhysicalAddress()).isEqualTo(
+ externalDevice.getPhysicalAddress());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
index f17173f61b69..6882ec1869ea 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageBuilderTest.java
@@ -26,10 +26,14 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.google.android.collect.Lists;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.Collections;
+
@SmallTest
@Presubmit
@RunWith(JUnit4.class)
@@ -88,6 +92,98 @@ public class HdmiCecMessageBuilderTest {
buildMessage("40:47:61:62:63:64:65:66:67:68:69:6A:6B:6C:6D:6E"));
}
+ @Test
+ public void buildGiveFeatures() {
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildGiveFeatures(ADDR_PLAYBACK_1, ADDR_TV);
+
+ assertThat(message).isEqualTo(buildMessage("40:A5"));
+ }
+
+ @Test
+ public void buildReportFeatures_basicTv_1_4() {
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+ Constants.VERSION_1_4,
+ Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV,
+ Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList());
+
+ assertThat(message).isEqualTo(buildMessage("0F:A6:05:80:00:00"));
+ }
+
+ @Test
+ public void buildReportFeatures_basicPlayback_1_4() {
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_PLAYBACK_1,
+ Constants.VERSION_1_4,
+ Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK), Constants.RC_PROFILE_TV,
+ Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList());
+
+ assertThat(message).isEqualTo(buildMessage("4F:A6:05:10:00:00"));
+ }
+
+ @Test
+ public void buildReportFeatures_basicPlaybackAudioSystem_1_4() {
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_PLAYBACK_1,
+ Constants.VERSION_1_4,
+ Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK,
+ HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM), Constants.RC_PROFILE_TV,
+ Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList());
+
+ assertThat(message).isEqualTo(buildMessage("4F:A6:05:18:00:00"));
+ }
+
+ @Test
+ public void buildReportFeatures_basicTv_2_0() {
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+ Constants.VERSION_2_0,
+ Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV,
+ Lists.newArrayList(Constants.RC_PROFILE_TV_NONE), Collections.emptyList());
+
+ assertThat(message).isEqualTo(buildMessage("0F:A6:06:80:00:00"));
+ }
+
+ @Test
+ public void buildReportFeatures_remoteControlTv_2_0() {
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+ Constants.VERSION_2_0,
+ Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV,
+ Lists.newArrayList(Constants.RC_PROFILE_TV_ONE), Collections.emptyList());
+
+ assertThat(message).isEqualTo(buildMessage("0F:A6:06:80:02:00"));
+ }
+
+ @Test
+ public void buildReportFeatures_remoteControlPlayback_2_0() {
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+ Constants.VERSION_2_0,
+ Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK), Constants.RC_PROFILE_SOURCE,
+ Lists.newArrayList(Constants.RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ Constants.RC_PROFILE_SOURCE_HANDLES_SETUP_MENU), Collections.emptyList());
+
+ assertThat(message).isEqualTo(buildMessage("0F:A6:06:10:4A:00"));
+ }
+
+ @Test
+ public void buildReportFeatures_deviceFeaturesTv_2_0() {
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+ Constants.VERSION_2_0,
+ Lists.newArrayList(HdmiDeviceInfo.DEVICE_TV), Constants.RC_PROFILE_TV,
+ Lists.newArrayList(Constants.RC_PROFILE_TV_NONE),
+ Lists.newArrayList(Constants.DEVICE_FEATURE_TV_SUPPORTS_RECORD_TV_SCREEN));
+
+ assertThat(message).isEqualTo(buildMessage("0F:A6:06:80:00:40"));
+ }
+
+ @Test
+ public void buildReportFeatures_deviceFeaturesPlayback_2_0() {
+ HdmiCecMessage message = HdmiCecMessageBuilder.buildReportFeatures(ADDR_TV,
+ Constants.VERSION_2_0,
+ Lists.newArrayList(HdmiDeviceInfo.DEVICE_PLAYBACK), Constants.RC_PROFILE_SOURCE,
+ Lists.newArrayList(Constants.RC_PROFILE_SOURCE_HANDLES_TOP_MENU,
+ Constants.RC_PROFILE_SOURCE_HANDLES_SETUP_MENU),
+ Lists.newArrayList(Constants.DEVICE_FEATURE_SUPPORTS_DECK_CONTROL));
+
+ assertThat(message).isEqualTo(buildMessage("0F:A6:06:10:4A:10"));
+ }
+
/**
* Build a CEC message from a hex byte string with bytes separated by {@code :}.
*
@@ -100,7 +196,7 @@ public class HdmiCecMessageBuilderTest {
int opcode = Integer.parseInt(parts[1], 16);
byte[] params = new byte[parts.length - 2];
for (int i = 0; i < params.length; i++) {
- params[i] = Byte.parseByte(parts[i + 2], 16);
+ params[i] = (byte) Integer.parseInt(parts[i + 2], 16);
}
return new HdmiCecMessage(src, dest, opcode, params);
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
index 553df3bafd00..0e9f01a3b8cd 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecMessageValidatorTest.java
@@ -353,6 +353,165 @@ public class HdmiCecMessageValidatorTest {
assertMessageValidity("40:35:EE:52:4A").isEqualTo(ERROR_PARAMETER);
}
+ @Test
+ public void isValid_giveFeatures() {
+ assertMessageValidity("40:A5").isEqualTo(OK);
+
+ assertMessageValidity("4F:A5").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:A5").isEqualTo(ERROR_SOURCE);
+ }
+
+ @Test
+ public void isValid_reportFeatures() {
+ assertMessageValidity("0F:A6:05:80:00:00").isEqualTo(OK);
+
+ assertMessageValidity("04:A6:05:80:00:00").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("FF:A6:05:80:00:00").isEqualTo(ERROR_SOURCE);
+
+ assertMessageValidity("0F:A6").isEqualTo(ERROR_PARAMETER_SHORT);
+ }
+
+ @Test
+ public void isValid_deckControl() {
+ assertMessageValidity("40:42:01:6E").isEqualTo(OK);
+ assertMessageValidity("40:42:04").isEqualTo(OK);
+
+ assertMessageValidity("4F:42:01").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:42:04").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("40:42").isEqualTo(ERROR_PARAMETER_SHORT);
+ assertMessageValidity("40:42:05").isEqualTo(ERROR_PARAMETER);
+ }
+
+ @Test
+ public void isValid_deckStatus() {
+ assertMessageValidity("40:1B:11:58").isEqualTo(OK);
+ assertMessageValidity("40:1B:1F").isEqualTo(OK);
+
+ assertMessageValidity("4F:1B:11").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:1B:1F").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("40:1B").isEqualTo(ERROR_PARAMETER_SHORT);
+ assertMessageValidity("40:1B:10").isEqualTo(ERROR_PARAMETER);
+ assertMessageValidity("40:1B:20").isEqualTo(ERROR_PARAMETER);
+ }
+
+ @Test
+ public void isValid_statusRequest() {
+ assertMessageValidity("40:08:01").isEqualTo(OK);
+ assertMessageValidity("40:08:02:5C").isEqualTo(OK);
+ assertMessageValidity("40:1A:01:F8").isEqualTo(OK);
+ assertMessageValidity("40:1A:03").isEqualTo(OK);
+
+ assertMessageValidity("4F:08:01").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:08:03").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("4F:1A:01").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:1A:03").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("40:08").isEqualTo(ERROR_PARAMETER_SHORT);
+ assertMessageValidity("40:1A").isEqualTo(ERROR_PARAMETER_SHORT);
+ assertMessageValidity("40:08:00").isEqualTo(ERROR_PARAMETER);
+ assertMessageValidity("40:08:05").isEqualTo(ERROR_PARAMETER);
+ assertMessageValidity("40:1A:00").isEqualTo(ERROR_PARAMETER);
+ assertMessageValidity("40:1A:04").isEqualTo(ERROR_PARAMETER);
+ }
+
+ @Test
+ public void isValid_play() {
+ assertMessageValidity("40:41:16:E3").isEqualTo(OK);
+ assertMessageValidity("40:41:20").isEqualTo(OK);
+
+ assertMessageValidity("4F:41:16").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:41:20").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("40:41").isEqualTo(ERROR_PARAMETER_SHORT);
+ assertMessageValidity("40:41:04").isEqualTo(ERROR_PARAMETER);
+ assertMessageValidity("40:41:18").isEqualTo(ERROR_PARAMETER);
+ assertMessageValidity("40:41:23").isEqualTo(ERROR_PARAMETER);
+ assertMessageValidity("40:41:26").isEqualTo(ERROR_PARAMETER);
+ }
+
+ @Test
+ public void isValid_selectAnalogueService() {
+ assertMessageValidity("40:92:00:13:0F:00:96").isEqualTo(OK);
+ assertMessageValidity("40:92:02:EA:60:1F").isEqualTo(OK);
+
+ assertMessageValidity("4F:92:00:13:0F:00").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:92:02:EA:60:1F").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("40:92:00:13:0F").isEqualTo(ERROR_PARAMETER_SHORT);
+ // Invalid Analogue Broadcast type
+ assertMessageValidity("40:92:03:EA:60:1F").isEqualTo(ERROR_PARAMETER);
+ // Invalid Analogue Frequency
+ assertMessageValidity("40:92:00:FF:FF:00").isEqualTo(ERROR_PARAMETER);
+ // Invalid Broadcast system
+ assertMessageValidity("40:92:02:EA:60:20").isEqualTo(ERROR_PARAMETER);
+ }
+
+ @Test
+ public void isValid_selectDigitalService() {
+ assertMessageValidity("40:93:00:11:CE:90:0F:00:78").isEqualTo(OK);
+ assertMessageValidity("40:93:10:13:0B:34:38").isEqualTo(OK);
+ assertMessageValidity("40:93:9A:06:F9:D3:E6").isEqualTo(OK);
+ assertMessageValidity("40:93:91:09:F4:40:C8").isEqualTo(OK);
+
+ assertMessageValidity("4F:93:00:11:CE:90:0F:00:78").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:93:10:13:0B:34:38").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("40:93:9A:06:F9").isEqualTo(ERROR_PARAMETER_SHORT);
+ // Invalid Digital Broadcast System
+ assertMessageValidity("40:93:14:11:CE:90:0F:00:78").isEqualTo(ERROR_PARAMETER);
+ // Invalid Digital Broadcast System
+ assertMessageValidity("40:93:A0:07:95:F1").isEqualTo(ERROR_PARAMETER);
+ // Insufficient data for ARIB Broadcast system
+ assertMessageValidity("40:93:00:11:CE:90:0F:00").isEqualTo(ERROR_PARAMETER);
+ // Insufficient data for ATSC Broadcast system
+ assertMessageValidity("40:93:10:13:0B:34").isEqualTo(ERROR_PARAMETER);
+ // Insufficient data for DVB Broadcast system
+ assertMessageValidity("40:93:18:BE:77:00:7D:01").isEqualTo(ERROR_PARAMETER);
+ // Invalid channel number format
+ assertMessageValidity("40:93:9A:10:F9:D3").isEqualTo(ERROR_PARAMETER);
+ // Insufficient data for 2 part channel number
+ assertMessageValidity("40:93:91:09:F4:40").isEqualTo(ERROR_PARAMETER);
+ }
+
+ @Test
+ public void isValid_UserControlPressed() {
+ assertMessageValidity("40:44:07").isEqualTo(OK);
+ assertMessageValidity("40:44:52:A7").isEqualTo(OK);
+
+ assertMessageValidity("40:44:60").isEqualTo(OK);
+ assertMessageValidity("40:44:60:1A").isEqualTo(OK);
+
+ assertMessageValidity("40:44:67").isEqualTo(OK);
+ assertMessageValidity("40:44:67:04:00:B1").isEqualTo(OK);
+ assertMessageValidity("40:44:67:09:C8:72:C8").isEqualTo(OK);
+
+ assertMessageValidity("40:44:68").isEqualTo(OK);
+ assertMessageValidity("40:44:68:93").isEqualTo(OK);
+ assertMessageValidity("40:44:69").isEqualTo(OK);
+ assertMessageValidity("40:44:69:7C").isEqualTo(OK);
+ assertMessageValidity("40:44:6A").isEqualTo(OK);
+ assertMessageValidity("40:44:6A:B4").isEqualTo(OK);
+
+ assertMessageValidity("40:44:56").isEqualTo(OK);
+ assertMessageValidity("40:44:56:60").isEqualTo(OK);
+
+ assertMessageValidity("40:44:57").isEqualTo(OK);
+ assertMessageValidity("40:44:57:A0").isEqualTo(OK);
+
+ assertMessageValidity("4F:44:07").isEqualTo(ERROR_DESTINATION);
+ assertMessageValidity("F0:44:52:A7").isEqualTo(ERROR_SOURCE);
+ assertMessageValidity("40:44").isEqualTo(ERROR_PARAMETER_SHORT);
+ assertMessageValidity("40:44:67:04:B1").isEqualTo(ERROR_PARAMETER_SHORT);
+ // Invalid Play mode
+ assertMessageValidity("40:44:60:04").isEqualTo(ERROR_PARAMETER);
+ assertMessageValidity("40:44:60:08").isEqualTo(ERROR_PARAMETER);
+ assertMessageValidity("40:44:60:26").isEqualTo(ERROR_PARAMETER);
+ // Invalid Channel Identifier - Channel number format
+ assertMessageValidity("40:44:67:11:8A:42").isEqualTo(ERROR_PARAMETER);
+ // Insufficient data for 2 - part channel number
+ assertMessageValidity("40:44:67:09:C8:72").isEqualTo(ERROR_PARAMETER);
+ // Invalid UI Broadcast type
+ assertMessageValidity("40:44:56:11").isEqualTo(ERROR_PARAMETER);
+ // Invalid UI Sound Presentation Control
+ assertMessageValidity("40:44:57:40").isEqualTo(ERROR_PARAMETER);
+ }
+
private IntegerSubject assertMessageValidity(String message) {
return assertThat(mHdmiCecMessageValidator.isValid(buildMessage(message)));
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
index 74a00521d7f4..c212bf868c76 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceBinderAPITest.java
@@ -38,6 +38,8 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* Tests for {@link HdmiControlServiceBinderAPITest} class.
@@ -99,6 +101,21 @@ public class HdmiControlServiceBinderAPITest {
protected void setCanGoToStandby(boolean canGoToStandby) {
mCanGoToStandby = canGoToStandby;
}
+
+ @Override
+ protected int getRcProfile() {
+ return 0;
+ }
+
+ @Override
+ protected List<Integer> getRcFeatures() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ protected List<Integer> getDeviceFeatures() {
+ return Collections.emptyList();
+ }
}
private static final String TAG = "HdmiControlServiceBinderAPITest";
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 68b46c408028..2e4bed97dbec 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -54,6 +54,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Arrays;
/**
* Tests for {@link HdmiControlService} class.
@@ -141,11 +142,18 @@ public class HdmiControlServiceTest {
when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
+ HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
+
mHdmiControlService = new HdmiControlService(mContextSpy) {
@Override
boolean isStandbyMessageReceived() {
return mStandbyMessageReceived;
}
+
+ @Override
+ HdmiCecConfig getHdmiCecConfig() {
+ return hdmiCecConfig;
+ }
};
mMyLooper = mTestLooper.getLooper();
@@ -389,38 +397,85 @@ public class HdmiControlServiceTest {
Settings.Global.HDMI_CEC_VERSION,
null);
mHdmiControlService.setControlEnabled(true);
- assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_1_4);
+ assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b);
}
@Test
public void getCecVersion_1_4() {
- Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION,
- Constants.VERSION_1_4);
+ mHdmiControlService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b);
mHdmiControlService.setControlEnabled(true);
- assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_1_4);
+ assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b);
}
@Test
public void getCecVersion_2_0() {
- Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION,
- Constants.VERSION_2_0);
+ mHdmiControlService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.HDMI_CEC_VERSION_2_0);
mHdmiControlService.setControlEnabled(true);
- assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_2_0);
+ assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
+ HdmiControlManager.HDMI_CEC_VERSION_2_0);
}
@Test
public void getCecVersion_change() {
- Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION,
- Constants.VERSION_1_4);
+ mHdmiControlService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b);
+ mHdmiControlService.setControlEnabled(true);
+ assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b);
+
+ mHdmiControlService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.HDMI_CEC_VERSION_2_0);
mHdmiControlService.setControlEnabled(true);
- assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_1_4);
+ assertThat(mHdmiControlService.getCecVersion()).isEqualTo(
+ HdmiControlManager.HDMI_CEC_VERSION_2_0);
+ }
- Settings.Global.putInt(mContextSpy.getContentResolver(), Settings.Global.HDMI_CEC_VERSION,
- Constants.VERSION_2_0);
+ @Test
+ public void handleGiveFeatures_cec14_featureAbort() {
+ mHdmiControlService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b);
mHdmiControlService.setControlEnabled(true);
- assertThat(mHdmiControlService.getCecVersion()).isEqualTo(Constants.VERSION_2_0);
+ mTestLooper.dispatchAll();
+
+ mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveFeatures(Constants.ADDR_TV,
+ Constants.ADDR_PLAYBACK_1));
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand(
+ Constants.ADDR_PLAYBACK_1, Constants.ADDR_TV, Constants.MESSAGE_GIVE_FEATURES,
+ Constants.ABORT_UNRECOGNIZED_OPCODE);
+ assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort);
}
+ @Test
+ public void handleGiveFeatures_cec20_reportsFeatures() {
+ mHdmiControlService.getHdmiCecConfig().setIntValue(
+ HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
+ HdmiControlManager.HDMI_CEC_VERSION_2_0);
+ mHdmiControlService.setControlEnabled(true);
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+
+ mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveFeatures(Constants.ADDR_TV,
+ Constants.ADDR_PLAYBACK_1));
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage reportFeatures = HdmiCecMessageBuilder.buildReportFeatures(
+ Constants.ADDR_PLAYBACK_1, Constants.VERSION_2_0,
+ Arrays.asList(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM),
+ mMyPlaybackDevice.getRcProfile(), mMyPlaybackDevice.getRcFeatures(),
+ mMyPlaybackDevice.getDeviceFeatures());
+ assertThat(mNativeWrapper.getResultMessages()).contains(reportFeatures);
+ }
private static class VolumeControlFeatureCallback extends
IHdmiCecVolumeControlFeatureListener.Stub {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
index a8f3acf8726f..dbf3b531fe04 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiUtilsTest.java
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.platform.test.annotations.Presubmit;
import android.util.Slog;
@@ -533,69 +534,84 @@ public class HdmiUtilsTest {
@Test
public void isEligibleAddressForCecVersion_1_4() {
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_TV)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_RECORDER_1)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_RECORDER_2)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_TUNER_1)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_PLAYBACK_1)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_AUDIO_SYSTEM)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_TUNER_2)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_TUNER_3)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_PLAYBACK_2)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_RECORDER_3)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_TUNER_4)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_PLAYBACK_3)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_BACKUP_1)).isFalse();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_BACKUP_2)).isFalse();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_1_4,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(
+ HdmiControlManager.HDMI_CEC_VERSION_1_4_b,
Constants.ADDR_SPECIFIC_USE)).isTrue();
}
@Test
public void isEligibleAddressForCecVersion_2_0() {
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_TV)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_RECORDER_1)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_RECORDER_2)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_TUNER_1)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_PLAYBACK_1)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_AUDIO_SYSTEM)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_TUNER_2)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_TUNER_3)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_PLAYBACK_2)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_RECORDER_3)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_TUNER_4)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_PLAYBACK_3)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_BACKUP_1)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_BACKUP_2)).isTrue();
- assertThat(HdmiUtils.isEligibleAddressForCecVersion(Constants.VERSION_2_0,
+ assertThat(HdmiUtils.isEligibleAddressForCecVersion(HdmiControlManager.HDMI_CEC_VERSION_2_0,
Constants.ADDR_SPECIFIC_USE)).isTrue();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
index 0e4bfab0d94c..0a225a06b380 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/SystemAudioInitiationActionFromAvrTest.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.annotation.Nullable;
+import android.content.Context;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.media.AudioManager;
@@ -61,9 +62,12 @@ public class SystemAudioInitiationActionFromAvrTest {
@Before
public void SetUp() {
mDeviceInfoForTests = new HdmiDeviceInfo(1001, 1234);
- HdmiControlService hdmiControlService =
- new HdmiControlService(InstrumentationRegistry.getTargetContext()) {
+ Context context = InstrumentationRegistry.getTargetContext();
+
+ HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(context);
+
+ HdmiControlService hdmiControlService = new HdmiControlService(context) {
@Override
void sendCecCommand(
HdmiCecMessage command, @Nullable SendMessageCallback callback) {
@@ -156,6 +160,11 @@ public class SystemAudioInitiationActionFromAvrTest {
int pathToPortId(int path) {
return -1;
}
+
+ @Override
+ HdmiCecConfig getHdmiCecConfig() {
+ return hdmiCecConfig;
+ }
};
Looper looper = mTestLooper.getLooper();
diff --git a/services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java b/services/tests/servicestests/src/com/android/server/location/countrydetector/ComprehensiveCountryDetectorTest.java
index 98966c032d14..41cfa62f2e2b 100644
--- a/services/tests/servicestests/src/com/android/server/location/ComprehensiveCountryDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/countrydetector/ComprehensiveCountryDetectorTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 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.
@@ -11,10 +11,10 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
-package com.android.server.location;
+package com.android.server.location.countrydetector;
import android.location.Country;
import android.location.CountryListener;
diff --git a/services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java b/services/tests/servicestests/src/com/android/server/location/countrydetector/CustomCountryDetectorTestClass.java
index e159012f1b54..fc19a945d09c 100644
--- a/services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java
+++ b/services/tests/servicestests/src/com/android/server/location/countrydetector/CustomCountryDetectorTestClass.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.server.location;
+package com.android.server.location.countrydetector;
import android.content.Context;
import android.location.Country;
diff --git a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java b/services/tests/servicestests/src/com/android/server/location/countrydetector/LocationBasedCountryDetectorTest.java
index 5f5d6684f383..46269ebb3219 100644
--- a/services/tests/servicestests/src/com/android/server/location/LocationBasedCountryDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/countrydetector/LocationBasedCountryDetectorTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 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.
@@ -11,9 +11,9 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
-package com.android.server.location;
+package com.android.server.location.countrydetector;
import android.location.Country;
import android.location.CountryListener;
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
index 292b7c6bf5ad..c4b19e84bccb 100644
--- a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
@@ -26,7 +26,6 @@ import static com.android.server.location.timezone.LocationTimeZoneProvider.Prov
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
import static com.android.server.location.timezone.TestSupport.USER1_CONFIG_GEO_DETECTION_DISABLED;
import static com.android.server.location.timezone.TestSupport.USER1_CONFIG_GEO_DETECTION_ENABLED;
-import static com.android.server.location.timezone.TestSupport.USER1_ID;
import static com.android.server.location.timezone.TestSupport.USER2_CONFIG_GEO_DETECTION_ENABLED;
import static org.junit.Assert.assertEquals;
@@ -38,9 +37,7 @@ import static java.util.Arrays.asList;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.location.timezone.LocationTimeZoneEvent;
-import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.util.IndentingPrintWriter;
@@ -66,13 +63,13 @@ public class ControllerImplTest {
private static final long ARBITRARY_TIME = 12345L;
private static final LocationTimeZoneEvent USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1 =
- createLocationTimeZoneEvent(USER1_ID, EVENT_TYPE_SUCCESS, asList("Europe/London"));
+ createLocationTimeZoneEvent(EVENT_TYPE_SUCCESS, asList("Europe/London"));
private static final LocationTimeZoneEvent USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2 =
- createLocationTimeZoneEvent(USER1_ID, EVENT_TYPE_SUCCESS, asList("Europe/Paris"));
+ createLocationTimeZoneEvent(EVENT_TYPE_SUCCESS, asList("Europe/Paris"));
private static final LocationTimeZoneEvent USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT =
- createLocationTimeZoneEvent(USER1_ID, EVENT_TYPE_UNCERTAIN, null);
+ createLocationTimeZoneEvent(EVENT_TYPE_UNCERTAIN, null);
private static final LocationTimeZoneEvent USER1_PERM_FAILURE_LOCATION_TIME_ZONE_EVENT =
- createLocationTimeZoneEvent(USER1_ID, EVENT_TYPE_PERMANENT_FAILURE, null);
+ createLocationTimeZoneEvent(EVENT_TYPE_PERMANENT_FAILURE, null);
private TestThreadingDomain mTestThreadingDomain;
private TestCallback mTestCallback;
@@ -936,11 +933,10 @@ public class ControllerImplTest {
controller.getUncertaintyTimeoutDelayMillis());
}
- private static LocationTimeZoneEvent createLocationTimeZoneEvent(@UserIdInt int userId,
+ private static LocationTimeZoneEvent createLocationTimeZoneEvent(
int eventType, @Nullable List<String> timeZoneIds) {
LocationTimeZoneEvent.Builder builder = new LocationTimeZoneEvent.Builder()
.setElapsedRealtimeNanos(ARBITRARY_TIME)
- .setUserHandle(UserHandle.of(userId))
.setEventType(eventType);
if (timeZoneIds != null) {
builder.setTimeZoneIds(timeZoneIds);
diff --git a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
index 40d959d9793d..9ba096766be2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
@@ -44,7 +44,6 @@ import java.util.concurrent.atomic.AtomicInteger;
public class IncrementalStatesTest {
private IncrementalStates mIncrementalStates;
private ConditionVariable mUnstartableCalled = new ConditionVariable();
- private ConditionVariable mStartableCalled = new ConditionVariable();
private ConditionVariable mFullyLoadedCalled = new ConditionVariable();
private AtomicInteger mUnstartableReason = new AtomicInteger(0);
private static final int WAIT_TIMEOUT_MILLIS = 1000; /* 1 second */
@@ -57,7 +56,6 @@ public class IncrementalStatesTest {
@Override
public void onPackageStartable() {
- mStartableCalled.open();
}
@Override
@@ -77,24 +75,22 @@ public class IncrementalStatesTest {
mIncrementalStates.setCallback(mCallback);
mIncrementalStates.onCommit(true);
// Test that package is now startable and loading
- assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertTrue(mIncrementalStates.isStartable());
assertTrue(mIncrementalStates.isLoading());
- mStartableCalled.close();
mUnstartableCalled.close();
mFullyLoadedCalled.close();
}
/**
- * Test that startable state changes to false when Incremental Storage is unhealthy.
+ * Test that the package is still startable when Incremental Storage is unhealthy.
*/
@Test
public void testStartableTransition_IncrementalStorageUnhealthy() {
mIncrementalStates.onStorageHealthStatusChanged(
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
- // Test that package is now unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
+ // Test that package is still startable
+ assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
+ assertTrue(mIncrementalStates.isStartable());
assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN, mUnstartableReason.get());
}
@@ -112,70 +108,31 @@ public class IncrementalStatesTest {
}
/**
- * Test that the package becomes unstartable when health status indicate storage issues.
+ * Test that the package is still startable when health status indicate storage issues.
*/
@Test
public void testStartableTransition_IncrementalStorageBlocked() {
mIncrementalStates.onStorageHealthStatusChanged(
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_STORAGE);
- // Test that package is now unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE,
+ // Test that package is still startable
+ assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
+ assertTrue(mIncrementalStates.isStartable());
+ assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN,
mUnstartableReason.get());
}
/**
- * Test that the package becomes unstartable when health status indicates transport issues.
+ * Test that the package is still startable when health status indicates transport issues.
*/
@Test
public void testStartableTransition_DataLoaderIntegrityError() {
mIncrementalStates.onStorageHealthStatusChanged(
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_TRANSPORT);
- // Test that package is now unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR,
- mUnstartableReason.get());
- }
-
- /**
- * Test that the package becomes unstartable when Incremental Storage is unhealthy, and it
- * becomes startable again when Incremental Storage is healthy again.
- */
- @Test
- public void testStartableTransition_IncrementalStorageUnhealthyBackToHealthy()
- throws InterruptedException {
- mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
- // Test that package is unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
-
- mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_OK);
- // Test that package is now startable
- assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
- }
-
- /**
- * Test that the package becomes unstartable when health status indicates transportation issue,
- * and it becomes startable again when health status is ok again.
- */
- @Test
- public void testStartableTransition_DataLoaderUnhealthyBackToHealthy()
- throws InterruptedException {
- mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_TRANSPORT);
- // Test that package is unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
-
- mIncrementalStates.onStorageHealthStatusChanged(IStorageHealthListener.HEALTH_STATUS_OK);
- // Test that package is now startable
- assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
+ // Test that package is still startable
+ assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertTrue(mIncrementalStates.isStartable());
+ assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN,
+ mUnstartableReason.get());
}
/**
@@ -197,43 +154,11 @@ public class IncrementalStatesTest {
}
/**
- * Test that when loading progress is 1, the package becomes fully loaded, and if the package
- * was unstartable, it becomes startable.
- */
- @Test
- public void testLoadingTransition_FullyLoadedWhenUnstartable() throws InterruptedException {
- mIncrementalStates.onStorageHealthStatusChanged(
- IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
- // Test that package is unstartable
- assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
- // Test that package is still loading
- assertTrue(mIncrementalStates.isLoading());
-
- mIncrementalStates.setProgress(0.5f);
- // Test that package is still unstartable
- assertFalse(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isStartable());
- mIncrementalStates.setProgress(1.0f);
- // Test that package is now startable
- assertTrue(mStartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
- // Test that package is now fully loaded
- assertTrue(mFullyLoadedCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isLoading());
- }
-
- /**
* Test startability transitions if app crashes or anrs
*/
@Test
public void testStartableTransition_AppCrashOrAnr() {
mIncrementalStates.onCrashOrAnr();
- assertFalse(mIncrementalStates.isStartable());
- mIncrementalStates.setProgress(1.0f);
- assertTrue(mIncrementalStates.isStartable());
- mIncrementalStates.onCrashOrAnr();
- // Test that if fully loaded, app remains startable even if it has crashed
assertTrue(mIncrementalStates.isStartable());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 6febae00f0fb..7f35511236f7 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -1053,6 +1053,35 @@ public class PowerManagerServiceTest {
}
@Test
+ public void testGetAmbientDisplaySuppressionTokens_default() {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+
+ assertThat(service.getAmbientDisplaySuppressionTokens()).isEmpty();
+ }
+
+ @Test
+ public void testGetAmbientDisplaySuppressionTokens_singleToken() {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+ service.suppressAmbientDisplay("test1", true);
+ service.suppressAmbientDisplay("test2", false);
+
+ assertThat(service.getAmbientDisplaySuppressionTokens()).containsExactly("test1");
+ }
+
+ @Test
+ public void testGetAmbientDisplaySuppressionTokens_multipleTokens() {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+ service.suppressAmbientDisplay("test1", true);
+ service.suppressAmbientDisplay("test2", true);
+
+ assertThat(service.getAmbientDisplaySuppressionTokens())
+ .containsExactly("test1", "test2");
+ }
+
+ @Test
public void testSetPowerBoost_redirectsCallToNativeWrapper() {
createService();
mService.systemReady(null);
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
index dc30add1b383..fb6b29e4188e 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
@@ -117,7 +117,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
@SmallTest
public void testGetBatterySaverPolicy_PolicyVibration_WithAccessibilityEnabled() {
- mBatterySaverPolicy.setAccessibilityEnabled(true);
+ mBatterySaverPolicy.mAccessibilityEnabled.update(true);
testServiceDefaultValue_Off(ServiceType.VIBRATION);
}
@@ -340,7 +340,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
verifyBatterySaverConstantsUpdated();
}
- public void testCarModeChanges_Full() {
+ public void testAutomotiveProjectionChanges_Full() {
mBatterySaverPolicy.updateConstantsLocked(
"gps_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF
+ ",enable_night_mode=true", "");
@@ -350,7 +350,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
assertTrue(mBatterySaverPolicy.getBatterySaverPolicy(
ServiceType.NIGHT_MODE).batterySaverEnabled);
- mBatterySaverPolicy.setCarModeEnabled(true);
+ mBatterySaverPolicy.mAutomotiveProjectionActive.update(true);
assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
.isAnyOf(PowerManager.LOCATION_MODE_NO_CHANGE,
@@ -358,7 +358,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
assertFalse(mBatterySaverPolicy.getBatterySaverPolicy(
ServiceType.NIGHT_MODE).batterySaverEnabled);
- mBatterySaverPolicy.setCarModeEnabled(false);
+ mBatterySaverPolicy.mAutomotiveProjectionActive.update(false);
assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
.isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
@@ -366,7 +366,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
ServiceType.NIGHT_MODE).batterySaverEnabled);
}
- public void testCarModeChanges_Adaptive() {
+ public void testAutomotiveProjectionChanges_Adaptive() {
mBatterySaverPolicy.setAdaptivePolicyLocked(
Policy.fromSettings(
"gps_mode=" + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF
@@ -377,7 +377,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
assertTrue(mBatterySaverPolicy.getBatterySaverPolicy(
ServiceType.NIGHT_MODE).batterySaverEnabled);
- mBatterySaverPolicy.setCarModeEnabled(true);
+ mBatterySaverPolicy.mAutomotiveProjectionActive.update(true);
assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
.isAnyOf(PowerManager.LOCATION_MODE_NO_CHANGE,
@@ -385,7 +385,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase {
assertFalse(mBatterySaverPolicy.getBatterySaverPolicy(
ServiceType.NIGHT_MODE).batterySaverEnabled);
- mBatterySaverPolicy.setCarModeEnabled(false);
+ mBatterySaverPolicy.mAutomotiveProjectionActive.update(false);
assertThat(mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.LOCATION).locationMode)
.isEqualTo(PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index c43050386dcf..0ad669f32060 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -728,7 +728,6 @@ public class AppStandbyControllerTests {
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
}
- @Ignore
@Test
public void testPredictionTimedOut() throws Exception {
// Set it to timeout or usage, so that prediction can override it
@@ -1257,6 +1256,7 @@ public class AppStandbyControllerTests {
assertBucket(STANDBY_BUCKET_ACTIVE);
}
+ @Ignore
@Test
public void testPredictionStrikesBack() throws Exception {
reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
diff --git a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
new file mode 100644
index 000000000000..40575e4cf16f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
@@ -0,0 +1,304 @@
+/**
+ * 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.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.TraceBuffer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class for {@link Watcher}, {@link Watchable}, {@link WatchableImpl},
+ * {@link WatchedArrayMap}, {@link WatchedSparseArray}, and
+ * {@link WatchedSparseBooleanArray}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:WatcherTest
+ */
+@SmallTest
+public class WatcherTest {
+
+ // A small Watchable leaf node
+ private class Leaf extends WatchableImpl {
+ private int datum = 0;
+ void set(int i) {
+ if (datum != i) {
+ datum = i;
+ dispatchChange(this);
+ }
+ }
+ void tick() {
+ set(datum + 1);
+ }
+ }
+
+ // A top-most watcher. It counts the number of notifications that it receives.
+ private class Tester extends Watcher {
+ // The count of changes.
+ public int changes = 0;
+
+ // The single Watchable that this monitors.
+ public final Watchable mWatched;
+
+ // The key, used for messages
+ public String mKey;
+
+ // Create the Tester with a Watcher
+ public Tester(Watchable w, String k) {
+ mWatched = w;
+ mKey = k;
+ }
+
+ // Listen for events
+ public void register() {
+ mWatched.registerObserver(this);
+ }
+
+ // Stop listening for events
+ public void unregister() {
+ mWatched.unregisterObserver(this);
+ }
+
+ // Count the number of notifications received.
+ @Override
+ public void onChange(Watchable what) {
+ changes++;
+ }
+
+ // Verify the count.
+ public void verify(int want, String msg) {
+ assertEquals(mKey + " " + msg, want, changes);
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void test_notify() {
+
+ Tester tester;
+
+ // Create a few leaves
+ Leaf a = new Leaf();
+ Leaf b = new Leaf();
+ Leaf c = new Leaf();
+ Leaf d = new Leaf();
+
+ // Basic test. Create a leaf and verify that changes to the leaf get notified to
+ // the tester.
+ tester = new Tester(a, "Leaf");
+ tester.verify(0, "Initial leaf - no registration");
+ a.tick();
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ a.tick();
+ tester.verify(1, "Updates with registration");
+ a.tick();
+ a.tick();
+ tester.verify(3, "Updates with registration");
+
+ // Add the same leaf to more than one tester. Verify that a change to the leaf is seen by
+ // all registered listeners.
+ Tester buddy1 = new Tester(a, "Leaf2");
+ Tester buddy2 = new Tester(a, "Leaf3");
+ buddy1.verify(0, "Initial leaf - no registration");
+ buddy2.verify(0, "Initial leaf - no registration");
+ a.tick();
+ tester.verify(4, "Updates with buddies");
+ buddy1.verify(0, "Updates - no registration");
+ buddy2.verify(0, "Updates - no registration");
+ buddy1.register();
+ buddy2.register();
+ buddy1.verify(0, "No updates - registered");
+ buddy2.verify(0, "No updates - registered");
+ a.tick();
+ buddy1.verify(1, "First update");
+ buddy2.verify(1, "First update");
+ buddy1.unregister();
+ a.tick();
+ buddy1.verify(1, "Second update - unregistered");
+ buddy2.verify(2, "Second update");
+
+ buddy1 = null;
+ buddy2 = null;
+
+ final int INDEX_A = 1;
+ final int INDEX_B = 2;
+ final int INDEX_C = 3;
+ final int INDEX_D = 4;
+
+ // Test WatchedArrayMap
+ WatchedArrayMap<Integer, Leaf> am = new WatchedArrayMap<>();
+ am.put(INDEX_A, a);
+ am.put(INDEX_B, b);
+ tester = new Tester(am, "WatchedArrayMap");
+ tester.verify(0, "Initial array - no registration");
+ a.tick();
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ tester.verify(0, "Updates with no registration");
+ a.tick();
+ tester.verify(1, "Updates with registration");
+ b.tick();
+ tester.verify(2, "Updates with registration");
+ am.remove(INDEX_B);
+ tester.verify(3, "Removed b");
+ b.tick();
+ tester.verify(3, "Updates with b not watched");
+ am.put(INDEX_B, b);
+ am.put(INDEX_C, b);
+ tester.verify(5, "Added b twice");
+ b.tick();
+ tester.verify(6, "Changed b - single notification");
+ am.remove(INDEX_C);
+ tester.verify(7, "Removed first b");
+ b.tick();
+ tester.verify(8, "Changed b - single notification");
+ am.remove(INDEX_B);
+ tester.verify(9, "Removed second b");
+ b.tick();
+ tester.verify(9, "Updated b - no change");
+ am.clear();
+ tester.verify(10, "Cleared array");
+ b.tick();
+ tester.verify(10, "Change to b not in array");
+
+ // Special methods
+ am.put(INDEX_C, c);
+ tester.verify(11, "Added c");
+ c.tick();
+ tester.verify(12, "Ticked c");
+ am.setValueAt(am.indexOfKey(INDEX_C), d);
+ tester.verify(13, "Replaced c with d");
+ c.tick();
+ d.tick();
+ tester.verify(14, "Ticked d and c (c not registered)");
+
+ am = null;
+
+ // Test WatchedSparseArray
+ WatchedSparseArray<Leaf> sa = new WatchedSparseArray<>();
+ sa.put(INDEX_A, a);
+ sa.put(INDEX_B, b);
+ tester = new Tester(sa, "WatchedSparseArray");
+ tester.verify(0, "Initial array - no registration");
+ a.tick();
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ tester.verify(0, "Updates with no registration");
+ a.tick();
+ tester.verify(1, "Updates with registration");
+ b.tick();
+ tester.verify(2, "Updates with registration");
+ sa.remove(INDEX_B);
+ tester.verify(3, "Removed b");
+ b.tick();
+ tester.verify(3, "Updates with b not watched");
+ sa.put(INDEX_B, b);
+ sa.put(INDEX_C, b);
+ tester.verify(5, "Added b twice");
+ b.tick();
+ tester.verify(6, "Changed b - single notification");
+ sa.remove(INDEX_C);
+ tester.verify(7, "Removed first b");
+ b.tick();
+ tester.verify(8, "Changed b - single notification");
+ sa.remove(INDEX_B);
+ tester.verify(9, "Removed second b");
+ b.tick();
+ tester.verify(9, "Updated b - no change");
+ sa.clear();
+ tester.verify(10, "Cleared array");
+ b.tick();
+ tester.verify(10, "Change to b not in array");
+
+ // Special methods
+ sa.put(INDEX_A, a);
+ sa.put(INDEX_B, b);
+ sa.put(INDEX_C, c);
+ tester.verify(13, "Added c");
+ c.tick();
+ tester.verify(14, "Ticked c");
+ sa.setValueAt(sa.indexOfKey(INDEX_C), d);
+ tester.verify(15, "Replaced c with d");
+ c.tick();
+ d.tick();
+ tester.verify(16, "Ticked d and c (c not registered)");
+ sa.append(INDEX_D, c);
+ tester.verify(17, "Append c");
+ c.tick();
+ d.tick();
+ tester.verify(19, "Ticked d and c");
+ assertEquals("Verify four elements", 4, sa.size());
+ // Figure out which elements are at which indices.
+ Leaf[] x = new Leaf[4];
+ for (int i = 0; i < 4; i++) {
+ x[i] = sa.valueAt(i);
+ }
+ sa.removeAtRange(0, 2);
+ tester.verify(20, "Removed two elements in one operation");
+ x[0].tick();
+ x[1].tick();
+ tester.verify(20, "Ticked two removed elements");
+ x[2].tick();
+ x[3].tick();
+ tester.verify(22, "Ticked two remaining elements");
+
+ sa = null;
+
+ // Test WatchedSparseBooleanArray
+ WatchedSparseBooleanArray sb = new WatchedSparseBooleanArray();
+ tester = new Tester(sb, "WatchedSparseBooleanArray");
+ tester.verify(0, "Initial array - no registration");
+ sb.put(INDEX_A, true);
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ tester.verify(0, "Updates with no registration");
+ sb.put(INDEX_B, true);
+ tester.verify(1, "Updates with registration");
+ sb.put(INDEX_B, true);
+ tester.verify(1, "Null update");
+ sb.put(INDEX_B, false);
+ sb.put(INDEX_C, true);
+ tester.verify(3, "Updates with registration");
+ // Special methods
+ sb.put(INDEX_C, true);
+ tester.verify(3, "Added true, no change");
+ sb.setValueAt(sb.indexOfKey(INDEX_C), false);
+ tester.verify(4, "Replaced true with false");
+ sb.append(INDEX_D, true);
+ tester.verify(5, "Append true");
+
+ sb = null;
+ }
+}
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 4439f998a527..e5646db7731f 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -25,6 +25,9 @@ android_test {
"hamcrest-library",
"testables",
"truth-prebuilt",
+ // TODO: remove once Android migrates to JUnit 4.12,
+ // which provides assertThrows
+ "testng",
],
libs: [
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index 88b1d191dc4d..4df469e79814 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -16,8 +16,46 @@
package com.android.server;
+import static android.app.UiModeManager.MODE_NIGHT_AUTO;
+import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
+import static android.app.UiModeManager.MODE_NIGHT_NO;
+import static android.app.UiModeManager.MODE_NIGHT_YES;
+import static android.app.UiModeManager.PROJECTION_TYPE_ALL;
+import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
+import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
+
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.empty;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+import static org.testng.Assert.assertThrows;
+
import android.Manifest;
import android.app.AlarmManager;
+import android.app.IOnProjectionStateChangeListener;
import android.app.IUiModeManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -25,10 +63,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Handler;
+import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
@@ -40,44 +78,24 @@ import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
import com.android.server.wm.WindowManagerInternal;
+
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
+import java.util.List;
import java.util.function.Consumer;
-import static android.app.UiModeManager.MODE_NIGHT_AUTO;
-import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
-import static android.app.UiModeManager.MODE_NIGHT_NO;
-import static android.app.UiModeManager.MODE_NIGHT_YES;
-import static junit.framework.TestCase.assertFalse;
-import static junit.framework.TestCase.assertTrue;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.notNull;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-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 static org.mockito.MockitoAnnotations.initMocks;
-
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class UiModeManagerServiceTest extends UiServiceTestCase {
+ private static final String PACKAGE_NAME = "Diane Coffee";
private UiModeManagerService mUiManagerService;
private IUiModeManager mService;
@Mock
@@ -100,6 +118,10 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
private TwilightState mTwilightState;
@Mock
PowerManagerInternal mLocalPowerManager;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private IBinder mBinder;
private BroadcastReceiver mScreenOffCallback;
private BroadcastReceiver mTimeChangedCallback;
@@ -124,6 +146,7 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
.thenReturn(new PowerSaveState.Builder().setBatterySaverEnabled(false).build());
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPowerManager.isInteractive()).thenReturn(true);
when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
when(mTwilightManager.getLastTwilightState()).thenReturn(mTwilightState);
@@ -156,8 +179,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
addLocalService(PowerManagerInternal.class, mLocalPowerManager);
addLocalService(TwilightManager.class, mTwilightManager);
- mUiManagerService = new UiModeManagerService(mContext, true,
- mTwilightManager);
+ mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true,
+ mTwilightManager, new TestInjector());
try {
mUiManagerService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
} catch (SecurityException e) {/* ignore for permission denial */}
@@ -449,4 +472,353 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
return (mUiManagerService.getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_YES) != 0;
}
+
+ @Test
+ public void requestProjection_failsForBogusPackageName() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+ .thenReturn(TestInjector.CALLING_UID + 1);
+
+ assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
+ PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
+ assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void requestProjection_failsIfNameNotFound() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+ .thenThrow(new PackageManager.NameNotFoundException());
+
+ assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
+ PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
+ assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void requestProjection_failsIfNoProjectionTypes() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mService.requestProjection(mBinder, PROJECTION_TYPE_NONE, PACKAGE_NAME));
+ verify(mContext, never()).enforceCallingPermission(
+ eq(Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION), any());
+ verifyZeroInteractions(mBinder);
+ assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void requestProjection_failsIfMultipleProjectionTypes() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+
+ // Don't use PROJECTION_TYPE_ALL because that's actually == -1 and will fail the > 0 check.
+ int multipleProjectionTypes = PROJECTION_TYPE_AUTOMOTIVE | 0x0002 | 0x0004;
+
+ assertThrows(IllegalArgumentException.class,
+ () -> mService.requestProjection(mBinder, multipleProjectionTypes, PACKAGE_NAME));
+ verify(mContext, never()).enforceCallingPermission(
+ eq(Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION), any());
+ verifyZeroInteractions(mBinder);
+ assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void requestProjection_enforcesToggleAutomotiveProjectionPermission() throws Exception {
+ doThrow(new SecurityException()).when(mPackageManager).getPackageUid(PACKAGE_NAME, 0);
+
+ assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
+ PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
+ assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void requestProjection_automotive_failsIfAlreadySetByOtherPackage() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
+
+ String otherPackage = "Raconteurs";
+ when(mPackageManager.getPackageUid(otherPackage, 0)).thenReturn(TestInjector.CALLING_UID);
+ assertFalse(mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, otherPackage));
+ assertThat(mService.getProjectingPackages(PROJECTION_TYPE_AUTOMOTIVE),
+ contains(PACKAGE_NAME));
+ }
+
+ @Test
+ public void requestProjection_failsIfCannotLinkToDeath() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ doThrow(new RemoteException()).when(mBinder).linkToDeath(any(), anyInt());
+
+ assertFalse(mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
+ assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void requestProjection() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ // Should work for all powers of two.
+ for (int p = 1; p < PROJECTION_TYPE_ALL; p = p * 2) {
+ assertTrue(mService.requestProjection(mBinder, p, PACKAGE_NAME));
+ assertTrue((mService.getActiveProjectionTypes() & p) != 0);
+ assertThat(mService.getProjectingPackages(p), contains(PACKAGE_NAME));
+ // Subsequent calls should still succeed.
+ assertTrue(mService.requestProjection(mBinder, p, PACKAGE_NAME));
+ }
+ assertEquals(PROJECTION_TYPE_ALL, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void releaseProjection_failsForBogusPackageName() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
+
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+ .thenReturn(TestInjector.CALLING_UID + 1);
+
+ assertThrows(SecurityException.class, () -> mService.releaseProjection(
+ PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
+ assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void releaseProjection_failsIfNameNotFound() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0))
+ .thenThrow(new PackageManager.NameNotFoundException());
+
+ assertThrows(SecurityException.class, () -> mService.releaseProjection(
+ PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
+ assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void releaseProjection_enforcesToggleAutomotiveProjectionPermission() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
+ doThrow(new SecurityException()).when(mContext).enforceCallingPermission(
+ eq(Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION), any());
+
+ // Should not be enforced for other types of projection.
+ int nonAutomotiveProjectionType = PROJECTION_TYPE_AUTOMOTIVE * 2;
+ mService.releaseProjection(nonAutomotiveProjectionType, PACKAGE_NAME);
+ assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
+
+ assertThrows(SecurityException.class, () -> mService.requestProjection(mBinder,
+ PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
+ assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void releaseProjection() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ // Should work for all powers of two.
+ for (int p = 1; p < PROJECTION_TYPE_ALL; p = p * 2) {
+ mService.requestProjection(mBinder, p, PACKAGE_NAME);
+ }
+ assertEquals(PROJECTION_TYPE_ALL, mService.getActiveProjectionTypes());
+
+ assertTrue(mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME));
+ int everythingButAutomotive = PROJECTION_TYPE_ALL & ~PROJECTION_TYPE_AUTOMOTIVE;
+ assertEquals(everythingButAutomotive, mService.getActiveProjectionTypes());
+
+ for (int p = 1; p < PROJECTION_TYPE_ALL; p = p * 2) {
+ assertEquals(p != PROJECTION_TYPE_AUTOMOTIVE,
+ (boolean) mService.releaseProjection(p, PACKAGE_NAME));
+ }
+
+ assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void binderDeath_releasesProjection() throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ for (int p = 1; p < PROJECTION_TYPE_ALL; p = p * 2) {
+ mService.requestProjection(mBinder, p, PACKAGE_NAME);
+ }
+ assertEquals(PROJECTION_TYPE_ALL, mService.getActiveProjectionTypes());
+ ArgumentCaptor<IBinder.DeathRecipient> deathRecipientCaptor = ArgumentCaptor.forClass(
+ IBinder.DeathRecipient.class);
+ verify(mBinder, atLeastOnce()).linkToDeath(deathRecipientCaptor.capture(), anyInt());
+
+ // Wipe them out. All of them.
+ deathRecipientCaptor.getAllValues().forEach(IBinder.DeathRecipient::binderDied);
+ assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void getActiveProjectionTypes() throws Exception {
+ assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
+ mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ assertEquals(PROJECTION_TYPE_NONE, mService.getActiveProjectionTypes());
+ }
+
+ @Test
+ public void getProjectingPackages() throws Exception {
+ assertTrue(mService.getProjectingPackages(PROJECTION_TYPE_ALL).isEmpty());
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ assertEquals(1, mService.getProjectingPackages(PROJECTION_TYPE_AUTOMOTIVE).size());
+ assertEquals(1, mService.getProjectingPackages(PROJECTION_TYPE_ALL).size());
+ assertThat(mService.getProjectingPackages(PROJECTION_TYPE_AUTOMOTIVE),
+ contains(PACKAGE_NAME));
+ assertThat(mService.getProjectingPackages(PROJECTION_TYPE_ALL), contains(PACKAGE_NAME));
+ mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ assertThat(mService.getProjectingPackages(PROJECTION_TYPE_ALL), empty());
+ }
+
+ @Test
+ public void addOnProjectionStateChangeListener_enforcesReadProjStatePermission() {
+ doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.READ_PROJECTION_STATE), any());
+ IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+
+ assertThrows(SecurityException.class, () -> mService.addOnProjectionStateChangeListener(
+ listener, PROJECTION_TYPE_ALL));
+ }
+
+ @Test
+ public void addOnProjectionStateChangeListener_callsListenerIfProjectionActive()
+ throws Exception {
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ assertEquals(PROJECTION_TYPE_AUTOMOTIVE, mService.getActiveProjectionTypes());
+
+ IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ when(listener.asBinder()).thenReturn(mBinder); // Any binder will do
+ mService.addOnProjectionStateChangeListener(listener, PROJECTION_TYPE_ALL);
+ verify(listener).onProjectionStateChanged(eq(PROJECTION_TYPE_AUTOMOTIVE),
+ eq(List.of(PACKAGE_NAME)));
+ }
+
+ @Test
+ public void removeOnProjectionStateChangeListener_enforcesReadProjStatePermission() {
+ doThrow(new SecurityException()).when(mContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.READ_PROJECTION_STATE), any());
+ IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+
+ assertThrows(SecurityException.class, () -> mService.removeOnProjectionStateChangeListener(
+ listener));
+ }
+
+ @Test
+ public void removeOnProjectionStateChangeListener() throws Exception {
+ IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ when(listener.asBinder()).thenReturn(mBinder); // Any binder will do.
+ mService.addOnProjectionStateChangeListener(listener, PROJECTION_TYPE_ALL);
+
+ mService.removeOnProjectionStateChangeListener(listener);
+ // Now set automotive projection, should not call back.
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ verify(listener, never()).onProjectionStateChanged(anyInt(), any());
+ }
+
+ @Test
+ public void projectionStateChangeListener_calledWhenStateChanges() throws Exception {
+ IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ when(listener.asBinder()).thenReturn(mBinder); // Any binder will do.
+ mService.addOnProjectionStateChangeListener(listener, PROJECTION_TYPE_ALL);
+ verify(listener, atLeastOnce()).asBinder(); // Called twice during register.
+
+ // No calls initially, no projection state set.
+ verifyNoMoreInteractions(listener);
+
+ // Now set automotive projection, should call back.
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ verify(listener).onProjectionStateChanged(eq(PROJECTION_TYPE_AUTOMOTIVE),
+ eq(List.of(PACKAGE_NAME)));
+
+ // Subsequent calls that are noops do nothing.
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ int unsetProjectionType = 0x0002;
+ mService.releaseProjection(unsetProjectionType, PACKAGE_NAME);
+ verifyNoMoreInteractions(listener);
+
+ // Release should call back though.
+ mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ verify(listener).onProjectionStateChanged(eq(PROJECTION_TYPE_NONE),
+ eq(List.of()));
+
+ // But only the first time.
+ mService.releaseProjection(PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ verifyNoMoreInteractions(listener);
+ }
+
+ @Test
+ public void projectionStateChangeListener_calledForAnyRelevantStateChange() throws Exception {
+ int fakeProjectionType = 0x0002;
+ int otherFakeProjectionType = 0x0004;
+ String otherPackageName = "Internet Arms";
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ when(mPackageManager.getPackageUid(otherPackageName, 0))
+ .thenReturn(TestInjector.CALLING_UID);
+ IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ when(listener.asBinder()).thenReturn(mBinder); // Any binder will do.
+ IOnProjectionStateChangeListener listener2 = mock(IOnProjectionStateChangeListener.class);
+ when(listener2.asBinder()).thenReturn(mBinder); // Any binder will do.
+ mService.addOnProjectionStateChangeListener(listener, fakeProjectionType);
+ mService.addOnProjectionStateChangeListener(listener2,
+ fakeProjectionType | otherFakeProjectionType);
+ verify(listener, atLeastOnce()).asBinder(); // Called twice during register.
+ verify(listener2, atLeastOnce()).asBinder(); // Called twice during register.
+
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ verifyNoMoreInteractions(listener, listener2);
+
+ // fakeProjectionType should trigger both.
+ mService.requestProjection(mBinder, fakeProjectionType, PACKAGE_NAME);
+ verify(listener).onProjectionStateChanged(eq(fakeProjectionType),
+ eq(List.of(PACKAGE_NAME)));
+ verify(listener2).onProjectionStateChanged(eq(fakeProjectionType),
+ eq(List.of(PACKAGE_NAME)));
+
+ // otherFakeProjectionType should only trigger the second listener.
+ mService.requestProjection(mBinder, otherFakeProjectionType, otherPackageName);
+ verifyNoMoreInteractions(listener);
+ verify(listener2).onProjectionStateChanged(
+ eq(fakeProjectionType | otherFakeProjectionType),
+ eq(List.of(PACKAGE_NAME, otherPackageName)));
+
+ // Turning off fakeProjectionType should trigger both again.
+ mService.releaseProjection(fakeProjectionType, PACKAGE_NAME);
+ verify(listener).onProjectionStateChanged(eq(PROJECTION_TYPE_NONE), eq(List.of()));
+ verify(listener2).onProjectionStateChanged(eq(otherFakeProjectionType),
+ eq(List.of(otherPackageName)));
+
+ // Turning off otherFakeProjectionType should only trigger the second listener.
+ mService.releaseProjection(otherFakeProjectionType, otherPackageName);
+ verifyNoMoreInteractions(listener);
+ verify(listener2).onProjectionStateChanged(eq(PROJECTION_TYPE_NONE), eq(List.of()));
+ }
+
+ @Test
+ public void projectionStateChangeListener_unregisteredOnDeath() throws Exception {
+ IOnProjectionStateChangeListener listener = mock(IOnProjectionStateChangeListener.class);
+ IBinder listenerBinder = mock(IBinder.class);
+ when(listener.asBinder()).thenReturn(listenerBinder);
+ mService.addOnProjectionStateChangeListener(listener, PROJECTION_TYPE_ALL);
+ ArgumentCaptor<IBinder.DeathRecipient> listenerDeathRecipient = ArgumentCaptor.forClass(
+ IBinder.DeathRecipient.class);
+ verify(listenerBinder).linkToDeath(listenerDeathRecipient.capture(), anyInt());
+
+ // Now kill the binder for the listener. This should remove it from the list of listeners.
+ listenerDeathRecipient.getValue().binderDied();
+ when(mPackageManager.getPackageUid(PACKAGE_NAME, 0)).thenReturn(TestInjector.CALLING_UID);
+ mService.requestProjection(mBinder, PROJECTION_TYPE_AUTOMOTIVE, PACKAGE_NAME);
+ verify(listener, never()).onProjectionStateChanged(anyInt(), any());
+ }
+
+ private static class TestInjector extends UiModeManagerService.Injector {
+ private static final int CALLING_UID = 8675309;
+
+ public int getCallingUid() {
+ return CALLING_UID;
+ }
+ }
}
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 87aaba2b164a..70d3f988f1f7 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4923,6 +4923,32 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testDontCallShowToastAgainOnTheSameCustomToast() throws Exception {
+ final String testPackage = "testPackageName";
+ assertEquals(0, mService.mToastQueue.size());
+ mService.isSystemUid = false;
+
+ // package is not suspended
+ when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+ .thenReturn(false);
+
+ setAppInForegroundForToasts(mUid, true);
+
+ Binder token = new Binder();
+ ITransientNotification callback = mock(ITransientNotification.class);
+ INotificationManager nmService = (INotificationManager) mService.mService;
+
+ // first time trying to show the toast, showToast gets called
+ nmService.enqueueToast(testPackage, token, callback, 2000, 0);
+ verify(callback, times(1)).show(any());
+
+ // second time trying to show the same toast, showToast isn't called again (total number of
+ // invocations stays at one)
+ nmService.enqueueToast(testPackage, token, callback, 2000, 0);
+ verify(callback, times(1)).show(any());
+ }
+
+ @Test
public void testAllowForegroundTextToasts() throws Exception {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
@@ -4959,6 +4985,33 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testDontCallShowToastAgainOnTheSameTextToast() throws Exception {
+ final String testPackage = "testPackageName";
+ assertEquals(0, mService.mToastQueue.size());
+ mService.isSystemUid = false;
+
+ // package is not suspended
+ when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+ .thenReturn(false);
+
+ setAppInForegroundForToasts(mUid, true);
+
+ Binder token = new Binder();
+ INotificationManager nmService = (INotificationManager) mService.mService;
+
+ // first time trying to show the toast, showToast gets called
+ nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
+ verify(mStatusBar, times(1))
+ .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+
+ // second time trying to show the same toast, showToast isn't called again (total number of
+ // invocations stays at one)
+ nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
+ verify(mStatusBar, times(1))
+ .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
+ }
+
+ @Test
public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws
Exception {
final String testPackage = "testPackageName";
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 93666b4c46fe..7b9ccae794f3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -59,9 +59,9 @@ import static com.android.server.wm.Task.ActivityState.RESUMED;
import static com.android.server.wm.Task.ActivityState.STARTED;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
-import static com.android.server.wm.Task.STACK_VISIBILITY_INVISIBLE;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
import static com.google.common.truth.Truth.assertThat;
@@ -516,13 +516,13 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.setState(Task.ActivityState.STOPPED, "Testing");
spyOn(mStack);
- doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
+ doReturn(TASK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
- doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
+ doReturn(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
- doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
+ doReturn(TASK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
}
@@ -535,7 +535,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent());
topActivity.finishing = true;
- doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
+ doReturn(TASK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
assertEquals(false, mActivity.shouldPauseActivity(null /*activeActivity */));
}
@@ -1127,7 +1127,8 @@ public class ActivityRecordTests extends WindowTestsBase {
topActivity.setState(RESUMED, "true");
doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
any() /* starting */, anyInt() /* configChanges */,
- anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
+ anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */,
+ anyBoolean() /* userLeaving */);
topActivity.setShowWhenLocked(true);
// Verify the stack-top activity is occluded keyguard.
@@ -1173,7 +1174,7 @@ public class ActivityRecordTests extends WindowTestsBase {
secondActivity.completeFinishing("test");
verify(secondActivity.mDisplayContent).ensureActivitiesVisible(null /* starting */,
0 /* configChanges */ , false /* preserveWindows */,
- true /* notifyClients */);
+ true /* notifyClients */, false /* userLeaving */);
// Finish the first activity
firstActivity.finishing = true;
@@ -1181,7 +1182,7 @@ public class ActivityRecordTests extends WindowTestsBase {
firstActivity.completeFinishing("test");
verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */,
0 /* configChanges */ , false /* preserveWindows */,
- true /* notifyClients */);
+ true /* notifyClients */, false /* userLeaving */);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 3c5b9f9cee05..faf4f5217672 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -43,10 +43,10 @@ import static com.android.server.wm.Task.ActivityState.RESUMED;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
-import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
-import static com.android.server.wm.Task.STACK_VISIBILITY_INVISIBLE;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE;
-import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+import static com.android.server.wm.Task.REPARENT_MOVE_ROOT_TASK_TO_FRONT;
+import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
import static com.android.server.wm.TaskDisplayArea.getStackAbove;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -123,7 +123,7 @@ public class ActivityStackTests extends WindowTestsBase {
final Task destStack = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mTask.reparent(destStack, true /* toTop */, Task.REPARENT_KEEP_STACK_AT_FRONT,
+ mTask.reparent(destStack, true /* toTop */, Task.REPARENT_KEEP_ROOT_TASK_AT_FRONT,
false /* animate */, true /* deferResume*/,
"testResumedActivityFromTaskReparenting");
@@ -140,7 +140,7 @@ public class ActivityStackTests extends WindowTestsBase {
final Task destStack = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mTask.reparent(destStack, true /*toTop*/, REPARENT_MOVE_STACK_TO_FRONT, false, false,
+ mTask.reparent(destStack, true /*toTop*/, REPARENT_MOVE_ROOT_TASK_TO_FRONT, false, false,
"testResumedActivityFromActivityReparenting");
assertNull(mStack.getResumedActivity());
@@ -418,10 +418,10 @@ public class ActivityStackTests extends WindowTestsBase {
assertFalse(homeStack.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
// Home stack should be visible if one of the halves of split-screen is translucent.
@@ -429,11 +429,11 @@ public class ActivityStackTests extends WindowTestsBase {
assertTrue(homeStack.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
homeStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
final Task splitScreenSecondary2 =
@@ -444,9 +444,9 @@ public class ActivityStackTests extends WindowTestsBase {
doReturn(false).when(splitScreenSecondary2).isTranslucent(any());
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
// First split-screen secondary should be visible behind another translucent split-screen
@@ -454,9 +454,9 @@ public class ActivityStackTests extends WindowTestsBase {
doReturn(true).when(splitScreenSecondary2).isTranslucent(any());
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
final Task assistantStack = createStackForShouldBeVisibleTest(
@@ -469,13 +469,13 @@ public class ActivityStackTests extends WindowTestsBase {
assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
assistantStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
// Split-screen stacks should be visible behind a translucent fullscreen stack.
@@ -484,13 +484,13 @@ public class ActivityStackTests extends WindowTestsBase {
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
assistantStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitScreenSecondary2.getVisibility(null /* starting */));
// Assistant stack shouldn't be visible behind translucent split-screen stack,
@@ -505,25 +505,25 @@ public class ActivityStackTests extends WindowTestsBase {
assertTrue(assistantStack.shouldBeVisible(null /* starting */));
assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
assistantStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
} else {
assertFalse(assistantStack.shouldBeVisible(null /* starting */));
assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
assistantStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
splitScreenSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
splitScreenSecondary2.getVisibility(null /* starting */));
}
}
@@ -548,33 +548,33 @@ public class ActivityStackTests extends WindowTestsBase {
// Re-parent home to split secondary.
homeStack.reparent(splitSecondary, POSITION_TOP);
// Current tasks should be visible.
- assertEquals(STACK_VISIBILITY_VISIBLE, splitPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE, splitSecondary.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, splitPrimary.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, splitSecondary.getVisibility(null /* starting */));
// Home task should still be visible even though it is a child of another visible task.
- assertEquals(STACK_VISIBILITY_VISIBLE, homeStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, homeStack.getVisibility(null /* starting */));
// Add fullscreen translucent task that partially occludes split tasks
final Task translucentStack = createStandardStackForVisibilityTest(
WINDOWING_MODE_FULLSCREEN, true /* translucent */);
// Fullscreen translucent task should be visible
- assertEquals(STACK_VISIBILITY_VISIBLE, translucentStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, translucentStack.getVisibility(null /* starting */));
// Split tasks should be visible behind translucent
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitPrimary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
splitSecondary.getVisibility(null /* starting */));
// Home task should be visible behind translucent since its parent is visible behind
// translucent.
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
homeStack.getVisibility(null /* starting */));
// Hide split-secondary
splitSecondary.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, true /* set */);
// Home split secondary and home task should be invisible.
- assertEquals(STACK_VISIBILITY_INVISIBLE, splitSecondary.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_INVISIBLE, splitSecondary.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */));
}
@Test
@@ -586,9 +586,9 @@ public class ActivityStackTests extends WindowTestsBase {
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
bottomStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
translucentStack.getVisibility(null /* starting */));
}
@@ -604,10 +604,10 @@ public class ActivityStackTests extends WindowTestsBase {
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- assertEquals(STACK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
translucentStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
}
@Test
@@ -622,10 +622,10 @@ public class ActivityStackTests extends WindowTestsBase {
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- assertEquals(STACK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
opaqueStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
translucentStack.getVisibility(null /* starting */));
}
@@ -638,9 +638,9 @@ public class ActivityStackTests extends WindowTestsBase {
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
true /* translucent */);
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
bottomTranslucentStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
translucentStack.getVisibility(null /* starting */));
}
@@ -653,9 +653,9 @@ public class ActivityStackTests extends WindowTestsBase {
createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
false /* translucent */);
- assertEquals(STACK_VISIBILITY_INVISIBLE,
+ assertEquals(TASK_VISIBILITY_INVISIBLE,
bottomTranslucentStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
}
@Test
@@ -669,15 +669,15 @@ public class ActivityStackTests extends WindowTestsBase {
final Task pinnedStack = createStackForShouldBeVisibleTest(mDefaultTaskDisplayArea,
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ assertEquals(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
bottomStack.getVisibility(null /* starting */));
- assertEquals(STACK_VISIBILITY_VISIBLE,
+ assertEquals(TASK_VISIBILITY_VISIBLE,
translucentStack.getVisibility(null /* starting */));
// Add an activity to the pinned stack so it isn't considered empty for visibility check.
final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
.setTask(pinnedStack)
.build();
- assertEquals(STACK_VISIBILITY_VISIBLE, pinnedStack.getVisibility(null /* starting */));
+ assertEquals(TASK_VISIBILITY_VISIBLE, pinnedStack.getVisibility(null /* starting */));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 3bd8c2766ee2..5a6e556d4864 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -31,12 +31,15 @@ import static android.app.ActivityManager.START_SWITCHES_CANCELED;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
+import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
@@ -304,7 +307,12 @@ public class ActivityStarterTests extends WindowTestsBase {
}
private ActivityStarter prepareStarter(@Intent.Flags int launchFlags) {
- return prepareStarter(launchFlags, true /* mockGetLaunchStack */);
+ return prepareStarter(launchFlags, true /* mockGetLaunchStack */, LAUNCH_MULTIPLE);
+ }
+
+ private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
+ boolean mockGetLaunchStack) {
+ return prepareStarter(launchFlags, mockGetLaunchStack, LAUNCH_MULTIPLE);
}
/**
@@ -318,7 +326,7 @@ public class ActivityStarterTests extends WindowTestsBase {
* @return A {@link ActivityStarter} with default setup.
*/
private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
- boolean mockGetLaunchStack) {
+ boolean mockGetLaunchStack, int launchMode) {
// always allow test to start activity.
doReturn(true).when(mSupervisor).checkStartAnyActivityPermission(
any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
@@ -362,6 +370,7 @@ public class ActivityStarterTests extends WindowTestsBase {
info.applicationInfo = new ApplicationInfo();
info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
+ info.launchMode = launchMode;
return new ActivityStarter(mController, mAtm,
mAtm.mStackSupervisor, mock(ActivityStartInterceptor.class))
@@ -416,7 +425,8 @@ public class ActivityStarterTests extends WindowTestsBase {
@Test
public void testSplitScreenDeliverToTop() {
final ActivityStarter starter = prepareStarter(
- FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
+ FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP,
+ false /* mockGetLaunchStack */);
final ActivityRecord splitPrimaryFocusActivity =
new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord splitSecondReusableActivity =
@@ -486,7 +496,7 @@ public class ActivityStarterTests extends WindowTestsBase {
final ActivityStarter starter = prepareStarter(0);
final LockTaskController lockTaskController = mAtm.getLockTaskController();
- doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
+ doReturn(true).when(lockTaskController).isNewTaskLockTaskModeViolation(any());
final int result = starter.setReason("testTaskModeViolation").execute();
@@ -584,6 +594,12 @@ public class ActivityStarterTests extends WindowTestsBase {
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
true, false, false, false, false);
+ runAndVerifyBackgroundActivityStartsSubtest(
+ "disallowed_pinned_singleinstance_aborted", true,
+ UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
+ UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
+ false, false, false, false, false, true);
+
}
/**
@@ -647,11 +663,28 @@ public class ActivityStarterTests extends WindowTestsBase {
boolean callerIsTempAllowed,
boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
boolean isCallingUidDeviceOwner) {
+ runAndVerifyBackgroundActivityStartsSubtest(name, shouldHaveAborted, callingUid,
+ callingUidHasVisibleWindow, callingUidProcState, realCallingUid,
+ realCallingUidHasVisibleWindow, realCallingUidProcState,
+ hasForegroundActivities, callerIsRecents, callerIsTempAllowed,
+ callerIsInstrumentingWithBackgroundActivityStartPrivileges,
+ isCallingUidDeviceOwner, false /* isPinnedSingleInstance */);
+ }
+
+ private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
+ int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
+ int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
+ boolean hasForegroundActivities, boolean callerIsRecents,
+ boolean callerIsTempAllowed,
+ boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
+ boolean isCallingUidDeviceOwner,
+ boolean isPinnedSingleInstance) {
// window visibility
doReturn(callingUidHasVisibleWindow).when(mAtm.mWindowManager.mRoot)
.isAnyNonToastWindowVisibleForUid(callingUid);
doReturn(realCallingUidHasVisibleWindow).when(mAtm.mWindowManager.mRoot)
.isAnyNonToastWindowVisibleForUid(realCallingUid);
+
// process importance
doReturn(callingUidProcState).when(mAtm).getUidState(callingUid);
doReturn(realCallingUidProcState).when(mAtm).getUidState(realCallingUid);
@@ -662,8 +695,8 @@ public class ActivityStarterTests extends WindowTestsBase {
ai.uid = callingUid;
ai.packageName = "com.android.test.package";
final WindowProcessController callerApp =
- new WindowProcessController(mAtm, ai, null, callingUid, -1, null, listener);
- callerApp.setHasForegroundActivities(hasForegroundActivities);
+ spy(new WindowProcessController(mAtm, ai, null, callingUid, -1, null, listener));
+ doReturn(hasForegroundActivities).when(callerApp).hasForegroundActivities();
doReturn(callerApp).when(mAtm).getProcessController(caller);
// caller is recents
RecentTasks recentTasks = mock(RecentTasks.class);
@@ -679,9 +712,20 @@ public class ActivityStarterTests extends WindowTestsBase {
// callingUid is the device owner
doReturn(isCallingUidDeviceOwner).when(mAtm).isDeviceOwner(callingUid);
+ int launchMode = LAUNCH_MULTIPLE;
+ if (isPinnedSingleInstance) {
+ final ActivityRecord baseActivity =
+ new ActivityBuilder(mAtm).setCreateTask(true).build();
+ baseActivity.getRootTask()
+ .setWindowingMode(WINDOWING_MODE_PINNED);
+ doReturn(baseActivity).when(mRootWindowContainer).findTask(any(), any());
+ launchMode = LAUNCH_SINGLE_INSTANCE;
+ }
+
final ActivityOptions options = spy(ActivityOptions.makeBasic());
ActivityRecord[] outActivity = new ActivityRecord[1];
- ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
+ ActivityStarter starter = prepareStarter(
+ FLAG_ACTIVITY_NEW_TASK, true, launchMode)
.setCallingPackage("com.whatever.dude")
.setCaller(caller)
.setCallingUid(callingUid)
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 28d5ffe342a0..f77454d440f9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -437,7 +437,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
false /* newTask */, false /* keepCurTransition */, null /* options */);
middle.makeFinishingLocked();
- assertNull(mActivity.startingWindow);
+ assertNull(mActivity.mStartingWindow);
assertHasStartingWindow(middle);
final ActivityRecord top = new ActivityBuilder(mWm.mAtmService)
@@ -449,7 +449,7 @@ public class AppWindowTokenTests extends WindowTestsBase {
mStack.startActivityLocked(top, null /* focusedTopActivity */,
false /* newTask */, false /* keepCurTransition */, null /* options */);
- assertNull(middle.startingWindow);
+ assertNull(middle.mStartingWindow);
assertHasStartingWindow(top);
assertTrue(top.isVisible());
// The activity was visible by mVisibleSetFromTransferredStartingWindow, so after its
@@ -573,14 +573,14 @@ public class AppWindowTokenTests extends WindowTestsBase {
}
private void assertHasStartingWindow(ActivityRecord atoken) {
- assertNotNull(atoken.startingSurface);
+ assertNotNull(atoken.mStartingSurface);
assertNotNull(atoken.mStartingData);
- assertNotNull(atoken.startingWindow);
+ assertNotNull(atoken.mStartingWindow);
}
private void assertNoStartingWindow(ActivityRecord atoken) {
- assertNull(atoken.startingSurface);
- assertNull(atoken.startingWindow);
+ assertNull(atoken.mStartingSurface);
+ assertNull(atoken.mStartingWindow);
assertNull(atoken.mStartingData);
atoken.forAllWindows(windowState -> {
assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
index 4a5a81e89cd7..cfe956f77bd3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaGroupTest.java
@@ -90,7 +90,7 @@ public class DisplayAreaGroupTest extends WindowTestsBase {
}
@Test
- public void testGetOrientation() {
+ public void testGetRequestedOrientationForDisplay() {
doReturn(true).when(mDisplayContent).onDescendantOrientationChanged(any(), any());
mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
@@ -98,21 +98,44 @@ public class DisplayAreaGroupTest extends WindowTestsBase {
mDisplayContent.setBounds(0, 0, 600, 900);
assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
- assertThat(mActivity.getRequestedConfigurationOrientation())
+ assertThat(mActivity.getRequestedConfigurationOrientation(true /* forDisplay */))
.isEqualTo(ORIENTATION_PORTRAIT);
// DisplayAreaGroup is landscape, different from Display
mDisplayAreaGroup.setBounds(0, 0, 600, 450);
assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_LANDSCAPE);
- assertThat(mActivity.getRequestedConfigurationOrientation())
+ assertThat(mActivity.getRequestedConfigurationOrientation(true /* forDisplay */))
.isEqualTo(ORIENTATION_LANDSCAPE);
// DisplayAreaGroup is portrait, same as Display
mDisplayAreaGroup.setBounds(0, 0, 300, 900);
assertThat(mDisplayAreaGroup.getOrientation()).isEqualTo(SCREEN_ORIENTATION_PORTRAIT);
- assertThat(mActivity.getRequestedConfigurationOrientation())
+ assertThat(mActivity.getRequestedConfigurationOrientation(true /* forDisplay */))
+ .isEqualTo(ORIENTATION_PORTRAIT);
+ }
+
+ @Test
+ public void testResolveOverrideConfiguration_reverseOrientationWhenDifferentFromParentRoot() {
+ mDisplayContent.setBounds(0, 0, 600, 900);
+ mDisplayContent.updateOrientation();
+ mDisplayContent.sendNewConfiguration();
+
+ // DAG fills Display
+ assertThat(mDisplayAreaGroup.getConfiguration().orientation)
+ .isEqualTo(ORIENTATION_PORTRAIT);
+
+ // DisplayAreaGroup is landscape, different from Display
+ mDisplayAreaGroup.setBounds(0, 0, 600, 450);
+
+ assertThat(mDisplayAreaGroup.getConfiguration().orientation)
+ .isEqualTo(ORIENTATION_LANDSCAPE);
+
+ // DisplayAreaGroup is portriat, same as Display
+ mDisplayAreaGroup.setBounds(0, 0, 300, 450);
+
+ assertThat(mDisplayAreaGroup.getConfiguration().orientation)
.isEqualTo(ORIENTATION_PORTRAIT);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index 01c1f1f73ee9..04adcd648b14 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.content.ActivityInfoProto.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
@@ -25,7 +27,9 @@ import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
import static com.android.server.wm.DisplayArea.Type.ANY;
import static com.android.server.wm.DisplayArea.Type.BELOW_TASKS;
@@ -41,6 +45,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -54,9 +59,8 @@ import android.view.WindowManager;
import com.google.android.collect.Lists;
-import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
@@ -71,30 +75,22 @@ import java.util.function.Function;
* atest WmTests:DisplayAreaTest
*/
@Presubmit
-public class DisplayAreaTest {
- @Rule
- public SystemServicesTestRule mWmsRule = new SystemServicesTestRule();
-
- private WindowManagerService mWms;
-
- @Before
- public void setup() {
- mWms = mWmsRule.getWindowManagerService();
- }
+@RunWith(WindowTestRunner.class)
+public class DisplayAreaTest extends WindowTestsBase {
@Test
public void testDisplayArea_positionChanged_throwsIfIncompatibleChild() {
- DisplayArea<WindowContainer> parent = new DisplayArea<>(mWms, BELOW_TASKS, "Parent");
- DisplayArea<WindowContainer> child = new DisplayArea<>(mWms, ANY, "Child");
+ DisplayArea<WindowContainer> parent = new DisplayArea<>(mWm, BELOW_TASKS, "Parent");
+ DisplayArea<WindowContainer> child = new DisplayArea<>(mWm, ANY, "Child");
assertThrows(IllegalStateException.class, () -> parent.addChild(child, 0));
}
@Test
public void testType_typeOf() {
- assertEquals(ABOVE_TASKS, typeOf(new DisplayArea<>(mWms, ABOVE_TASKS, "test")));
- assertEquals(ANY, typeOf(new DisplayArea<>(mWms, ANY, "test")));
- assertEquals(BELOW_TASKS, typeOf(new DisplayArea<>(mWms, BELOW_TASKS, "test")));
+ assertEquals(ABOVE_TASKS, typeOf(new DisplayArea<>(mWm, ABOVE_TASKS, "test")));
+ assertEquals(ANY, typeOf(new DisplayArea<>(mWm, ANY, "test")));
+ assertEquals(BELOW_TASKS, typeOf(new DisplayArea<>(mWm, BELOW_TASKS, "test")));
assertEquals(ABOVE_TASKS, typeOf(createWindowToken(TYPE_APPLICATION_OVERLAY)));
assertEquals(ABOVE_TASKS, typeOf(createWindowToken(TYPE_PRESENTATION)));
@@ -134,10 +130,10 @@ public class DisplayAreaTest {
@Test
public void testAsDisplayArea() {
- final WindowContainer windowContainer = new WindowContainer(mWms);
- final DisplayArea<WindowContainer> displayArea = new DisplayArea<>(mWms, ANY, "DA");
+ final WindowContainer windowContainer = new WindowContainer(mWm);
+ final DisplayArea<WindowContainer> displayArea = new DisplayArea<>(mWm, ANY, "DA");
final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(null /* displayContent */,
- mWms, "TDA", FEATURE_DEFAULT_TASK_CONTAINER);
+ mWm, "TDA", FEATURE_DEFAULT_TASK_CONTAINER);
assertThat(windowContainer.asDisplayArea()).isNull();
assertThat(displayArea.asDisplayArea()).isEqualTo(displayArea);
@@ -147,15 +143,15 @@ public class DisplayAreaTest {
@Test
public void testForAllTaskDisplayAreas_onlyTraversesDisplayAreaOfTypeAny() {
final RootDisplayArea root =
- new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWms);
+ new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWm);
final Function<TaskDisplayArea, Boolean> callback0 = tda -> false;
final Consumer<TaskDisplayArea> callback1 = tda -> { };
final BiFunction<TaskDisplayArea, Integer, Integer> callback2 = (tda, result) -> result;
final Function<TaskDisplayArea, TaskDisplayArea> callback3 = tda -> null;
// Don't traverse the child if the current DA has type BELOW_TASKS
- final DisplayArea<WindowContainer> da1 = new DisplayArea<>(mWms, BELOW_TASKS, "DA1");
- final DisplayArea<WindowContainer> da2 = new DisplayArea<>(mWms, BELOW_TASKS, "DA2");
+ final DisplayArea<WindowContainer> da1 = new DisplayArea<>(mWm, BELOW_TASKS, "DA1");
+ final DisplayArea<WindowContainer> da2 = new DisplayArea<>(mWm, BELOW_TASKS, "DA2");
root.addChild(da1, POSITION_BOTTOM);
da1.addChild(da2, POSITION_TOP);
spyOn(da2);
@@ -168,8 +164,8 @@ public class DisplayAreaTest {
verifyZeroInteractions(da2);
// Traverse the child if the current DA has type ANY
- final DisplayArea<WindowContainer> da3 = new DisplayArea<>(mWms, ANY, "DA3");
- final DisplayArea<WindowContainer> da4 = new DisplayArea<>(mWms, ANY, "DA4");
+ final DisplayArea<WindowContainer> da3 = new DisplayArea<>(mWm, ANY, "DA3");
+ final DisplayArea<WindowContainer> da4 = new DisplayArea<>(mWm, ANY, "DA4");
root.addChild(da3, POSITION_TOP);
da3.addChild(da4, POSITION_TOP);
spyOn(da4);
@@ -187,8 +183,8 @@ public class DisplayAreaTest {
callback3, true /* traverseTopToBottom */);
// Don't traverse the child if the current DA has type ABOVE_TASKS
- final DisplayArea<WindowContainer> da5 = new DisplayArea<>(mWms, ABOVE_TASKS, "DA5");
- final DisplayArea<WindowContainer> da6 = new DisplayArea<>(mWms, ABOVE_TASKS, "DA6");
+ final DisplayArea<WindowContainer> da5 = new DisplayArea<>(mWm, ABOVE_TASKS, "DA5");
+ final DisplayArea<WindowContainer> da6 = new DisplayArea<>(mWm, ABOVE_TASKS, "DA6");
root.addChild(da5, POSITION_TOP);
da5.addChild(da6, POSITION_TOP);
spyOn(da6);
@@ -204,17 +200,17 @@ public class DisplayAreaTest {
@Test
public void testForAllTaskDisplayAreas_appliesOnTaskDisplayAreaInOrder() {
final RootDisplayArea root =
- new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWms);
+ new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWm);
final DisplayArea<DisplayArea> da1 =
- new DisplayArea<>(mWms, ANY, "DA1");
+ new DisplayArea<>(mWm, ANY, "DA1");
final DisplayArea<DisplayArea> da2 =
- new DisplayArea<>(mWms, ANY, "DA2");
+ new DisplayArea<>(mWm, ANY, "DA2");
final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */,
- mWms, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
+ mWm, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */,
- mWms, "TDA2", FEATURE_VENDOR_FIRST);
+ mWm, "TDA2", FEATURE_VENDOR_FIRST);
final TaskDisplayArea tda3 = new TaskDisplayArea(null /* displayContent */,
- mWms, "TDA3", FEATURE_VENDOR_FIRST + 1);
+ mWm, "TDA3", FEATURE_VENDOR_FIRST + 1);
root.addChild(da1, POSITION_TOP);
root.addChild(da2, POSITION_TOP);
da1.addChild(tda1, POSITION_TOP);
@@ -304,11 +300,11 @@ public class DisplayAreaTest {
@Test
public void testForAllTaskDisplayAreas_returnsWhenCallbackReturnTrue() {
final RootDisplayArea root =
- new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWms);
+ new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWm);
final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */,
- mWms, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
+ mWm, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */,
- mWms, "TDA2", FEATURE_VENDOR_FIRST);
+ mWm, "TDA2", FEATURE_VENDOR_FIRST);
root.addChild(tda1, POSITION_TOP);
root.addChild(tda2, POSITION_TOP);
@@ -332,11 +328,11 @@ public class DisplayAreaTest {
@Test
public void testReduceOnAllTaskDisplayAreas_returnsTheAccumulativeResult() {
final RootDisplayArea root =
- new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWms);
+ new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWm);
final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */,
- mWms, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
+ mWm, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */,
- mWms, "TDA2", FEATURE_VENDOR_FIRST);
+ mWm, "TDA2", FEATURE_VENDOR_FIRST);
root.addChild(tda1, POSITION_TOP);
root.addChild(tda2, POSITION_TOP);
@@ -358,11 +354,11 @@ public class DisplayAreaTest {
@Test
public void testGetItemFromTaskDisplayAreas_returnsWhenCallbackReturnNotNull() {
final RootDisplayArea root =
- new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWms);
+ new DisplayAreaPolicyBuilderTest.SurfacelessDisplayAreaRoot(mWm);
final TaskDisplayArea tda1 = new TaskDisplayArea(null /* displayContent */,
- mWms, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
+ mWm, "TDA1", FEATURE_DEFAULT_TASK_CONTAINER);
final TaskDisplayArea tda2 = new TaskDisplayArea(null /* displayContent */,
- mWms, "TDA2", FEATURE_VENDOR_FIRST);
+ mWm, "TDA2", FEATURE_VENDOR_FIRST);
root.addChild(tda1, POSITION_TOP);
root.addChild(tda2, POSITION_TOP);
@@ -394,9 +390,9 @@ public class DisplayAreaTest {
parentBounds.right / 2, parentBounds.bottom);
final Rect childBounds2 = new Rect(parentBounds.right / 2, parentBounds.top,
parentBounds.right, parentBounds.bottom);
- TestDisplayArea parentDa = new TestDisplayArea(mWms, parentBounds);
- TestDisplayArea childDa1 = new TestDisplayArea(mWms, childBounds1);
- TestDisplayArea childDa2 = new TestDisplayArea(mWms, childBounds2);
+ TestDisplayArea parentDa = new TestDisplayArea(mWm, parentBounds);
+ TestDisplayArea childDa1 = new TestDisplayArea(mWm, childBounds1);
+ TestDisplayArea childDa2 = new TestDisplayArea(mWm, childBounds2);
parentDa.addChild(childDa1, 0);
parentDa.addChild(childDa2, 1);
@@ -413,7 +409,7 @@ public class DisplayAreaTest {
@Test
public void testGetOrientation() {
- final DisplayArea.Tokens area = new DisplayArea.Tokens(mWms, ABOVE_TASKS, "test");
+ final DisplayArea.Tokens area = new DisplayArea.Tokens(mWm, ABOVE_TASKS, "test");
final WindowToken token = createWindowToken(TYPE_APPLICATION_OVERLAY);
spyOn(token);
doReturn(mock(DisplayContent.class)).when(token).getDisplayContent();
@@ -440,7 +436,7 @@ public class DisplayAreaTest {
@Test
public void testSetIgnoreOrientationRequest() {
- final DisplayArea.Tokens area = new DisplayArea.Tokens(mWms, ABOVE_TASKS, "test");
+ final DisplayArea.Tokens area = new DisplayArea.Tokens(mWm, ABOVE_TASKS, "test");
final WindowToken token = createWindowToken(TYPE_APPLICATION_OVERLAY);
spyOn(token);
doReturn(mock(DisplayContent.class)).when(token).getDisplayContent();
@@ -460,6 +456,28 @@ public class DisplayAreaTest {
assertEquals(ActivityInfo.SCREEN_ORIENTATION_UNSET, area.getOrientation());
}
+ @Test
+ public void testSetIgnoreOrientationRequest_notCallSuperOnDescendantOrientationChanged() {
+ final TaskDisplayArea tda =
+ mDisplayContent.getDefaultTaskDisplayArea();
+ final Task stack =
+ new TaskBuilder(mSupervisor).setOnTop(!ON_TOP).setCreateActivity(true).build();
+ final ActivityRecord activity = stack.getTopNonFinishingActivity();
+
+ tda.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+ verify(tda).onDescendantOrientationChanged(any(), any());
+ verify(mDisplayContent, never()).onDescendantOrientationChanged(any(), any());
+
+ tda.setIgnoreOrientationRequest(false /* ignoreOrientationRequest */);
+ activity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+ verify(tda, times(2)).onDescendantOrientationChanged(any(), any());
+ verify(mDisplayContent).onDescendantOrientationChanged(any(), any());
+ }
+
private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
private TestDisplayArea(WindowManagerService wms, Rect bounds) {
super(wms, ANY, "half display area");
@@ -473,14 +491,14 @@ public class DisplayAreaTest {
}
private WindowState createWindowState(WindowToken token) {
- return new WindowState(mWms, mock(Session.class), new TestIWindow(), token,
+ return new WindowState(mWm, mock(Session.class), new TestIWindow(), token,
null /* parentWindow */, 0 /* appOp */, new WindowManager.LayoutParams(),
View.VISIBLE, 0 /* ownerId */, 0 /* showUserId */,
false /* ownerCanAddInternalSystemWindow */);
}
private WindowToken createWindowToken(int type) {
- return new WindowToken(mWmsRule.getWindowManagerService(), new Binder(),
+ return new WindowToken(mWm, new Binder(),
type, false /* persist */, null /* displayContent */,
false /* canManageTokens */);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index fbfc0e09584b..dc33b75ec57a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1533,11 +1533,12 @@ public class DisplayContentTests extends WindowTestsBase {
// The assertion will fail if DisplayArea#ensureActivitiesVisible is called twice.
assertFalse(called[0]);
called[0] = true;
- mDisplayContent.ensureActivitiesVisible(null, 0, false, false);
+ mDisplayContent.ensureActivitiesVisible(null, 0, false, false, false);
return null;
- }).when(mockTda).ensureActivitiesVisible(any(), anyInt(), anyBoolean(), anyBoolean());
+ }).when(mockTda).ensureActivitiesVisible(any(), anyInt(), anyBoolean(), anyBoolean(),
+ anyBoolean());
- mDisplayContent.ensureActivitiesVisible(null, 0, false, false);
+ mDisplayContent.ensureActivitiesVisible(null, 0, false, false, false);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
new file mode 100644
index 000000000000..b346bb810b2e
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.Nullable;
+import android.platform.test.annotations.Presubmit;
+import android.util.Xml;
+import android.view.Display;
+import android.view.DisplayAddress;
+import android.view.DisplayInfo;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Tests for the {@link DisplayWindowSettingsProvider} class.
+ *
+ * Build/Install/Run:
+ * atest WmTests:DisplayWindowSettingsProviderTests
+ */
+@SmallTest
+@Presubmit
+@WindowTestsBase.UseTestDisplay
+@RunWith(WindowTestRunner.class)
+public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
+ private static final int DISPLAY_PORT = 0xFF;
+ private static final long DISPLAY_MODEL = 0xEEEEEEEEL;
+
+ private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
+
+ private TestStorage mBaseSettingsStorage;
+ private TestStorage mOverrideSettingsStorage;
+
+ private DisplayContent mPrimaryDisplay;
+ private DisplayContent mSecondaryDisplay;
+
+ @Before
+ public void setUp() throws Exception {
+ deleteRecursively(TEST_FOLDER);
+
+ mBaseSettingsStorage = new TestStorage();
+ mOverrideSettingsStorage = new TestStorage();
+
+ mPrimaryDisplay = mWm.getDefaultDisplayContentLocked();
+ mSecondaryDisplay = mDisplayContent;
+ assertNotEquals(Display.DEFAULT_DISPLAY, mSecondaryDisplay.getDisplayId());
+ }
+
+ @After
+ public void tearDown() {
+ deleteRecursively(TEST_FOLDER);
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage() {
+ final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
+ prepareOverrideDisplaySettings(displayIdentifier);
+
+ SettingsEntry expectedSettings = new SettingsEntry();
+ expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED;
+ readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage_LegacyDisplayId() {
+ final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().name;
+ prepareOverrideDisplaySettings(displayIdentifier);
+
+ SettingsEntry expectedSettings = new SettingsEntry();
+ expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED;
+ readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage_LegacyDisplayId_UpdateAfterAccess()
+ throws Exception {
+ // Store display settings with legacy display identifier.
+ final DisplayInfo mPrimaryDisplayInfo = mPrimaryDisplay.getDisplayInfo();
+ final String displayIdentifier = mPrimaryDisplayInfo.name;
+ prepareOverrideDisplaySettings(displayIdentifier);
+
+ // Update settings with new value, should trigger write to injector.
+ DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+ mBaseSettingsStorage, mOverrideSettingsStorage);
+ SettingsEntry overrideSettings = provider.getOverrideSettings(mPrimaryDisplayInfo);
+ overrideSettings.mForcedDensity = 200;
+ provider.updateOverrideSettings(mPrimaryDisplayInfo, overrideSettings);
+ assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
+
+ // Verify that display identifier was updated.
+ final String newDisplayIdentifier = getStoredDisplayAttributeValue(
+ mOverrideSettingsStorage, "name");
+ assertEquals("Display identifier must be updated to use uniqueId",
+ mPrimaryDisplayInfo.uniqueId, newDisplayIdentifier);
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage_UsePortAsId() {
+ final DisplayAddress.Physical displayAddress =
+ DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
+ mPrimaryDisplay.getDisplayInfo().address = displayAddress;
+
+ final String displayIdentifier = "port:" + DISPLAY_PORT;
+ prepareOverrideDisplaySettings(displayIdentifier, true /* usePortAsId */);
+
+ SettingsEntry expectedSettings = new SettingsEntry();
+ expectedSettings.mWindowingMode = WINDOWING_MODE_PINNED;
+ readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+ }
+
+ @Test
+ public void testReadingDisplaySettingsFromStorage_UsePortAsId_IncorrectAddress() {
+ final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().uniqueId;
+ prepareOverrideDisplaySettings(displayIdentifier, true /* usePortAsId */);
+
+ mPrimaryDisplay.getDisplayInfo().address = DisplayAddress.fromPhysicalDisplayId(123456);
+
+ // Verify that the entry is not matched and default settings are returned instead.
+ SettingsEntry expectedSettings = new SettingsEntry();
+ readAndAssertExpectedSettings(mPrimaryDisplay, expectedSettings);
+ }
+
+ @Test
+ public void testWritingDisplaySettingsToStorage() throws Exception {
+ final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
+
+ // Write some settings to storage.
+ DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+ mBaseSettingsStorage, mOverrideSettingsStorage);
+ SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
+ overrideSettings.mShouldShowSystemDecors = true;
+ overrideSettings.mShouldShowIme = true;
+ provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
+
+ // Verify that settings were stored correctly.
+ assertEquals("Attribute value must be stored", secondaryDisplayInfo.uniqueId,
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "name"));
+ assertEquals("Attribute value must be stored", "true",
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowSystemDecors"));
+ assertEquals("Attribute value must be stored", "true",
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowIme"));
+ }
+
+ @Test
+ public void testWritingDisplaySettingsToStorage_UsePortAsId() throws Exception {
+ prepareOverrideDisplaySettings(null /* displayIdentifier */, true /* usePortAsId */);
+
+ // Store config to use port as identifier.
+ final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
+ final DisplayAddress.Physical displayAddress =
+ DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
+ secondaryDisplayInfo.address = displayAddress;
+
+ // Write some settings to storage.
+ DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+ mBaseSettingsStorage, mOverrideSettingsStorage);
+ SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
+ overrideSettings.mShouldShowSystemDecors = true;
+ overrideSettings.mShouldShowIme = true;
+ provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
+
+ // Verify that settings were stored correctly.
+ assertEquals("Attribute value must be stored", "port:" + DISPLAY_PORT,
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "name"));
+ assertEquals("Attribute value must be stored", "true",
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowSystemDecors"));
+ assertEquals("Attribute value must be stored", "true",
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowIme"));
+ }
+
+ /**
+ * Prepares display settings and stores in {@link #mOverrideSettingsStorage}. Uses provided
+ * display identifier and stores windowingMode=WINDOWING_MODE_PINNED.
+ */
+ private void prepareOverrideDisplaySettings(String displayIdentifier) {
+ prepareOverrideDisplaySettings(displayIdentifier, false /* usePortAsId */);
+ }
+
+ private void prepareOverrideDisplaySettings(String displayIdentifier, boolean usePortAsId) {
+ String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<display-settings>\n";
+ if (usePortAsId) {
+ contents += " <config identifier=\"1\"/>\n";
+ }
+ if (displayIdentifier != null) {
+ contents += " <display\n"
+ + " name=\"" + displayIdentifier + "\"\n"
+ + " windowingMode=\"" + WINDOWING_MODE_PINNED + "\"/>\n";
+ }
+ contents += "</display-settings>\n";
+
+ final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+ mOverrideSettingsStorage.setReadStream(is);
+ }
+
+ private void readAndAssertExpectedSettings(DisplayContent displayContent,
+ SettingsEntry expectedSettings) {
+ final DisplayWindowSettingsProvider provider =
+ new DisplayWindowSettingsProvider(mBaseSettingsStorage, mOverrideSettingsStorage);
+ assertEquals(expectedSettings, provider.getSettings(displayContent.getDisplayInfo()));
+ }
+
+ @Nullable
+ private String getStoredDisplayAttributeValue(TestStorage storage, String attr)
+ throws Exception {
+ try (InputStream stream = storage.openRead()) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Do nothing.
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new IllegalStateException("no start tag found");
+ }
+
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("display")) {
+ return parser.getAttributeValue(null, attr);
+ }
+ }
+ } finally {
+ storage.closeRead();
+ }
+ return null;
+ }
+
+ private static boolean deleteRecursively(File file) {
+ boolean fullyDeleted = true;
+ if (file.isFile()) {
+ return file.delete();
+ } else if (file.isDirectory()) {
+ final File[] files = file.listFiles();
+ for (File child : files) {
+ fullyDeleted &= deleteRecursively(child);
+ }
+ fullyDeleted &= file.delete();
+ }
+ return fullyDeleted;
+ }
+
+ /** In-memory storage implementation. */
+ public class TestStorage implements DisplayWindowSettingsProvider.WritableSettingsStorage {
+ private InputStream mReadStream;
+ private ByteArrayOutputStream mWriteStream;
+
+ private boolean mWasSuccessful;
+
+ /**
+ * Returns input stream for reading. By default tries forward the output stream if previous
+ * write was successful.
+ * @see #closeRead()
+ */
+ @Override
+ public InputStream openRead() throws FileNotFoundException {
+ if (mReadStream == null && mWasSuccessful) {
+ mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
+ }
+ if (mReadStream == null) {
+ throw new FileNotFoundException();
+ }
+ if (mReadStream.markSupported()) {
+ mReadStream.mark(Integer.MAX_VALUE);
+ }
+ return mReadStream;
+ }
+
+ /** Must be called after each {@link #openRead} to reset the position in the stream. */
+ void closeRead() throws IOException {
+ if (mReadStream == null) {
+ throw new FileNotFoundException();
+ }
+ if (mReadStream.markSupported()) {
+ mReadStream.reset();
+ }
+ mReadStream = null;
+ }
+
+ /**
+ * Creates new or resets existing output stream for write. Automatically closes previous
+ * read stream, since following reads should happen based on this new write.
+ */
+ @Override
+ public OutputStream startWrite() throws IOException {
+ if (mWriteStream == null) {
+ mWriteStream = new ByteArrayOutputStream();
+ } else {
+ mWriteStream.reset();
+ }
+ if (mReadStream != null) {
+ closeRead();
+ }
+ return mWriteStream;
+ }
+
+ @Override
+ public void finishWrite(OutputStream os, boolean success) {
+ mWasSuccessful = success;
+ try {
+ os.close();
+ } catch (IOException e) {
+ // This method can't throw IOException since the super implementation doesn't, so
+ // we just wrap it in a RuntimeException so we end up crashing the test all the
+ // same.
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Overrides the read stream of the injector. By default it uses current write stream. */
+ private void setReadStream(InputStream is) {
+ mReadStream = is;
+ }
+
+ private boolean wasWriteSuccessful() {
+ return mWasSuccessful;
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index a3d3739a9015..2ca5583c48c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -17,15 +17,12 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DISABLED;
import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_DESTROY;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -40,12 +37,11 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Matchers.eq;
+import android.annotation.NonNull;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.platform.test.annotations.Presubmit;
-import android.util.Xml;
import android.view.Display;
-import android.view.DisplayAddress;
import android.view.DisplayInfo;
import android.view.Surface;
@@ -53,21 +49,14 @@ import androidx.test.filters.SmallTest;
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParser;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
/**
* Tests for the {@link DisplayWindowSettings} class.
@@ -80,12 +69,8 @@ import java.nio.charset.StandardCharsets;
@WindowTestsBase.UseTestDisplay
@RunWith(WindowTestRunner.class)
public class DisplayWindowSettingsTests extends WindowTestsBase {
-
- private static final int DISPLAY_PORT = 0xFF;
- private static final long DISPLAY_MODEL = 0xEEEEEEEEL;
-
- private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
- private DisplayWindowSettings mTarget;
+ private TestSettingsProvider mSettingsProvider;
+ private DisplayWindowSettings mDisplayWindowSettings;
private DisplayInfo mPrivateDisplayInfo;
@@ -93,18 +78,19 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
private DisplayContent mSecondaryDisplay;
private DisplayContent mPrivateDisplay;
- private TestStorage mStorage;
-
@Before
public void setUp() throws Exception {
- deleteRecursively(TEST_FOLDER);
-
+ // TODO(b/121296525): We may want to restore other display settings (not only overscans in
+ // testPersistOverscan*test) on mPrimaryDisplay and mSecondaryDisplay back to default
+ // values after each test finishes, since we are going to reuse a singleton
+ // WindowManagerService instance among all tests that extend {@link WindowTestsBase} class
+ // (b/113239988).
mWm.mAtmService.mSupportsFreeformWindowManagement = false;
mWm.setIsPc(false);
mWm.setForceDesktopModeOnExternalDisplays(false);
- mStorage = new TestStorage();
- mTarget = new DisplayWindowSettings(mWm, mStorage);
+ mSettingsProvider = new TestSettingsProvider();
+ mDisplayWindowSettings = new DisplayWindowSettings(mWm, mSettingsProvider);
mPrimaryDisplay = mWm.getDefaultDisplayContentLocked();
mSecondaryDisplay = mDisplayContent;
@@ -117,20 +103,9 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
assertNotEquals(mSecondaryDisplay.getDisplayId(), mPrivateDisplay.getDisplayId());
}
- @After
- public void tearDown() {
- deleteRecursively(TEST_FOLDER);
-
- // TODO(b/121296525): We may want to restore other display settings (not only overscans in
- // testPersistOverscan*test) on mPrimaryDisplay and mSecondaryDisplay back to default
- // values after each test finishes, since we are going to reuse a singleton
- // WindowManagerService instance among all tests that extend {@link WindowTestsBase} class
- // (b/113239988).
- }
-
@Test
public void testPrimaryDisplayDefaultToFullscreen_NoFreeformSupport() {
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
mPrimaryDisplay.getWindowingMode());
@@ -140,7 +115,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
public void testPrimaryDisplayDefaultToFullscreen_HasFreeformSupport_NonPc_NoDesktopMode() {
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
mPrimaryDisplay.getWindowingMode());
@@ -151,7 +126,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setForceDesktopModeOnExternalDisplays(true);
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
mPrimaryDisplay.getWindowingMode());
@@ -162,20 +137,19 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setIsPc(true);
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
- assertEquals(WINDOWING_MODE_FREEFORM,
- mPrimaryDisplay.getWindowingMode());
+ assertEquals(WINDOWING_MODE_FREEFORM, mPrimaryDisplay.getWindowingMode());
}
@Test
public void testPrimaryDisplayUpdateToFreeform_HasFreeformSupport_IsPc() {
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setIsPc(true);
- mTarget.updateSettingsForDisplay(mPrimaryDisplay);
+ mDisplayWindowSettings.updateSettingsForDisplay(mPrimaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
mPrimaryDisplay.getWindowingMode());
@@ -183,7 +157,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
@Test
public void testSecondaryDisplayDefaultToFullscreen_NoFreeformSupport() {
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
mSecondaryDisplay.getWindowingMode());
@@ -193,7 +167,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
public void testSecondaryDisplayDefaultToFreeform_HasFreeformSupport_NonPc_NoDesktopMode() {
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
mSecondaryDisplay.getWindowingMode());
@@ -204,7 +178,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setForceDesktopModeOnExternalDisplays(true);
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WINDOWING_MODE_FREEFORM,
mSecondaryDisplay.getWindowingMode());
@@ -215,7 +189,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
mWm.mAtmService.mSupportsFreeformWindowManagement = true;
mWm.setIsPc(true);
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(WINDOWING_MODE_FREEFORM,
mSecondaryDisplay.getWindowingMode());
@@ -228,7 +202,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
final int originalDensity = mSecondaryDisplay.mBaseDisplayDensity;
final boolean originalScalingDisabled = mSecondaryDisplay.mDisplayScalingDisabled;
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(originalWidth, mSecondaryDisplay.mBaseDisplayWidth);
assertEquals(originalHeight, mSecondaryDisplay.mBaseDisplayHeight);
@@ -245,8 +219,9 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
return null;
}).when(mWm.mDisplayManagerInternal).getNonOverrideDisplayInfo(anyInt(), any());
- mTarget.setForcedSize(mSecondaryDisplay, 1000 /* width */, 2000 /* height */);
- applySettingsToDisplayByNewInstance(mSecondaryDisplay);
+ mDisplayWindowSettings.setForcedSize(mSecondaryDisplay, 1000 /* width */,
+ 2000 /* height */);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(1000 /* width */, mSecondaryDisplay.mBaseDisplayWidth);
assertEquals(2000 /* height */, mSecondaryDisplay.mBaseDisplayHeight);
@@ -258,8 +233,9 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
@Test
public void testSetForcedDensity() {
- mTarget.setForcedDensity(mSecondaryDisplay, 600 /* density */, 0 /* userId */);
- applySettingsToDisplayByNewInstance(mSecondaryDisplay);
+ mDisplayWindowSettings.setForcedDensity(mSecondaryDisplay, 600 /* density */,
+ 0 /* userId */);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(600 /* density */, mSecondaryDisplay.mBaseDisplayDensity);
@@ -270,8 +246,9 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
@Test
public void testSetForcedScalingMode() {
- mTarget.setForcedScalingMode(mSecondaryDisplay, DisplayContent.FORCE_SCALING_MODE_DISABLED);
- applySettingsToDisplayByNewInstance(mSecondaryDisplay);
+ mDisplayWindowSettings.setForcedScalingMode(mSecondaryDisplay,
+ DisplayContent.FORCE_SCALING_MODE_DISABLED);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertTrue(mSecondaryDisplay.mDisplayScalingDisabled);
@@ -282,7 +259,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
@Test
public void testDefaultToFreeUserRotation() {
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, rotation.getUserRotationMode());
@@ -291,7 +268,7 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
@Test
public void testDefaultTo0DegRotation() {
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(Surface.ROTATION_0, mSecondaryDisplay.getDisplayRotation().getUserRotation());
}
@@ -299,70 +276,68 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
@Test
public void testPrivateDisplayDefaultToDestroyContent() {
assertEquals(REMOVE_CONTENT_MODE_DESTROY,
- mTarget.getRemoveContentModeLocked(mPrivateDisplay));
+ mDisplayWindowSettings.getRemoveContentModeLocked(mPrivateDisplay));
}
@Test
public void testPublicDisplayDefaultToMoveToPrimary() {
assertEquals(REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY,
- mTarget.getRemoveContentModeLocked(mSecondaryDisplay));
+ mDisplayWindowSettings.getRemoveContentModeLocked(mSecondaryDisplay));
}
@Test
public void testDefaultToNotShowWithInsecureKeyguard() {
- assertFalse(mTarget.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
- assertFalse(mTarget.shouldShowWithInsecureKeyguardLocked(mSecondaryDisplay));
+ assertFalse(mDisplayWindowSettings.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
+ assertFalse(mDisplayWindowSettings.shouldShowWithInsecureKeyguardLocked(mSecondaryDisplay));
}
- @Test
+ @Test(expected = IllegalArgumentException.class)
public void testPublicDisplayNotAllowSetShouldShowWithInsecureKeyguard() {
- mTarget.setShouldShowWithInsecureKeyguardLocked(mSecondaryDisplay, true);
-
- assertFalse(mTarget.shouldShowWithInsecureKeyguardLocked(mSecondaryDisplay));
+ mDisplayWindowSettings.setShouldShowWithInsecureKeyguardLocked(mSecondaryDisplay, true);
}
@Test
public void testPrivateDisplayAllowSetShouldShowWithInsecureKeyguard() {
- mTarget.setShouldShowWithInsecureKeyguardLocked(mPrivateDisplay, true);
+ mDisplayWindowSettings.setShouldShowWithInsecureKeyguardLocked(mPrivateDisplay, true);
- assertTrue(mTarget.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
+ assertTrue(mDisplayWindowSettings.shouldShowWithInsecureKeyguardLocked(mPrivateDisplay));
}
@Test
public void testPrimaryDisplayShouldShowSystemDecors() {
- assertTrue(mTarget.shouldShowSystemDecorsLocked(mPrimaryDisplay));
+ assertTrue(mDisplayWindowSettings.shouldShowSystemDecorsLocked(mPrimaryDisplay));
- mTarget.setShouldShowSystemDecorsLocked(mPrimaryDisplay, false);
+ mDisplayWindowSettings.setShouldShowSystemDecorsLocked(mPrimaryDisplay, false);
// Default display should show system decors
- assertTrue(mTarget.shouldShowSystemDecorsLocked(mPrimaryDisplay));
+ assertTrue(mDisplayWindowSettings.shouldShowSystemDecorsLocked(mPrimaryDisplay));
}
@Test
public void testSecondaryDisplayDefaultToNotShowSystemDecors() {
- assertFalse(mTarget.shouldShowSystemDecorsLocked(mSecondaryDisplay));
+ assertFalse(mDisplayWindowSettings.shouldShowSystemDecorsLocked(mSecondaryDisplay));
}
@Test
public void testPrimaryDisplayShouldShowIme() {
- assertTrue(mTarget.shouldShowImeLocked(mPrimaryDisplay));
+ assertTrue(mDisplayWindowSettings.shouldShowImeLocked(mPrimaryDisplay));
- mTarget.setShouldShowImeLocked(mPrimaryDisplay, false);
+ mDisplayWindowSettings.setShouldShowImeLocked(mPrimaryDisplay, false);
- assertTrue(mTarget.shouldShowImeLocked(mPrimaryDisplay));
+ assertTrue(mDisplayWindowSettings.shouldShowImeLocked(mPrimaryDisplay));
}
@Test
public void testSecondaryDisplayDefaultToNotShowIme() {
- assertFalse(mTarget.shouldShowImeLocked(mSecondaryDisplay));
+ assertFalse(mDisplayWindowSettings.shouldShowImeLocked(mSecondaryDisplay));
}
@Test
- public void testPersistUserRotationModeInSameInstance() {
- mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
- Surface.ROTATION_90);
+ public void testSetUserRotationMode() {
+ mDisplayWindowSettings.setUserRotation(mSecondaryDisplay,
+ WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_90);
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation.getUserRotationMode());
@@ -370,48 +345,25 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
}
@Test
- public void testPersistUserRotationInSameInstance() {
- mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
- Surface.ROTATION_90);
+ public void testSetUserRotation() {
+ mDisplayWindowSettings.setUserRotation(mSecondaryDisplay,
+ WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_90);
- mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mSecondaryDisplay);
assertEquals(Surface.ROTATION_90, mSecondaryDisplay.getDisplayRotation().getUserRotation());
}
@Test
- public void testPersistUserRotationModeAcrossInstances() {
- mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
- Surface.ROTATION_270);
-
- applySettingsToDisplayByNewInstance(mSecondaryDisplay);
-
- final DisplayRotation rotation = mSecondaryDisplay.getDisplayRotation();
- assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation.getUserRotationMode());
- assertTrue(rotation.isRotationFrozen());
- }
-
- @Test
- public void testPersistUserRotationAcrossInstances() {
- mTarget.setUserRotation(mSecondaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
- Surface.ROTATION_270);
-
- applySettingsToDisplayByNewInstance(mSecondaryDisplay);
-
- assertEquals(Surface.ROTATION_270,
- mSecondaryDisplay.getDisplayRotation().getUserRotation());
- }
-
- @Test
public void testFixedToUserRotationDefault() {
- mTarget.setUserRotation(mPrimaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
- Surface.ROTATION_0);
+ mDisplayWindowSettings.setUserRotation(mPrimaryDisplay,
+ WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_0);
final DisplayRotation displayRotation = mock(DisplayRotation.class);
spyOn(mPrimaryDisplay);
doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
- mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
verify(displayRotation).restoreSettings(anyInt(), anyInt(),
eq(FIXED_TO_USER_ROTATION_DEFAULT));
@@ -419,13 +371,14 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
@Test
public void testSetFixedToUserRotationDisabled() {
- mTarget.setFixedToUserRotation(mPrimaryDisplay, FIXED_TO_USER_ROTATION_DISABLED);
+ mDisplayWindowSettings.setFixedToUserRotation(mPrimaryDisplay,
+ FIXED_TO_USER_ROTATION_DISABLED);
final DisplayRotation displayRotation = mock(DisplayRotation.class);
spyOn(mPrimaryDisplay);
doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
- applySettingsToDisplayByNewInstance(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
verify(displayRotation).restoreSettings(anyInt(), anyInt(),
eq(FIXED_TO_USER_ROTATION_DISABLED));
@@ -433,120 +386,20 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
@Test
public void testSetFixedToUserRotationEnabled() {
- mTarget.setFixedToUserRotation(mPrimaryDisplay, FIXED_TO_USER_ROTATION_ENABLED);
+ mDisplayWindowSettings.setFixedToUserRotation(mPrimaryDisplay,
+ FIXED_TO_USER_ROTATION_ENABLED);
final DisplayRotation displayRotation = mock(DisplayRotation.class);
spyOn(mPrimaryDisplay);
doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
- applySettingsToDisplayByNewInstance(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
verify(displayRotation).restoreSettings(anyInt(), anyInt(),
eq(FIXED_TO_USER_ROTATION_ENABLED));
}
@Test
- public void testReadingDisplaySettingsFromStorage() {
- final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
- prepareDisplaySettings(displayIdentifier);
-
- readAndAssertDisplaySettings(mPrimaryDisplay);
- }
-
- @Test
- public void testReadingDisplaySettingsFromStorage_LegacyDisplayId() {
- final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().name;
- prepareDisplaySettings(displayIdentifier);
-
- readAndAssertDisplaySettings(mPrimaryDisplay);
- }
-
- @Test
- public void testReadingDisplaySettingsFromStorage_LegacyDisplayId_UpdateAfterAccess()
- throws Exception {
- // Store display settings with legacy display identifier.
- final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().name;
- prepareDisplaySettings(displayIdentifier);
-
- // Update settings with new value, should trigger write to injector.
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
- settings.setRemoveContentModeLocked(mPrimaryDisplay, REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY);
- assertEquals("Settings value must be updated", REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY,
- settings.getRemoveContentModeLocked(mPrimaryDisplay));
- assertTrue(mStorage.wasWriteSuccessful());
-
- // Verify that display identifier was updated.
- final String newDisplayIdentifier = getStoredDisplayAttributeValue("name");
- assertEquals("Display identifier must be updated to use uniqueId",
- mPrimaryDisplay.getDisplayInfo().uniqueId, newDisplayIdentifier);
- }
-
- @Test
- public void testReadingDisplaySettingsFromStorage_UsePortAsId() {
- final DisplayAddress.Physical displayAddress =
- DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
- mPrimaryDisplay.getDisplayInfo().address = displayAddress;
-
- final String displayIdentifier = "port:" + DISPLAY_PORT;
- prepareDisplaySettings(displayIdentifier, true /* usePortAsId */);
-
- readAndAssertDisplaySettings(mPrimaryDisplay);
- }
-
- @Test
- public void testReadingDisplaySettingsFromStorage_UsePortAsId_IncorrectAddress() {
- final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().uniqueId;
- prepareDisplaySettings(displayIdentifier, true /* usePortAsId */);
-
- mPrimaryDisplay.getDisplayInfo().address = DisplayAddress.fromPhysicalDisplayId(123456);
-
- // Verify that the entry is not matched and default settings are returned instead.
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm);
- assertNotEquals("Default setting must be returned for new entry",
- WINDOWING_MODE_PINNED, settings.getWindowingModeLocked(mPrimaryDisplay));
- }
-
- @Test
- public void testWritingDisplaySettingsToStorage() throws Exception {
- // Write some settings to storage.
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
- settings.setShouldShowSystemDecorsLocked(mSecondaryDisplay, true);
- settings.setShouldShowImeLocked(mSecondaryDisplay, true);
- assertTrue(mStorage.wasWriteSuccessful());
-
- // Verify that settings were stored correctly.
- assertEquals("Attribute value must be stored", mSecondaryDisplay.getDisplayInfo().uniqueId,
- getStoredDisplayAttributeValue("name"));
- assertEquals("Attribute value must be stored", "true",
- getStoredDisplayAttributeValue("shouldShowSystemDecors"));
- assertEquals("Attribute value must be stored", "true",
- getStoredDisplayAttributeValue("shouldShowIme"));
- }
-
- @Test
- public void testWritingDisplaySettingsToStorage_UsePortAsId() throws Exception {
- // Store config to use port as identifier.
- final DisplayAddress.Physical displayAddress =
- DisplayAddress.fromPortAndModel(DISPLAY_PORT, DISPLAY_MODEL);
- mSecondaryDisplay.getDisplayInfo().address = displayAddress;
- prepareDisplaySettings(null /* displayIdentifier */, true /* usePortAsId */);
-
- // Write some settings.
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
- settings.setShouldShowSystemDecorsLocked(mSecondaryDisplay, true);
- settings.setShouldShowImeLocked(mSecondaryDisplay, true);
- assertTrue(mStorage.wasWriteSuccessful());
-
- // Verify that settings were stored correctly.
- assertEquals("Attribute value must be stored", "port:" + DISPLAY_PORT,
- getStoredDisplayAttributeValue("name"));
- assertEquals("Attribute value must be stored", "true",
- getStoredDisplayAttributeValue("shouldShowSystemDecors"));
- assertEquals("Attribute value must be stored", "true",
- getStoredDisplayAttributeValue("shouldShowIme"));
- }
-
- @Test
public void testShouldShowImeWithinForceDesktopMode() {
try {
// Presume display enabled force desktop mode from developer options.
@@ -567,14 +420,13 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
public void testDisplayWindowSettingsAppliedOnDisplayReady() {
// Set forced densities for two displays in DisplayWindowSettings
final DisplayContent dc = createMockSimulatedDisplay();
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
- settings.setForcedDensity(mPrimaryDisplay, 123, 0 /* userId */);
- settings.setForcedDensity(dc, 456, 0 /* userId */);
+ mDisplayWindowSettings.setForcedDensity(mPrimaryDisplay, 123, 0 /* userId */);
+ mDisplayWindowSettings.setForcedDensity(dc, 456, 0 /* userId */);
// Apply settings to displays - the settings will be stored, but config will not be
// recalculated immediately.
- settings.applySettingsToDisplayLocked(mPrimaryDisplay);
- settings.applySettingsToDisplayLocked(dc);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(mPrimaryDisplay);
+ mDisplayWindowSettings.applySettingsToDisplayLocked(dc);
assertFalse(mPrimaryDisplay.mWaitingForConfig);
assertFalse(dc.mWaitingForConfig);
@@ -589,173 +441,34 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
assertEquals(456, config.densityDpi);
}
- /**
- * Prepares display settings and stores in {@link #mStorage}. Uses provided display identifier
- * and stores windowingMode=WINDOWING_MODE_PINNED.
- */
- private void prepareDisplaySettings(String displayIdentifier) {
- prepareDisplaySettings(displayIdentifier, false /* usePortAsId */);
- }
-
- private void prepareDisplaySettings(String displayIdentifier, boolean usePortAsId) {
- String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
- + "<display-settings>\n";
- if (usePortAsId) {
- contents += " <config identifier=\"1\"/>\n";
- }
- if (displayIdentifier != null) {
- contents += " <display\n"
- + " name=\"" + displayIdentifier + "\"\n"
- + " windowingMode=\"" + WINDOWING_MODE_PINNED + "\"/>\n";
- }
- contents += "</display-settings>\n";
-
- final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
- mStorage.setReadStream(is);
- }
-
- private void readAndAssertDisplaySettings(DisplayContent displayContent) {
- final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
- assertEquals("Stored setting must be read",
- WINDOWING_MODE_PINNED, settings.getWindowingModeLocked(displayContent));
- assertEquals("Not stored setting must be set to default value",
- REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY,
- settings.getRemoveContentModeLocked(displayContent));
- }
-
- private String getStoredDisplayAttributeValue(String attr) throws Exception {
- try (InputStream stream = mStorage.openRead()) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(stream, StandardCharsets.UTF_8.name());
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- // Do nothing.
- }
-
- if (type != XmlPullParser.START_TAG) {
- throw new IllegalStateException("no start tag found");
- }
-
- int outerDepth = parser.getDepth();
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals("display")) {
- return parser.getAttributeValue(null, attr);
- }
- }
- } finally {
- mStorage.closeRead();
- }
- return null;
- }
-
- /**
- * This method helps to ensure read and write persistent settings successfully because the
- * constructor of {@link DisplayWindowSettings} should read the persistent file from the given
- * path that also means the previous state must be written correctly.
- */
- private void applySettingsToDisplayByNewInstance(DisplayContent display) {
- // Assert that prior write completed successfully.
- assertTrue(mStorage.wasWriteSuccessful());
-
- // Read and apply settings.
- new DisplayWindowSettings(mWm, mStorage).applySettingsToDisplayLocked(display);
- }
-
- private static boolean deleteRecursively(File file) {
- boolean fullyDeleted = true;
- if (file.isFile()) {
- return file.delete();
- } else if (file.isDirectory()) {
- final File[] files = file.listFiles();
- for (File child : files) {
- fullyDeleted &= deleteRecursively(child);
- }
- fullyDeleted &= file.delete();
- }
- return fullyDeleted;
- }
-
- /** In-memory storage implementation. */
- public class TestStorage implements DisplayWindowSettings.SettingPersister {
- private InputStream mReadStream;
- private ByteArrayOutputStream mWriteStream;
+ public final class TestSettingsProvider implements DisplayWindowSettings.SettingsProvider {
+ Map<DisplayInfo, SettingsEntry> mOverrideSettingsCache = new HashMap<>();
- private boolean mWasSuccessful;
-
- /**
- * Returns input stream for reading. By default tries forward the output stream if previous
- * write was successful.
- * @see #closeRead()
- */
@Override
- public InputStream openRead() throws FileNotFoundException {
- if (mReadStream == null && mWasSuccessful) {
- mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
- }
- if (mReadStream == null) {
- throw new FileNotFoundException();
- }
- if (mReadStream.markSupported()) {
- mReadStream.mark(Integer.MAX_VALUE);
- }
- return mReadStream;
- }
-
- /** Must be called after each {@link #openRead} to reset the position in the stream. */
- void closeRead() throws IOException {
- if (mReadStream == null) {
- throw new FileNotFoundException();
- }
- if (mReadStream.markSupported()) {
- mReadStream.reset();
- }
- mReadStream = null;
+ public SettingsEntry getSettings(@NonNull DisplayInfo info) {
+ return getOverrideSettings(info);
}
- /**
- * Creates new or resets existing output stream for write. Automatically closes previous
- * read stream, since following reads should happen based on this new write.
- */
@Override
- public OutputStream startWrite() throws IOException {
- if (mWriteStream == null) {
- mWriteStream = new ByteArrayOutputStream();
- } else {
- mWriteStream.reset();
- }
- if (mReadStream != null) {
- closeRead();
+ public SettingsEntry getOverrideSettings(@NonNull DisplayInfo info) {
+ SettingsEntry result = new SettingsEntry();
+ SettingsEntry overrideSettings = mOverrideSettingsCache.get(info);
+ if (overrideSettings != null) {
+ result.setTo(overrideSettings);
}
- return mWriteStream;
+ return result;
}
@Override
- public void finishWrite(OutputStream os, boolean success) {
- mWasSuccessful = success;
- try {
- os.close();
- } catch (IOException e) {
- // This method can't throw IOException since the super implementation doesn't, so
- // we just wrap it in a RuntimeException so we end up crashing the test all the
- // same.
- throw new RuntimeException(e);
+ public void updateOverrideSettings(@NonNull DisplayInfo info,
+ @NonNull SettingsEntry settings) {
+ SettingsEntry overrideSettings = mOverrideSettingsCache.get(info);
+ if (overrideSettings == null) {
+ overrideSettings = new SettingsEntry();
+ mOverrideSettingsCache.put(info, overrideSettings);
}
- }
-
- /** Override the read stream of the injector. By default it uses current write stream. */
- private void setReadStream(InputStream is) {
- mReadStream = is;
- }
- private boolean wasWriteSuccessful() {
- return mWasSuccessful;
+ overrideSettings.setTo(settings);
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 5cb3ac1d3dd5..5641fe28a52f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -83,6 +83,8 @@ import java.util.concurrent.TimeUnit;
public class DragDropControllerTests extends WindowTestsBase {
private static final int TIMEOUT_MS = 3000;
private static final int TEST_UID = 12345;
+ private static final int TEST_PID = 67890;
+ private static final String TEST_PACKAGE = "com.test.package";
private TestDragDropController mTarget;
private WindowState mWindow;
@@ -243,21 +245,16 @@ public class DragDropControllerTests extends WindowTestsBase {
});
try {
session.validateAndResolveDragMimeTypeExtras(
- createClipDataForActivity(null, null), 0);
- fail("Expected failure without pending intent and user");
- } catch (IllegalArgumentException e) {
- // Expected failure
- }
- try {
- session.validateAndResolveDragMimeTypeExtras(
- createClipDataForActivity(mock(PendingIntent.class), null), 0);
+ createClipDataForActivity(mock(PendingIntent.class), null), TEST_UID, TEST_PID,
+ TEST_PACKAGE);
fail("Expected failure without user");
} catch (IllegalArgumentException e) {
// Expected failure
}
try {
session.validateAndResolveDragMimeTypeExtras(
- createClipDataForActivity(null, mock(UserHandle.class)), 0);
+ createClipDataForActivity(null, mock(UserHandle.class)), TEST_UID, TEST_PID,
+ TEST_PACKAGE);
fail("Expected failure without pending intent");
} catch (IllegalArgumentException e) {
// Expected failure
@@ -286,15 +283,48 @@ public class DragDropControllerTests extends WindowTestsBase {
public void onAnimatorScaleChanged(float scale) {}
});
try {
- final ClipData clipData = new ClipData(
- new ClipDescription("drag", new String[] { MIMETYPE_APPLICATION_SHORTCUT }),
- new ClipData.Item(new Intent()));
-
- session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID);
+ session.validateAndResolveDragMimeTypeExtras(
+ createClipDataForShortcut(null, "test_shortcut_id", mock(UserHandle.class)),
+ TEST_UID, TEST_PID, TEST_PACKAGE);
+ fail("Expected failure without package name");
+ } catch (IllegalArgumentException e) {
+ // Expected failure
+ }
+ try {
+ session.validateAndResolveDragMimeTypeExtras(
+ createClipDataForShortcut("test_package", null, mock(UserHandle.class)),
+ TEST_UID, TEST_PID, TEST_PACKAGE);
fail("Expected failure without shortcut id");
} catch (IllegalArgumentException e) {
// Expected failure
}
+ try {
+ session.validateAndResolveDragMimeTypeExtras(
+ createClipDataForShortcut("test_package", "test_shortcut_id", null),
+ TEST_UID, TEST_PID, TEST_PACKAGE);
+ fail("Expected failure without package name");
+ } catch (IllegalArgumentException e) {
+ // Expected failure
+ }
+ }
+
+ private ClipData createClipDataForShortcut(String packageName, String shortcutId,
+ UserHandle user) {
+ final Intent data = new Intent();
+ if (packageName != null) {
+ data.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ }
+ if (shortcutId != null) {
+ data.putExtra(Intent.EXTRA_SHORTCUT_ID, shortcutId);
+ }
+ if (user != null) {
+ data.putExtra(Intent.EXTRA_USER, user);
+ }
+ final ClipData clipData = new ClipData(
+ new ClipDescription("drag", new String[] {
+ MIMETYPE_APPLICATION_SHORTCUT}),
+ new ClipData.Item(data));
+ return clipData;
}
@Test
@@ -308,7 +338,8 @@ public class DragDropControllerTests extends WindowTestsBase {
new ClipDescription("drag", new String[] { MIMETYPE_APPLICATION_TASK }),
new ClipData.Item(new Intent()));
- session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID);
+ session.validateAndResolveDragMimeTypeExtras(clipData, TEST_UID, TEST_PID,
+ TEST_PACKAGE);
fail("Expected failure without task id");
} catch (IllegalArgumentException e) {
// Expected failure
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index 044f81986517..bf718a7c4528 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -50,6 +50,11 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_PINNABLE;
import static com.android.server.wm.LockTaskController.STATUS_BAR_MASK_LOCKED;
import static com.android.server.wm.LockTaskController.STATUS_BAR_MASK_PINNED;
@@ -169,7 +174,7 @@ public class LockTaskControllerTest {
@Test
public void testStartLockTaskMode_once() throws Exception {
// GIVEN a task record with allowlisted auth
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
// WHEN calling setLockTaskMode for LOCKED mode without resuming
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -186,8 +191,8 @@ public class LockTaskControllerTest {
@Test
public void testStartLockTaskMode_twice() throws Exception {
// GIVEN two task records with allowlisted auth
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
// WHEN calling setLockTaskMode for LOCKED mode on both tasks
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -206,7 +211,7 @@ public class LockTaskControllerTest {
@Test
public void testStartLockTaskMode_pinningRequest() {
// GIVEN a task record that is not allowlisted, i.e. with pinned auth
- Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
+ Task tr = getTask(LOCK_TASK_AUTH_PINNABLE);
// WHEN calling startLockTaskMode
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -218,7 +223,7 @@ public class LockTaskControllerTest {
@Test
public void testStartLockTaskMode_pinnedBySystem() throws Exception {
// GIVEN a task record with pinned auth
- Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
+ Task tr = getTask(LOCK_TASK_AUTH_PINNABLE);
// WHEN the system calls startLockTaskMode
mLockTaskController.startLockTaskMode(tr, true, SYSTEM_UID);
@@ -237,41 +242,39 @@ public class LockTaskControllerTest {
@Test
public void testLockTaskViolation() {
// GIVEN one task record with allowlisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN it's not a lock task violation to try and launch this task without clearing
assertFalse(mLockTaskController.isLockTaskModeViolation(tr, false));
// THEN it's a lock task violation to launch another task that is not allowlisted
- assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_PINNABLE)));
+ assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(LOCK_TASK_AUTH_PINNABLE)));
// THEN it's a lock task violation to launch another task that is disallowed from lock task
- assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_DONT_LOCK)));
+ assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(LOCK_TASK_AUTH_DONT_LOCK)));
// THEN it's no a lock task violation to launch another task that is allowlisted
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_ALLOWLISTED)));
+ LOCK_TASK_AUTH_ALLOWLISTED)));
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_LAUNCHABLE)));
+ LOCK_TASK_AUTH_LAUNCHABLE)));
// THEN it's not a lock task violation to launch another task that is priv launchable
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV)));
+ LOCK_TASK_AUTH_LAUNCHABLE_PRIV)));
}
@Test
public void testLockTaskViolation_emergencyCall() {
// GIVEN one task record with allowlisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// GIVEN tasks necessary for emergency calling
Task keypad = getTask(new Intent().setComponent(EMERGENCY_DIALER_COMPONENT),
- Task.LOCK_TASK_AUTH_PINNABLE);
+ LOCK_TASK_AUTH_PINNABLE);
Task callAction = getTask(new Intent(Intent.ACTION_CALL_EMERGENCY),
- Task.LOCK_TASK_AUTH_PINNABLE);
- Task dialer = getTask("com.example.dialer", Task.LOCK_TASK_AUTH_PINNABLE);
+ LOCK_TASK_AUTH_PINNABLE);
+ Task dialer = getTask("com.example.dialer", LOCK_TASK_AUTH_PINNABLE);
when(mTelecomManager.getSystemDialerPackage())
.thenReturn(dialer.intent.getComponent().getPackageName());
@@ -295,7 +298,7 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode() throws Exception {
// GIVEN one task record with allowlisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN the same caller calls stopLockTaskMode
@@ -312,7 +315,7 @@ public class LockTaskControllerTest {
@Test(expected = SecurityException.class)
public void testStopLockTaskMode_differentCaller() {
// GIVEN one task record with allowlisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN a different caller calls stopLockTaskMode
@@ -324,7 +327,7 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode_systemCaller() {
// GIVEN one task record with allowlisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN system calls stopLockTaskMode
@@ -337,8 +340,8 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode_twoTasks() throws Exception {
// GIVEN two task records with allowlisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -358,8 +361,8 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode_rootTask() throws Exception {
// GIVEN two task records with allowlisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -379,7 +382,7 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode_pinned() throws Exception {
// GIVEN one task records that is in pinned mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
+ Task tr = getTask(LOCK_TASK_AUTH_PINNABLE);
mLockTaskController.startLockTaskMode(tr, true, SYSTEM_UID);
// GIVEN that the keyguard is required to show after unlocking
Settings.Secure.putInt(mContext.getContentResolver(),
@@ -406,8 +409,8 @@ public class LockTaskControllerTest {
@Test
public void testClearLockedTasks() throws Exception {
// GIVEN two task records with allowlisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -434,7 +437,7 @@ public class LockTaskControllerTest {
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -454,7 +457,7 @@ public class LockTaskControllerTest {
.thenReturn(true);
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -471,7 +474,7 @@ public class LockTaskControllerTest {
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 1, mContext.getUserId());
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -488,7 +491,7 @@ public class LockTaskControllerTest {
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 0, mContext.getUserId());
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr1 = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -574,7 +577,7 @@ public class LockTaskControllerTest {
@Test
public void testUpdateLockTaskFeatures() throws Exception {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -616,7 +619,7 @@ public class LockTaskControllerTest {
@Test
public void testUpdateLockTaskFeatures_differentUser() throws Exception {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -638,7 +641,7 @@ public class LockTaskControllerTest {
@Test
public void testUpdateLockTaskFeatures_keyguard() {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN keyguard should be disabled
@@ -704,7 +707,7 @@ public class LockTaskControllerTest {
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
// Start lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr = getTask(LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK is not enabled
@@ -758,14 +761,13 @@ public class LockTaskControllerTest {
* @param isAppAware {@code true} if the app has marked if allowlisted in its manifest
*/
private Task getTaskForUpdate(String pkg, boolean isAppAware) {
- final int authIfAllowlisted = isAppAware
- ? Task.LOCK_TASK_AUTH_LAUNCHABLE
- : Task.LOCK_TASK_AUTH_ALLOWLISTED;
+ final int authIfAllowlisted =
+ isAppAware ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_ALLOWLISTED;
Task tr = getTask(pkg, authIfAllowlisted);
doAnswer((invocation) -> {
boolean isAllowlisted =
mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg);
- tr.mLockTaskAuth = isAllowlisted ? authIfAllowlisted : Task.LOCK_TASK_AUTH_PINNABLE;
+ tr.mLockTaskAuth = isAllowlisted ? authIfAllowlisted : LOCK_TASK_AUTH_PINNABLE;
return null;
}).when(tr).setLockTaskAuth();
return tr;
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 bea0d8e60c40..80bffd17ab43 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -294,7 +294,7 @@ public class RecentTasksTest extends WindowTestsBase {
}).when(mSupervisor).endActivityVisibilityUpdate();
mTaskContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
- false /* preserveWindows */, false /* notifyClients */);
+ false /* preserveWindows */, false /* notifyClients */, false /* userLeaving */);
assertFalse(mSupervisor.inActivityVisibilityUpdate());
assertThat(mCallbacksRecorder.mAdded).hasSize(2);
@@ -474,6 +474,28 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
+ public void testAppendOrganizedChildTaskInfo() {
+ final Task root = createTaskBuilder(".CreatedByOrganizerRoot").build();
+ root.mCreatedByOrganizer = true;
+ // Add organized and non-organized child.
+ final Task child1 = createTaskBuilder(".Task1").setParentTask(root).build();
+ final Task child2 = createTaskBuilder(".Task2").setParentTask(root).build();
+ doReturn(true).when(child1).isOrganized();
+ doReturn(false).when(child2).isOrganized();
+ mRecentTasks.add(root);
+
+ doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
+ doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
+ final List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0 /* callingUid */).getList();
+
+ // Make sure only organized child will be appended.
+ final List<RecentTaskInfo> childrenTaskInfos = infos.get(0).childrenTaskInfos;
+ assertEquals(childrenTaskInfos.size(), 1);
+ assertEquals(childrenTaskInfos.get(0).taskId, child1.mTaskId);
+ }
+
+ @Test
public void testAddTasksHomeClearUntrackedTasks_expectFinish() {
// There may be multiple tasks with the same base intent by flags (FLAG_ACTIVITY_NEW_TASK |
// FLAG_ACTIVITY_MULTIPLE_TASK). If the previous task is still active, it should be removed
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 137cedde11cf..542747033765 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -100,7 +100,8 @@ public class RecentsAnimationTest extends WindowTestsBase {
doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
any() /* starting */, anyInt() /* configChanges */,
- anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
+ anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */,
+ anyBoolean() /* userLeaving */);
RecentsAnimationCallbacks recentsAnimation = startRecentsActivity(
mRecentsComponent, true /* getRecentsAnimation */);
@@ -191,7 +192,8 @@ public class RecentsAnimationTest extends WindowTestsBase {
doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
any() /* starting */, anyInt() /* configChanges */,
- anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
+ anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */,
+ anyBoolean() /* userLeaving */);
doReturn(app).when(mAtm).getProcessController(eq(recentActivity.processName), anyInt());
ClientLifecycleManager lifecycleManager = mAtm.getLifecycleManager();
doNothing().when(lifecycleManager).scheduleTransaction(any());
@@ -347,7 +349,8 @@ public class RecentsAnimationTest extends WindowTestsBase {
doReturn(TEST_USER_ID).when(mAtm).getCurrentUserId();
doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
any() /* starting */, anyInt() /* configChanges */,
- anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
+ anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */,
+ anyBoolean() /* userLeaving */);
startRecentsActivity(otherUserHomeActivity.getTask().getBaseIntent().getComponent(),
true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 1879e9e88822..4b8bbc165bad 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -38,7 +38,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
-import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
+import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
@@ -107,7 +107,7 @@ public class RootActivityContainerTests extends WindowTestsBase {
public void testRestoringInvalidTask() {
mRootWindowContainer.getDefaultDisplay().removeAllTasks();
Task task = mRootWindowContainer.anyTaskForId(0 /*taskId*/,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
+ MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
assertNull(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 4300971be689..ddc29f5dd516 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -41,6 +41,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doCallRealMethod;
import android.app.ActivityManager;
@@ -702,7 +703,6 @@ public class SizeCompatTests extends WindowTestsBase {
// size compat cache.
verify(mTask).onDescendantOrientationChanged(any(), same(newActivity));
verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
- verify(newActivity).clearSizeCompatMode(false /* recomputeTask */);
final Rect displayBounds = display.getBounds();
final Rect taskBounds = mTask.getBounds();
@@ -744,7 +744,6 @@ public class SizeCompatTests extends WindowTestsBase {
// size compat cache.
verify(mTask).onDescendantOrientationChanged(any(), same(newActivity));
verify(mTask).computeFullscreenBounds(any(), any(), any(), anyInt());
- verify(newActivity).clearSizeCompatMode(false /* recomputeTask */);
final Rect displayBounds = display.getBounds();
final Rect taskBounds = mTask.getBounds();
@@ -761,6 +760,40 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(taskBounds, newActivityBounds);
}
+ @Test
+ public void testDisplayIgnoreOrientationRequest_pausedAppNotLostSizeCompat() {
+ // Set up a display in landscape and ignoring orientation request.
+ setUpDisplaySizeWithApp(2800, 1400);
+ final DisplayContent display = mActivity.mDisplayContent;
+ display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+
+ // Portrait fixed app.
+ prepareUnresizable(0, SCREEN_ORIENTATION_PORTRAIT);
+ clearInvocations(mActivity);
+
+ assertTrue(mTask.isTaskLetterboxed());
+ assertFalse(mActivity.inSizeCompatMode());
+ assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity);
+
+ // Rotate display to portrait.
+ rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+
+ // App should be in size compat.
+ assertFalse(mTask.isTaskLetterboxed());
+ assertScaled();
+ assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity);
+
+ final Rect activityBounds = new Rect(mActivity.getBounds());
+ mStack.resumeTopActivityUncheckedLocked(null /* prev */, null /* options */);
+
+ // App still in size compat, and the bounds don't change.
+ verify(mActivity, never()).clearSizeCompatMode();
+ assertFalse(mTask.isTaskLetterboxed());
+ assertScaled();
+ assertEquals(mTask.getLastTaskBoundsComputeActivity(), mActivity);
+ assertEquals(activityBounds, mActivity.getBounds());
+ }
+
private static WindowState addWindowToActivity(ActivityRecord activity) {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 6f5389ddacce..a8c24c9b2f1b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -88,6 +88,7 @@ import org.mockito.quality.Strictness;
import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
/**
* JUnit test rule to correctly setting up system services like {@link WindowManagerService}
@@ -112,6 +113,7 @@ public class SystemServicesTestRule implements TestRule {
private WindowState.PowerManagerWrapper mPowerManagerWrapper;
private InputManagerService mImService;
private InputChannel mInputChannel;
+ private Supplier<Surface> mSurfaceFactory = () -> mock(Surface.class);
/**
* Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
*/
@@ -286,7 +288,7 @@ public class SystemServicesTestRule implements TestRule {
DisplayThread.getHandler().post(StrictMode::allowThreadDiskWritesMask);
mWmService = WindowManagerService.main(
mContext, mImService, false, false, mWMPolicy, mAtmService, StubTransaction::new,
- () -> mock(Surface.class), (unused) -> new MockSurfaceControlBuilder());
+ () -> mSurfaceFactory.get(), (unused) -> new MockSurfaceControlBuilder());
spyOn(mWmService);
spyOn(mWmService.mRoot);
// Invoked during {@link ActivityStack} creation.
@@ -295,7 +297,8 @@ public class SystemServicesTestRule implements TestRule {
doReturn(true).when(mWmService.mRoot).hasAwakeDisplay();
// Called when moving activity to pinned stack.
doNothing().when(mWmService.mRoot).ensureActivitiesVisible(any(),
- anyInt(), anyBoolean(), anyBoolean());
+ anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
+ spyOn(mWmService.mDisplayWindowSettings);
// Setup factory classes to prevent calls to native code.
mTransaction = spy(StubTransaction.class);
@@ -395,6 +398,10 @@ public class SystemServicesTestRule implements TestRule {
return mPowerManagerWrapper;
}
+ void setSurfaceFactory(Supplier<Surface> factory) {
+ mSurfaceFactory = factory;
+ }
+
void cleanupWindowManagerHandlers() {
final WindowManagerService wm = getWindowManagerService();
if (wm == null) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index c5c947bf21d8..4bd8edd44f5c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -296,6 +296,37 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
assertThat(taskDisplayArea.getOrientation()).isEqualTo(SCREEN_ORIENTATION_UNSET);
}
+ @Test
+ @UseTestDisplay
+ public void testRemove_reparentToDefault() {
+ final Task task = createTaskStackOnDisplay(mDisplayContent);
+ final TaskDisplayArea displayArea = task.getDisplayArea();
+ displayArea.remove();
+ assertTrue(displayArea.isRemoved());
+ assertFalse(displayArea.hasChild());
+
+ final RootWindowContainer rootWindowContainer = mWm.mAtmService.mRootWindowContainer;
+ final TaskDisplayArea defaultTaskDisplayArea =
+ rootWindowContainer.getDefaultTaskDisplayArea();
+ assertTrue(defaultTaskDisplayArea.mChildren.contains(task));
+ }
+
+ @Test
+ @UseTestDisplay
+ public void testRemove_stackCreatedByOrganizer() {
+ final Task task = createTaskStackOnDisplay(mDisplayContent);
+ task.mCreatedByOrganizer = true;
+ final TaskDisplayArea displayArea = task.getDisplayArea();
+ displayArea.remove();
+ assertTrue(displayArea.isRemoved());
+ assertFalse(displayArea.hasChild());
+
+ final RootWindowContainer rootWindowContainer = mWm.mAtmService.mRootWindowContainer;
+ final TaskDisplayArea defaultTaskDisplayArea =
+ rootWindowContainer.getDefaultTaskDisplayArea();
+ assertFalse(defaultTaskDisplayArea.mChildren.contains(task));
+ }
+
private void assertGetOrCreateStack(int windowingMode, int activityType, Task candidateTask,
boolean reuseCandidate) {
final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index b4a13375aeec..5ea73b830582 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -20,17 +20,23 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
+import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityManager.TaskSnapshot;
import android.content.ComponentName;
@@ -41,14 +47,18 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.platform.test.annotations.Presubmit;
+import android.view.Display;
+import android.view.IWindowSession;
import android.view.InsetsState;
import android.view.Surface;
import android.view.SurfaceControl;
+import android.view.WindowManager;
import androidx.test.filters.SmallTest;
import com.android.server.wm.TaskSnapshotSurface.Window;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -67,9 +77,6 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis,
int windowFlags, Rect taskBounds) {
- final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
- 1, HardwareBuffer.USAGE_CPU_READ_RARELY);
-
// Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic
// this behavior set the taskSize to be the same as the taskBounds width and height. The
// taskBounds passed here are assumed to be the same task bounds as when the snapshot was
@@ -79,16 +86,24 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
assertEquals(height, taskBounds.height());
Point taskSize = new Point(taskBounds.width(), taskBounds.height());
- final TaskSnapshot snapshot = new TaskSnapshot(
+ final TaskSnapshot snapshot = createTaskSnapshot(width, height, taskSize, contentInsets);
+ mSurface = new TaskSnapshotSurface(mWm, Display.DEFAULT_DISPLAY, new Window(),
+ new SurfaceControl(), snapshot, "Test", createTaskDescription(Color.WHITE,
+ Color.RED, Color.BLUE), sysuiVis, windowFlags, 0, taskBounds, ORIENTATION_PORTRAIT,
+ ACTIVITY_TYPE_STANDARD, new InsetsState());
+ }
+
+ private ActivityManager.TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
+ Rect contentInsets) {
+ final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
+ 1, HardwareBuffer.USAGE_CPU_READ_RARELY);
+ return new TaskSnapshot(
System.currentTimeMillis(),
new ComponentName("", ""), buffer,
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
Surface.ROTATION_0, taskSize, contentInsets, false,
true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
0 /* systemUiVisibility */, false /* isTranslucent */);
- mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
- createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0,
- taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState());
}
private static TaskDescription createTaskDescription(int background, int statusBar,
@@ -105,6 +120,35 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
new Rect(0, 0, width, height));
}
+ private boolean isTrustedOverlay(WindowManager.LayoutParams params) {
+ return (params.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mSystemServicesTestRule.setSurfaceFactory(() -> {
+ Surface surface = mock(Surface.class);
+ when(surface.isValid()).thenReturn(true);
+ return surface;
+ });
+ }
+
+ @Test
+ public void createSurface_asTrustedOverlay() throws Exception {
+ Point task = new Point(200, 100);
+ ActivityRecord activityRecord = createActivityRecord(mDisplayContent);
+ createWindow(null, TYPE_BASE_APPLICATION, activityRecord, "window");
+ TaskSnapshot taskSnapshot = createTaskSnapshot(task.x, task.y, task, new Rect());
+ IWindowSession session = mock(IWindowSession.class);
+
+ TaskSnapshotSurface surface = TaskSnapshotSurface.create(mWm, activityRecord, taskSnapshot,
+ session);
+
+ assertThat(surface).isNotNull();
+ verify(session).addToDisplay(any(), argThat(this::isTrustedOverlay), anyInt(), anyInt(),
+ any(), any(), any(), any(), any(), any());
+ }
+
@Test
public void fillEmptyBackground_fillHorizontally() {
setupSurface(200, 100);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 0b257ee87620..238f31448ba1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -257,4 +257,24 @@ public class TaskTests extends WindowTestsBase {
task.resolveOverrideConfiguration(parentConfig);
assertThat(resolvedOverride.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
}
+
+ @Test
+ public void testCleanUpActivityReferences_clearLastTaskBoundsComputeActivity() {
+ final Task rootTask = createTaskStackOnDisplay(mDisplayContent);
+ final Task leafTask = createTaskInStack(rootTask, 0 /* userId */);
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent, leafTask);
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent, leafTask);
+ activity1.finishing = false;
+ leafTask.resolveOverrideConfiguration(rootTask.getConfiguration());
+
+ assertEquals(activity1, leafTask.getLastTaskBoundsComputeActivity());
+
+ leafTask.cleanUpActivityReferences(activity2);
+
+ assertNotNull(leafTask.getLastTaskBoundsComputeActivity());
+
+ leafTask.cleanUpActivityReferences(activity1);
+
+ assertNull(leafTask.getLastTaskBoundsComputeActivity());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index db5c7965ebee..eb5f1f9b9c5f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -117,7 +117,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
window = WindowTestsBase.createWindow(null, TYPE_APPLICATION_STARTING, activity,
"Starting window", 0 /* ownerId */, 0 /* userId*/, false /* internalWindows */,
wm, mock(Session.class), iWindow, mPowerManagerWrapper);
- activity.startingWindow = window;
+ activity.mStartingWindow = window;
}
if (mRunnableWhenAddingSplashScreen != null) {
mRunnableWhenAddingSplashScreen.run();
@@ -126,7 +126,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
return () -> {
synchronized (wm.mGlobalLock) {
activity.removeChild(window);
- activity.startingWindow = null;
+ activity.mStartingWindow = null;
}
};
}
@@ -173,10 +173,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
}
@Override
- public void applyKeyguardPolicyLw(WindowState win, WindowState imeTarget) {
- }
-
- @Override
public void setAllowLockscreenWhenOn(int displayId, boolean allow) {
}
@@ -395,9 +391,4 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
public boolean canDismissBootAnimation() {
return true;
}
-
- @Override
- public boolean setAodShowing(boolean aodShowing) {
- return false;
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
index 8d5363c89570..ba144dd367d9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerSettingsTests.java
@@ -20,12 +20,16 @@ import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDO
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
+import static android.provider.Settings.Global.DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.ContentResolver;
@@ -37,6 +41,9 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.List;
/**
* Test for {@link WindowManagerService.SettingsObserver}.
@@ -124,6 +131,36 @@ public class WindowManagerSettingsTests extends WindowTestsBase {
}
}
+ @Test
+ public void testEnabledIgnoreVendorDisplaySettings() {
+ try (SettingsSession ignoreVendorDisplaySettingsSession = new
+ SettingsSession(DEVELOPMENT_IGNORE_VENDOR_DISPLAY_SETTINGS)) {
+ final boolean ignoreVendorDisplaySettings =
+ !ignoreVendorDisplaySettingsSession.getSetting();
+ final Uri ignoreVendorDisplaySettingUri =
+ ignoreVendorDisplaySettingsSession.setSetting(ignoreVendorDisplaySettings);
+
+ clearInvocations(mWm.mRoot);
+ clearInvocations(mWm.mDisplayWindowSettings);
+
+ mWm.mSettingsObserver.onChange(false /* selfChange */, ignoreVendorDisplaySettingUri);
+
+ assertEquals(mWm.mDisplayWindowSettingsProvider.getVendorSettingsIgnored(),
+ ignoreVendorDisplaySettings);
+
+ ArgumentCaptor<DisplayContent> captor =
+ ArgumentCaptor.forClass(DisplayContent.class);
+ verify(mWm.mDisplayWindowSettings, times(mWm.mRoot.mChildren.size()))
+ .applySettingsToDisplayLocked(captor.capture());
+ List<DisplayContent> configuredDisplays = captor.getAllValues();
+ for (DisplayContent dc : mWm.mRoot.mChildren) {
+ assertTrue(configuredDisplays.contains(dc));
+ }
+
+ verify(mWm.mRoot, atLeastOnce()).performSurfacePlacement();
+ }
+ }
+
private class SettingsSession implements AutoCloseable {
private static final int SETTING_VALUE_OFF = 0;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 7a41c02de3b6..8fe65eb2747d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -506,6 +506,14 @@ public class WindowOrganizerTests extends WindowTestsBase {
public void testTileAddRemoveChild() {
ITaskOrganizer listener = new ITaskOrganizer.Stub() {
@Override
+ public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+
+ }
+
+ @Override
+ public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+
+ @Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@Override
@@ -563,6 +571,14 @@ public class WindowOrganizerTests extends WindowTestsBase {
final boolean[] called = {false};
ITaskOrganizer listener = new ITaskOrganizer.Stub() {
@Override
+ public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+
+ }
+
+ @Override
+ public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+
+ @Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@Override
@@ -626,6 +642,14 @@ public class WindowOrganizerTests extends WindowTestsBase {
final ArrayMap<IBinder, RunningTaskInfo> lastReportedTiles = new ArrayMap<>();
ITaskOrganizer listener = new ITaskOrganizer.Stub() {
@Override
+ public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+
+ }
+
+ @Override
+ public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+
+ @Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@Override
@@ -763,6 +787,10 @@ public class WindowOrganizerTests extends WindowTestsBase {
RunningTaskInfo mInfo;
@Override
+ public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) { }
+ @Override
+ public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+ @Override
public void onTaskAppeared(RunningTaskInfo info, SurfaceControl leash) {
mInfo = info;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 21be6ef2e897..5afcedb10dd6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -22,6 +22,9 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.Display.INVALID_DISPLAY;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -168,11 +171,7 @@ public class WindowProcessControllerTests extends WindowTestsBase {
mAtm, applicationInfo, null, 0, -1, null, mMockListener);
wpc.setThread(mock(IApplicationThread.class));
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .setUseProcess(wpc)
- .build();
-
+ final ActivityRecord activity = createActivityRecord(wpc);
wpc.addActivityIfNeeded(activity);
// System UI owned processes should not be registered for activity config changes.
assertFalse(wpc.registeredForActivityConfigChanges());
@@ -185,11 +184,7 @@ public class WindowProcessControllerTests extends WindowTestsBase {
// Notify WPC that this process has started an IME service.
mWpc.onServiceStarted(serviceInfo);
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .setUseProcess(mWpc)
- .build();
-
+ final ActivityRecord activity = createActivityRecord(mWpc);
mWpc.addActivityIfNeeded(activity);
// IME processes should not be registered for activity config changes.
assertFalse(mWpc.registeredForActivityConfigChanges());
@@ -202,11 +197,7 @@ public class WindowProcessControllerTests extends WindowTestsBase {
// Notify WPC that this process has started an ally service.
mWpc.onServiceStarted(serviceInfo);
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .setUseProcess(mWpc)
- .build();
-
+ final ActivityRecord activity = createActivityRecord(mWpc);
mWpc.addActivityIfNeeded(activity);
// Ally processes should not be registered for activity config changes.
assertFalse(mWpc.registeredForActivityConfigChanges());
@@ -219,11 +210,7 @@ public class WindowProcessControllerTests extends WindowTestsBase {
// Notify WPC that this process has started an voice interaction service.
mWpc.onServiceStarted(serviceInfo);
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .setUseProcess(mWpc)
- .build();
-
+ final ActivityRecord activity = createActivityRecord(mWpc);
mWpc.addActivityIfNeeded(activity);
// Voice interaction service processes should not be registered for activity config changes.
assertFalse(mWpc.registeredForActivityConfigChanges());
@@ -244,7 +231,7 @@ public class WindowProcessControllerTests extends WindowTestsBase {
final int globalSeq = 100;
mRootWindowContainer.getConfiguration().seq = globalSeq;
invertOrientation(mWpc.getConfiguration());
- new ActivityBuilder(mAtm).setCreateTask(true).setUseProcess(mWpc).build();
+ createActivityRecord(mWpc);
assertTrue(mWpc.registeredForActivityConfigChanges());
assertEquals("Config seq of process should not be affected by activity",
@@ -253,10 +240,7 @@ public class WindowProcessControllerTests extends WindowTestsBase {
@Test
public void testComputeOomAdjFromActivities() {
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .setUseProcess(mWpc)
- .build();
+ final ActivityRecord activity = createActivityRecord(mWpc);
activity.mVisibleRequested = true;
final int[] callbackResult = { 0 };
final int visible = 1;
@@ -308,6 +292,41 @@ public class WindowProcessControllerTests extends WindowTestsBase {
assertEquals(other, callbackResult[0]);
}
+ @Test
+ public void testComputeProcessActivityState() {
+ final VisibleActivityProcessTracker tracker = mAtm.mVisibleActivityProcessTracker;
+ spyOn(tracker);
+ final ActivityRecord activity = createActivityRecord(mWpc);
+ activity.mVisibleRequested = true;
+ activity.setState(Task.ActivityState.STARTED, "test");
+
+ verify(tracker).onAnyActivityVisible(mWpc);
+ assertTrue(mWpc.hasVisibleActivities());
+
+ activity.setState(Task.ActivityState.RESUMED, "test");
+
+ verify(tracker).onActivityResumedWhileVisible(mWpc);
+ assertTrue(tracker.hasResumedActivity(mWpc.mUid));
+
+ activity.makeFinishingLocked();
+ activity.setState(Task.ActivityState.PAUSING, "test");
+
+ assertFalse(tracker.hasResumedActivity(mWpc.mUid));
+ assertTrue(mWpc.hasForegroundActivities());
+
+ activity.setVisibility(false);
+ activity.mVisibleRequested = false;
+ activity.setState(Task.ActivityState.STOPPED, "test");
+
+ verify(tracker).onAllActivitiesInvisible(mWpc);
+ assertFalse(mWpc.hasVisibleActivities());
+ assertFalse(mWpc.hasForegroundActivities());
+ }
+
+ private ActivityRecord createActivityRecord(WindowProcessController wpc) {
+ return new ActivityBuilder(mAtm).setCreateTask(true).setUseProcess(wpc).build();
+ }
+
private TestDisplayContent createTestDisplayContentInContainer() {
return new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 9304dc53c819..75d2c5159187 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -62,15 +62,18 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.when;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.util.Size;
import android.view.DisplayCutout;
+import android.view.InputWindowHandle;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowManager;
@@ -175,9 +178,9 @@ public class WindowStateTests extends WindowTestsBase {
final WindowState overlayWindow = spy(createWindow(null, TYPE_APPLICATION_OVERLAY,
"overlayWindow"));
overlayWindow.setHiddenWhileSuspended(true);
- verify(overlayWindow).hideLw(true, true);
+ verify(overlayWindow).hide(true /* doAnimation */, true /* requestAnim */);
overlayWindow.setHiddenWhileSuspended(false);
- verify(overlayWindow).showLw(true, true);
+ verify(overlayWindow).show(true /* doAnimation */, true /* requestAnim */);
}
@Test
@@ -202,7 +205,7 @@ public class WindowStateTests extends WindowTestsBase {
final WindowState window = createWindow(null, TYPE_APPLICATION, "window");
window.setHasSurface(true);
assertTrue(window.isOnScreen());
- window.hideLw(false /* doAnimation */);
+ window.hide(false /* doAnimation */, false /* requestAnim */);
assertFalse(window.isOnScreen());
}
@@ -239,8 +242,8 @@ public class WindowStateTests extends WindowTestsBase {
appWindow.mActivityRecord.setWindowingMode(initialMode);
// Make windows invisible
- appWindow.hideLw(false /* doAnimation */);
- imeWindow.hideLw(false /* doAnimation */);
+ appWindow.hide(false /* doAnimation */, false /* requestAnim */);
+ imeWindow.hide(false /* doAnimation */, false /* requestAnim */);
// Invisible window can't be IME targets even if they have the right flags.
assertFalse(appWindow.canBeImeTarget());
@@ -464,10 +467,10 @@ public class WindowStateTests extends WindowTestsBase {
public void testDisplayIdUpdatedOnReparent() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
// fake a different display
- app.mInputWindowHandle.displayId = mDisplayContent.getDisplayId() + 1;
+ app.mInputWindowHandle.setDisplayId(mDisplayContent.getDisplayId() + 1);
app.onDisplayChanged(mDisplayContent);
- assertThat(app.mInputWindowHandle.displayId, is(mDisplayContent.getDisplayId()));
+ assertThat(app.mInputWindowHandle.getDisplayId(), is(mDisplayContent.getDisplayId()));
assertThat(app.getDisplayId(), is(mDisplayContent.getDisplayId()));
}
@@ -548,7 +551,7 @@ public class WindowStateTests extends WindowTestsBase {
TYPE_BASE_APPLICATION, "startingApp");
final WindowState startingWindow = createWindow(null /* parent */,
TYPE_APPLICATION_STARTING, startingApp.mToken, "starting");
- startingApp.mActivityRecord.startingWindow = startingWindow;
+ startingApp.mActivityRecord.mStartingWindow = startingWindow;
final WindowState keyguardHostWindow = mNotificationShadeWindow;
final WindowState allDrawnApp = mAppWindow;
allDrawnApp.mActivityRecord.allDrawn = true;
@@ -678,6 +681,56 @@ public class WindowStateTests extends WindowTestsBase {
assertFalse(win0.canReceiveTouchInput());
}
+ @Test
+ public void testUpdateInputWindowHandle() {
+ final WindowState win = createWindow(null, TYPE_APPLICATION, "win");
+ win.mAttrs.inputFeatures = WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
+ final InputWindowHandle handle = new InputWindowHandle(
+ win.mInputWindowHandle.getInputApplicationHandle(), win.getDisplayId());
+ final InputWindowHandleWrapper handleWrapper = new InputWindowHandleWrapper(handle);
+ final IBinder inputChannelToken = mock(IBinder.class);
+ win.mInputChannelToken = inputChannelToken;
+
+ mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
+
+ assertTrue(handleWrapper.isChanged());
+ // The window of standard resizable task should not use surface crop as touchable region.
+ assertFalse(handle.replaceTouchableRegionWithCrop);
+ assertEquals(inputChannelToken, handle.token);
+ assertEquals(win.mActivityRecord.getInputApplicationHandle(false /* update */),
+ handle.inputApplicationHandle);
+ assertEquals(win.mAttrs.inputFeatures, handle.inputFeatures);
+ assertEquals(win.isVisible(), handle.visible);
+
+ final SurfaceControl sc = mock(SurfaceControl.class);
+ final SurfaceControl.Transaction transaction = mSystemServicesTestRule.mTransaction;
+ InputMonitor.setInputWindowInfoIfNeeded(transaction, sc, handleWrapper);
+
+ // The fields of input window handle are changed, so it must set input window info
+ // successfully. And then the changed flag should be reset.
+ verify(transaction).setInputWindowInfo(eq(sc), eq(handle));
+ assertFalse(handleWrapper.isChanged());
+ // Populate the same states again, the handle should not detect change.
+ mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
+ assertFalse(handleWrapper.isChanged());
+
+ // Apply the no change handle, the invocation of setInputWindowInfo should be skipped.
+ clearInvocations(transaction);
+ InputMonitor.setInputWindowInfoIfNeeded(transaction, sc, handleWrapper);
+ verify(transaction, never()).setInputWindowInfo(any(), any());
+
+ // Populate as an overlay to disable the input of window.
+ InputMonitor.populateOverlayInputInfo(handleWrapper, false /* isVisible */);
+ // The overlay attributes should be set.
+ assertTrue(handleWrapper.isChanged());
+ assertFalse(handle.focusable);
+ assertFalse(handle.visible);
+ assertNull(handle.token);
+ assertEquals(0L, handle.dispatchingTimeoutMillis);
+ assertEquals(WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL,
+ handle.inputFeatures);
+ }
+
@UseTestDisplay(addWindows = W_ACTIVITY)
@Test
public void testNeedsRelativeLayeringToIme_notAttached() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index d5fb3c5f5e3d..6e20c6240c89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -348,7 +348,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
win.mRelayoutCalled = true;
win.mHasSurface = true;
win.mHidden = false;
- win.showLw(false /* doAnimation */, false /* requestAnim */);
+ win.show(false /* doAnimation */, false /* requestAnim */);
}
}
@@ -1075,6 +1075,12 @@ class WindowTestsBase extends SystemServiceTestsBase {
mMoveToSecondaryOnEnter = move;
}
@Override
+ public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+ }
+ @Override
+ public void removeStartingWindow(ActivityManager.RunningTaskInfo info) {
+ }
+ @Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
}
@Override
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 64f8c585c80b..632ad4c33e36 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -1140,6 +1140,25 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
/**
+ * Stops and unloads all models. This is intended as a clean-up call with the expectation that
+ * this instance is not used after.
+ * @hide
+ */
+ public void detach() {
+ synchronized (mLock) {
+ for (ModelData model : mModelDataMap.values()) {
+ forceStopAndUnloadModelLocked(model, null);
+ }
+ mModelDataMap.clear();
+ internalClearGlobalStateLocked();
+ if (mModule != null) {
+ mModule.detach();
+ mModule = null;
+ }
+ }
+ }
+
+ /**
* Stops and unloads a sound model, and removes any reference to the model if successful.
*
* @param modelData The model data to remove.
@@ -1170,7 +1189,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
if (modelData.isModelStarted()) {
Slog.d(TAG, "Stopping previously started dangling model " + modelData.getHandle());
- if (mModule.stopRecognition(modelData.getHandle()) != STATUS_OK) {
+ if (mModule.stopRecognition(modelData.getHandle()) == STATUS_OK) {
modelData.setStopped();
modelData.setRequested(false);
} else {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
index f77d4907cf03..a976257a9ad1 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
@@ -27,6 +27,7 @@ import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.media.permission.Identity;
+import android.os.IBinder;
import com.android.server.voiceinteraction.VoiceInteractionManagerService;
@@ -46,10 +47,12 @@ public interface SoundTriggerInternal {
int STATUS_ERROR = SoundTrigger.STATUS_ERROR;
int STATUS_OK = SoundTrigger.STATUS_OK;
- Session attachAsOriginator(@NonNull Identity originatorIdentity);
+ Session attachAsOriginator(@NonNull Identity originatorIdentity,
+ @NonNull IBinder client);
Session attachAsMiddleman(@NonNull Identity middlemanIdentity,
- @NonNull Identity originatorIdentity);
+ @NonNull Identity originatorIdentity,
+ @NonNull IBinder client);
/**
* Dumps service-wide information.
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 5999044d9427..6c9f41c102b3 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -226,33 +226,45 @@ public class SoundTriggerService extends SystemService {
class SoundTriggerServiceStub extends ISoundTriggerService.Stub {
@Override
- public ISoundTriggerSession attachAsOriginator(Identity originatorIdentity) {
+ public ISoundTriggerSession attachAsOriginator(Identity originatorIdentity,
+ @NonNull IBinder client) {
try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
originatorIdentity)) {
- return new SoundTriggerSessionStub(newSoundTriggerHelper());
+ return new SoundTriggerSessionStub(newSoundTriggerHelper(), client);
}
}
@Override
public ISoundTriggerSession attachAsMiddleman(Identity originatorIdentity,
- Identity middlemanIdentity) {
+ Identity middlemanIdentity,
+ @NonNull IBinder client) {
try (SafeCloseable ignored = PermissionUtil.establishIdentityIndirect(mContext,
SOUNDTRIGGER_DELEGATE_IDENTITY, middlemanIdentity,
originatorIdentity)) {
- return new SoundTriggerSessionStub(newSoundTriggerHelper());
+ return new SoundTriggerSessionStub(newSoundTriggerHelper(), client);
}
}
}
class SoundTriggerSessionStub extends ISoundTriggerSession.Stub {
private final SoundTriggerHelper mSoundTriggerHelper;
+ // Used to detect client death.
+ private final IBinder mClient;
private final TreeMap<UUID, SoundModel> mLoadedModels = new TreeMap<>();
private final Object mCallbacksLock = new Object();
private final TreeMap<UUID, IRecognitionStatusCallback> mCallbacks = new TreeMap<>();
SoundTriggerSessionStub(
- SoundTriggerHelper soundTriggerHelper) {
+ SoundTriggerHelper soundTriggerHelper, @NonNull IBinder client) {
mSoundTriggerHelper = soundTriggerHelper;
+ mClient = client;
+ try {
+ mClient.linkToDeath(() -> {
+ clientDied();
+ }, 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register death listener.", e);
+ }
}
@Override
@@ -790,6 +802,13 @@ public class SoundTriggerService extends SystemService {
}
}
+ private void clientDied() {
+ Slog.w(TAG, "Client died, cleaning up session.");
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "Client died, cleaning up session."));
+ mSoundTriggerHelper.detach();
+ }
+
/**
* Local end for a {@link SoundTriggerDetectionService}. Operations are queued up and
* executed when the service connects.
@@ -1457,10 +1476,19 @@ public class SoundTriggerService extends SystemService {
private class SessionImpl implements Session {
private final @NonNull SoundTriggerHelper mSoundTriggerHelper;
+ private final @NonNull IBinder mClient;
private SessionImpl(
- @NonNull SoundTriggerHelper soundTriggerHelper) {
+ @NonNull SoundTriggerHelper soundTriggerHelper, @NonNull IBinder client) {
mSoundTriggerHelper = soundTriggerHelper;
+ mClient = client;
+ try {
+ mClient.linkToDeath(() -> {
+ clientDied();
+ }, 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register death listener.", e);
+ }
}
@Override
@@ -1507,22 +1535,31 @@ public class SoundTriggerService extends SystemService {
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mSoundTriggerHelper.dump(fd, pw, args);
}
+
+ private void clientDied() {
+ Slog.w(TAG, "Client died, cleaning up session.");
+ sEventLogger.log(new SoundTriggerLogger.StringEvent(
+ "Client died, cleaning up session."));
+ mSoundTriggerHelper.detach();
+ }
}
@Override
- public Session attachAsOriginator(@NonNull Identity originatorIdentity) {
+ public Session attachAsOriginator(@NonNull Identity originatorIdentity,
+ @NonNull IBinder client) {
try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
originatorIdentity)) {
- return new SessionImpl(newSoundTriggerHelper());
+ return new SessionImpl(newSoundTriggerHelper(), client);
}
}
@Override
public Session attachAsMiddleman(@NonNull Identity middlemanIdentity,
- @NonNull Identity originatorIdentity) {
+ @NonNull Identity originatorIdentity,
+ @NonNull IBinder client) {
try (SafeCloseable ignored = PermissionUtil.establishIdentityIndirect(mContext,
SOUNDTRIGGER_DELEGATE_IDENTITY, middlemanIdentity, originatorIdentity)) {
- return new SessionImpl(newSoundTriggerHelper());
+ return new SessionImpl(newSoundTriggerHelper(), client);
}
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 547d253501e8..2bcf3b55af1e 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -257,12 +257,13 @@ public class VoiceInteractionManagerService extends SystemService {
@Override
public @NonNull IVoiceInteractionSoundTriggerSession createSoundTriggerSessionAsOriginator(
- @NonNull Identity originatorIdentity) {
+ @NonNull Identity originatorIdentity, IBinder client) {
Objects.requireNonNull(originatorIdentity);
try (SafeCloseable ignored = PermissionUtil.establishIdentityDirect(
originatorIdentity)) {
SoundTriggerSession session = new SoundTriggerSession(
- mSoundTriggerInternal.attachAsOriginator(IdentityContext.getNonNull()));
+ mSoundTriggerInternal.attachAsOriginator(IdentityContext.getNonNull(),
+ client));
synchronized (mSessions) {
mSessions.add(new WeakReference<>(session));
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index a85eb53605d6..1238e7b69a87 100755
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1468,8 +1468,11 @@ public final class Call {
/**
* Writes the string {@param input} into the outgoing text stream for this RTT call. Since
- * RTT transmits text in real-time, this method should be called once for each character
- * the user enters into the device.
+ * RTT transmits text in real-time, this method should be called once for each user action.
+ * For example, when the user enters text as discrete characters using the keyboard, this
+ * method should be called once for each character. However, if the user enters text by
+ * pasting or autocomplete, the entire contents of the pasted or autocompleted text should
+ * be sent in one call to this method.
*
* This method is not thread-safe -- calling it from multiple threads simultaneously may
* lead to interleaved text.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index bbf34df8fe84..724a9e477b95 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -767,6 +767,19 @@ public abstract class Connection extends Conferenceable {
"android.telecom.extra.AUDIO_CODEC";
/**
+ * Float connection extra key used to store the audio codec bitrate in kbps for the current
+ * {@link Connection}.
+ */
+ public static final String EXTRA_AUDIO_CODEC_BITRATE_KBPS =
+ "android.telecom.extra.AUDIO_CODEC_BITRATE_KBPS";
+
+ /**
+ * Float connection extra key used to store the audio codec bandwidth in khz for the current
+ * {@link Connection}.
+ */
+ public static final String EXTRA_AUDIO_CODEC_BANDWIDTH_KHZ =
+ "android.telecom.extra.AUDIO_CODEC_BANDWIDTH_KHZ";
+ /**
* Connection event used to inform Telecom that it should play the on hold tone. This is used
* to play a tone when the peer puts the current call on hold. Sent to Telecom via
* {@link #sendConnectionEvent(String, Bundle)}.
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 982e5f30e28c..07de61759d59 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -680,6 +680,7 @@ public abstract class InCallService extends Service {
public static abstract class VideoCall {
/** @hide */
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void destroy();
/**
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index ae485d502a1e..5bba747894dc 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -373,6 +373,14 @@ public class TelecomManager {
"android.telecom.extra.CALL_DISCONNECT_MESSAGE";
/**
+ * A string value for {@link #EXTRA_CALL_DISCONNECT_MESSAGE}, indicates the call was dropped by
+ * lower layers
+ * @hide
+ */
+ public static final String CALL_AUTO_DISCONNECT_MESSAGE_STRING =
+ "Call dropped by lower layers";
+
+ /**
* Optional extra for {@link android.telephony.TelephonyManager#ACTION_PHONE_STATE_CHANGED}
* containing the component name of the associated connection service.
* @hide
@@ -984,8 +992,6 @@ public class TelecomManager {
* <p>
* If no {@link PhoneAccount} fits the criteria above, this method will return {@code null}.
*
- * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
- *
* @param uriScheme The URI scheme.
* @return The {@link PhoneAccountHandle} corresponding to the account to be used.
*/
@@ -1162,8 +1168,6 @@ public class TelecomManager {
* calls. The returned list includes only those accounts which have been explicitly enabled
* by the user.
*
- * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
- *
* @see #EXTRA_PHONE_ACCOUNT_HANDLE
* @return A list of {@code PhoneAccountHandle} objects.
*/
@@ -1234,7 +1238,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
@Deprecated
public List<PhoneAccountHandle> getPhoneAccountsForPackage() {
try {
@@ -1363,7 +1367,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void clearPhoneAccounts() {
clearAccounts();
}
@@ -1373,7 +1377,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void clearAccounts() {
try {
if (isServiceConnected()) {
@@ -1405,7 +1409,7 @@ public class TelecomManager {
* @hide
*/
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public ComponentName getDefaultPhoneApp() {
try {
if (isServiceConnected()) {
@@ -1466,9 +1470,6 @@ public class TelecomManager {
* the specified package does not correspond to an installed dialer, or is already
* the default dialer.
*
- * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
- * Requires permission: {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
- *
* @hide
* @deprecated Use
* {@link android.app.role.RoleManager#addRoleHolderAsUser(String, String, int, UserHandle,
@@ -1512,8 +1513,6 @@ public class TelecomManager {
* Return whether a given phone number is the configured voicemail number for a
* particular phone account.
*
- * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
- *
* @param accountHandle The handle for the account to check the voicemail number against
* @param number The number to look up.
*/
@@ -1533,8 +1532,6 @@ public class TelecomManager {
/**
* Return the voicemail number for a given phone account.
*
- * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
- *
* @param accountHandle The handle for the phone account.
* @return The voicemail number for the phone account, and {@code null} if one has not been
* configured.
@@ -1586,8 +1583,6 @@ public class TelecomManager {
/**
* Returns whether there is an ongoing phone call (can be in dialing, ringing, active or holding
* states) originating from either a manager or self-managed {@link ConnectionService}.
- * <p>
- * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
*
* @return {@code true} if there is an ongoing call in either a managed or self-managed
* {@link ConnectionService}, {@code false} otherwise.
@@ -1636,8 +1631,6 @@ public class TelecomManager {
* <p>
* If you also need to know if there are ongoing self-managed calls, use {@link #isInCall()}
* instead.
- * <p>
- * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
*
* @return {@code true} if there is an ongoing call in a managed {@link ConnectionService},
* {@code false} otherwise.
@@ -1711,8 +1704,6 @@ public class TelecomManager {
* If there is a ringing call, calling this method rejects the ringing call. Otherwise the
* foreground call is ended.
* <p>
- * Requires permission {@link android.Manifest.permission#ANSWER_PHONE_CALLS}.
- * <p>
* Note: this method CANNOT be used to end ongoing emergency calls and will return {@code false}
* if an attempt is made to end an emergency call.
*
@@ -1742,9 +1733,6 @@ public class TelecomManager {
* the incoming call requests. This means, for example, that an incoming call requesting
* {@link VideoProfile#STATE_BIDIRECTIONAL} will be answered, accepting that state.
*
- * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
- * {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
- *
* @deprecated Companion apps for wearable devices should use the {@link InCallService} API
* instead.
*/
@@ -1767,9 +1755,6 @@ public class TelecomManager {
* If there is a ringing incoming call, this method accepts the call on behalf of the user,
* with the specified video state.
*
- * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
- * {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
- *
* @param videoState The desired video state to answer the call with.
* @deprecated Companion apps for wearable devices should use the {@link InCallService} API
* instead.
@@ -1981,8 +1966,6 @@ public class TelecomManager {
* Requires that the method-caller be set as the system dialer app.
* </p>
*
- * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
- *
* @param dialString The digits to dial.
* @return True if the digits were processed as an MMI code, false otherwise.
*/
@@ -2007,8 +1990,6 @@ public class TelecomManager {
* Requires that the method-caller be set as the system dialer app.
* </p>
*
- * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
- *
* @param accountHandle The handle for the account the MMI code should apply to.
* @param dialString The digits to dial.
* @return True if the digits were processed as an MMI code, false otherwise.
@@ -2028,8 +2009,8 @@ public class TelecomManager {
}
/**
- * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
- *
+ * Returns a URI (with the content:// scheme) specific to the specified {@link PhoneAccount}
+ * for ADN content retrieval.
* @param accountHandle The handle for the account to derive an adn query URI for or
* {@code null} to return a URI which will use the default account.
* @return The URI (with the content:// scheme) specific to the specified {@link PhoneAccount}
@@ -2053,8 +2034,6 @@ public class TelecomManager {
* <p>
* Requires that the method-caller be set as the system dialer app.
* </p>
- *
- * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void cancelMissedCallsNotification() {
diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
index b92d410f3d6c..76291631b37d 100644
--- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
@@ -33,6 +33,7 @@ import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.TelephonyUtils;
import java.util.ArrayList;
import java.util.List;
@@ -316,7 +317,7 @@ public final class CarrierAppUtils {
String[] packageNames = new String[enabledCarrierPackages.size()];
enabledCarrierPackages.toArray(packageNames);
permissionManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames,
- UserHandle.of(userId), Runnable::run, isSuccess -> { });
+ UserHandle.of(userId), TelephonyUtils.DIRECT_EXECUTOR, isSuccess -> { });
}
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Could not reach PackageManager", e);
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index b8ca3267cf9e..125296540688 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -34,6 +34,7 @@ import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
@@ -44,6 +45,8 @@ public final class TelephonyUtils {
public static boolean IS_USER = "user".equals(android.os.Build.TYPE);
public static boolean IS_DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
+ public static final Executor DIRECT_EXECUTOR = Runnable::run;
+
/**
* Verify that caller holds {@link android.Manifest.permission#DUMP}.
*
diff --git a/telephony/java/android/telephony/CarrierBandwidth.aidl b/telephony/java/android/telephony/CarrierBandwidth.aidl
new file mode 100644
index 000000000000..d0861b88e737
--- /dev/null
+++ b/telephony/java/android/telephony/CarrierBandwidth.aidl
@@ -0,0 +1,17 @@
+/*
+ * 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.telephony;
+parcelable CarrierBandwidth; \ No newline at end of file
diff --git a/telephony/java/android/telephony/CarrierBandwidth.java b/telephony/java/android/telephony/CarrierBandwidth.java
new file mode 100644
index 000000000000..17747a3919ee
--- /dev/null
+++ b/telephony/java/android/telephony/CarrierBandwidth.java
@@ -0,0 +1,208 @@
+/*
+ * 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.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Defines downlink and uplink capacity of a network in kbps
+ * @hide
+ */
+@SystemApi
+public final class CarrierBandwidth implements Parcelable {
+ /**
+ * Any field that is not reported shall be set to INVALID
+ */
+ public static final int INVALID = -1;
+
+ /**
+ * Estimated downlink capacity in kbps of the primary carrier.
+ * This bandwidth estimate shall be the estimated maximum sustainable link bandwidth.
+ * This will be {@link #INVALID} if the network is not connected
+ */
+ private int mPrimaryDownlinkCapacityKbps;
+
+ /**
+ * Estimated uplink capacity in kbps of the primary carrier.
+ * This bandwidth estimate shall be the estimated maximum sustainable link bandwidth.
+ * This will be {@link #INVALID} if the network is not connected
+ */
+ private int mPrimaryUplinkCapacityKbps;
+
+ /**
+ * Estimated downlink capacity in kbps of the secondary carrier in a dual connected network.
+ * This bandwidth estimate shall be the estimated maximum sustainable link bandwidth.
+ * This will be {@link #INVALID} if the network is not connected
+ */
+ private int mSecondaryDownlinkCapacityKbps;
+
+ /**
+ * Estimated uplink capacity in kbps of the secondary carrier in a dual connected network.
+ * This bandwidth estimate shall be the estimated maximum sustainable link bandwidth.
+ * This will be {@link #INVALID} if the network is not connected
+ */
+ private int mSecondaryUplinkCapacityKbps;
+
+ /** @hide **/
+ public CarrierBandwidth(Parcel in) {
+ mPrimaryDownlinkCapacityKbps = in.readInt();
+ mPrimaryUplinkCapacityKbps = in.readInt();
+ mSecondaryDownlinkCapacityKbps = in.readInt();
+ mSecondaryUplinkCapacityKbps = in.readInt();
+ }
+
+ /** @hide **/
+ public CarrierBandwidth() {
+ mPrimaryDownlinkCapacityKbps = INVALID;
+ mPrimaryUplinkCapacityKbps = INVALID;
+ mSecondaryDownlinkCapacityKbps = INVALID;
+ mSecondaryUplinkCapacityKbps = INVALID;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param primaryDownlinkCapacityKbps Estimated downlink capacity in kbps of
+ * the primary carrier.
+ * @param primaryUplinkCapacityKbps Estimated uplink capacity in kbps of
+ * the primary carrier.
+ * @param secondaryDownlinkCapacityKbps Estimated downlink capacity in kbps of
+ * the secondary carrier
+ * @param secondaryUplinkCapacityKbps Estimated uplink capacity in kbps of
+ * the secondary carrier
+ */
+ public CarrierBandwidth(int primaryDownlinkCapacityKbps, int primaryUplinkCapacityKbps,
+ int secondaryDownlinkCapacityKbps, int secondaryUplinkCapacityKbps) {
+ mPrimaryDownlinkCapacityKbps = primaryDownlinkCapacityKbps;
+ mPrimaryUplinkCapacityKbps = primaryUplinkCapacityKbps;
+ mSecondaryDownlinkCapacityKbps = secondaryDownlinkCapacityKbps;
+ mSecondaryUplinkCapacityKbps = secondaryUplinkCapacityKbps;
+ }
+
+ /**
+ * Retrieves the upstream bandwidth for the primary network in Kbps. This always only refers to
+ * the estimated first hop transport bandwidth.
+ * This will be INVALID if the network is not connected
+ *
+ * @return The estimated first hop upstream (device to network) bandwidth.
+ */
+ public int getPrimaryDownlinkCapacityKbps() {
+ return mPrimaryDownlinkCapacityKbps;
+ }
+
+ /**
+ * Retrieves the downstream bandwidth for the primary network in Kbps. This always only refers
+ * to the estimated first hop transport bandwidth.
+ * This will be INVALID if the network is not connected
+ *
+ * @return The estimated first hop downstream (network to device) bandwidth.
+ */
+ public int getPrimaryUplinkCapacityKbps() {
+ return mPrimaryUplinkCapacityKbps;
+ }
+
+ /**
+ * Retrieves the upstream bandwidth for the secondary network in Kbps. This always only refers
+ * to the estimated first hop transport bandwidth.
+ * This will be INVALID if the network is not connected
+ *
+ * @return The estimated first hop upstream (device to network) bandwidth.
+ */
+ public int getSecondaryDownlinkCapacityKbps() {
+ return mSecondaryDownlinkCapacityKbps;
+ }
+
+ /**
+ * Retrieves the downstream bandwidth for the secondary network in Kbps. This always only
+ * refers to the estimated first hop transport bandwidth.
+ * This will be INVALID if the network is not connected
+ *
+ * @return The estimated first hop downstream (network to device) bandwidth.
+ */
+ public int getSecondaryUplinkCapacityKbps() {
+ return mSecondaryUplinkCapacityKbps;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "CarrierBandwidth: {primaryDownlinkCapacityKbps=" + mPrimaryDownlinkCapacityKbps
+ + " primaryUplinkCapacityKbps=" + mPrimaryUplinkCapacityKbps
+ + " secondaryDownlinkCapacityKbps=" + mSecondaryDownlinkCapacityKbps
+ + " secondaryUplinkCapacityKbps=" + mSecondaryUplinkCapacityKbps
+ + "}";
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mPrimaryDownlinkCapacityKbps,
+ mPrimaryUplinkCapacityKbps,
+ mSecondaryDownlinkCapacityKbps,
+ mSecondaryUplinkCapacityKbps);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o == null || !(o instanceof CallQuality) || hashCode() != o.hashCode()) {
+ return false;
+ }
+ if (this == o) {
+ return true;
+ }
+ CarrierBandwidth s = (CarrierBandwidth) o;
+ return (mPrimaryDownlinkCapacityKbps == s.mPrimaryDownlinkCapacityKbps
+ && mPrimaryUplinkCapacityKbps == s.mPrimaryUplinkCapacityKbps
+ && mSecondaryDownlinkCapacityKbps == s.mSecondaryDownlinkCapacityKbps
+ && mSecondaryDownlinkCapacityKbps == s.mSecondaryDownlinkCapacityKbps);
+ }
+
+ /**
+ * {@link Parcelable#describeContents}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@link Parcelable#writeToParcel}
+ * @hide
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mPrimaryDownlinkCapacityKbps);
+ dest.writeInt(mPrimaryUplinkCapacityKbps);
+ dest.writeInt(mSecondaryDownlinkCapacityKbps);
+ dest.writeInt(mSecondaryUplinkCapacityKbps);
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<CarrierBandwidth> CREATOR =
+ new Parcelable.Creator() {
+ public CarrierBandwidth createFromParcel(Parcel in) {
+ return new CarrierBandwidth(in);
+ }
+
+ public CarrierBandwidth[] newArray(int size) {
+ return new CarrierBandwidth[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index b806313e32f8..902dc0619014 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4792,7 +4792,7 @@ public class CarrierConfigManager {
*/
@NonNull
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public static PersistableBundle getDefaultConfig() {
return new PersistableBundle(sDefaults);
}
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java
index 8f5ec365e65c..e595002d175b 100644
--- a/telephony/java/android/telephony/CellLocation.java
+++ b/telephony/java/android/telephony/CellLocation.java
@@ -98,12 +98,14 @@ public abstract class CellLocation {
/**
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void fillInNotifierBundle(Bundle bundle);
/**
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract boolean isEmpty();
@@ -111,6 +113,7 @@ public abstract class CellLocation {
* Invalidate this object. The location area code and the cell id are set to -1.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract void setStateInvalid();
/**
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index 28feab27a794..42d7707c97d9 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -22,7 +22,12 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.telephony.BinderCacheManager;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyFrameworkInitializer;
+import android.telephony.ims.aidl.IImsRcsController;
+
+import com.android.internal.telephony.ITelephony;
/**
* Provides access to information about Telephony IMS services on the device.
@@ -30,8 +35,6 @@ import android.telephony.SubscriptionManager;
@SystemService(Context.TELEPHONY_IMS_SERVICE)
public class ImsManager {
- private Context mContext;
-
/**
* <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
@@ -87,6 +90,14 @@ public class ImsManager {
public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE =
"android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
+ // Cache Telephony Binder interfaces, one cache per process.
+ private static final BinderCacheManager<ITelephony> sTelephonyCache =
+ new BinderCacheManager<>(ImsManager::getITelephonyInterface);
+ private static final BinderCacheManager<IImsRcsController> sRcsCache =
+ new BinderCacheManager<>(ImsManager::getIImsRcsControllerInterface);
+
+ private final Context mContext;
+
/**
* Use {@link Context#getSystemService(String)} to get an instance of this class.
* @hide
@@ -108,7 +119,7 @@ public class ImsManager {
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
- return new ImsRcsManager(mContext, subscriptionId);
+ return new ImsRcsManager(mContext, subscriptionId, sRcsCache);
}
/**
@@ -124,17 +135,19 @@ public class ImsManager {
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
- return new ImsMmTelManager(subscriptionId);
+ return new ImsMmTelManager(subscriptionId, sTelephonyCache);
}
/**
- * Create an instance of SipDelegateManager for the subscription id specified.
+ * Create an instance of {@link SipDelegateManager} for the subscription id specified.
* <p>
- * Used for RCS single registration cases, where an IMS application needs to forward SIP
- * traffic through the device's IMS service.
- * @param subscriptionId The ID of the subscription that this SipDelegateManager will use.
+ * Allows an IMS application to forward SIP traffic through the device's IMS service,
+ * which is used for cellular carriers that require the device to share a single IMS
+ * registration for both MMTEL and RCS features.
+ * @param subscriptionId The ID of the subscription that this {@link SipDelegateManager} will
+ * be bound to.
* @throws IllegalArgumentException if the subscription is invalid.
- * @return a SipDelegateManager instance for the specified subscription ID.
+ * @return a {@link SipDelegateManager} instance for the specified subscription ID.
* @hide
*/
@SystemApi
@@ -144,6 +157,22 @@ public class ImsManager {
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
- return new SipDelegateManager(mContext, subscriptionId);
+ return new SipDelegateManager(mContext, subscriptionId, sRcsCache);
+ }
+
+ private static IImsRcsController getIImsRcsControllerInterface() {
+ return IImsRcsController.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyImsServiceRegisterer()
+ .get());
+ }
+
+ private static ITelephony getITelephonyInterface() {
+ return ITelephony.Stub.asInterface(
+ TelephonyFrameworkInitializer
+ .getTelephonyServiceManager()
+ .getTelephonyServiceRegisterer()
+ .get());
}
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index f8a200a5f8d3..8507d8512a5c 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.AccessNetworkConstants.TransportType;
@@ -635,7 +636,8 @@ public final class NetworkRegistrationInfo implements Parcelable {
.append(" cellIdentity=").append(mCellIdentity)
.append(" voiceSpecificInfo=").append(mVoiceSpecificInfo)
.append(" dataSpecificInfo=").append(mDataSpecificInfo)
- .append(" nrState=").append(nrStateToString(mNrState))
+ .append(" nrState=").append(Build.IS_DEBUGGABLE
+ ? nrStateToString(mNrState) : "****")
.append(" rRplmn=").append(mRplmn)
.append(" isUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
.append("}").toString();
diff --git a/telephony/java/android/telephony/PinResult.java b/telephony/java/android/telephony/PinResult.java
index c2a4f33e95b9..b8c1ffe58371 100644
--- a/telephony/java/android/telephony/PinResult.java
+++ b/telephony/java/android/telephony/PinResult.java
@@ -19,6 +19,7 @@ package android.telephony;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -27,10 +28,16 @@ import com.android.internal.telephony.PhoneConstants;
import java.util.Objects;
/**
- * Holds the result from a pin attempt.
+ * Holds the result from a PIN attempt.
+ *
+ * @see TelephonyManager#supplyIccLockPin
+ * @see TelephonyManager#supplyIccLockPuk
+ * @see TelephonyManager#setIccLockEnabled
+ * @see TelephonyManager#changeIccLockPin
*
* @hide
*/
+@SystemApi
public final class PinResult implements Parcelable {
/** @hide */
@IntDef({
@@ -64,24 +71,24 @@ public final class PinResult implements Parcelable {
private static final PinResult sFailedResult =
new PinResult(PinResult.PIN_RESULT_TYPE_FAILURE, -1);
- private final @PinResultType int mType;
+ private final @PinResultType int mResult;
private final int mAttemptsRemaining;
/**
- * Returns either success, incorrect or failure.
+ * Returns the result of the PIN attempt.
*
- * @see #PIN_RESULT_TYPE_SUCCESS
- * @see #PIN_RESULT_TYPE_INCORRECT
- * @see #PIN_RESULT_TYPE_FAILURE
- * @return The result type of the pin attempt.
+ * @return The result of the PIN attempt.
*/
- public @PinResultType int getType() {
- return mType;
+ public @PinResultType int getResult() {
+ return mResult;
}
/**
- * The number of pin attempts remaining.
+ * Returns the number of PIN attempts remaining.
+ * This will be set when {@link #getResult} is {@link #PIN_RESULT_TYPE_INCORRECT}.
+ * Indicates the number of attempts at entering the PIN before the SIM will be locked and
+ * require a PUK unlock to be performed.
*
* @return Number of attempts remaining.
*/
@@ -89,22 +96,32 @@ public final class PinResult implements Parcelable {
return mAttemptsRemaining;
}
+ /**
+ * Used to indicate a failed PIN attempt result.
+ *
+ * @return default PinResult for failure.
+ *
+ * @hide
+ */
@NonNull
public static PinResult getDefaultFailedResult() {
return sFailedResult;
}
/**
- * PinResult constructor
+ * PinResult constructor.
*
- * @param type The type of pin result.
+ * @param result The pin result value.
* @see #PIN_RESULT_TYPE_SUCCESS
* @see #PIN_RESULT_TYPE_INCORRECT
* @see #PIN_RESULT_TYPE_FAILURE
+ * @see #PIN_RESULT_TYPE_ABORTED
* @param attemptsRemaining Number of pin attempts remaining.
+ *
+ * @hide
*/
- public PinResult(@PinResultType int type, int attemptsRemaining) {
- mType = type;
+ public PinResult(@PinResultType int result, int attemptsRemaining) {
+ mResult = result;
mAttemptsRemaining = attemptsRemaining;
}
@@ -114,7 +131,7 @@ public final class PinResult implements Parcelable {
* @hide
*/
private PinResult(Parcel in) {
- mType = in.readInt();
+ mResult = in.readInt();
mAttemptsRemaining = in.readInt();
}
@@ -124,11 +141,11 @@ public final class PinResult implements Parcelable {
@NonNull
@Override
public String toString() {
- return "type: " + getType() + ", attempts remaining: " + getAttemptsRemaining();
+ return "result: " + getResult() + ", attempts remaining: " + getAttemptsRemaining();
}
/**
- * Required to be Parcelable
+ * Describe the contents of this object.
*/
@Override
public int describeContents() {
@@ -136,15 +153,17 @@ public final class PinResult implements Parcelable {
}
/**
- * Required to be Parcelable
+ * Write this object to a Parcel.
*/
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeInt(mType);
+ out.writeInt(mResult);
out.writeInt(mAttemptsRemaining);
}
- /** Required to be Parcelable */
+ /**
+ * Parcel creator class.
+ */
public static final @NonNull Parcelable.Creator<PinResult> CREATOR = new Creator<PinResult>() {
public PinResult createFromParcel(Parcel in) {
return new PinResult(in);
@@ -156,7 +175,7 @@ public final class PinResult implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mAttemptsRemaining, mType);
+ return Objects.hash(mAttemptsRemaining, mResult);
}
@Override
@@ -171,7 +190,7 @@ public final class PinResult implements Parcelable {
return false;
}
PinResult other = (PinResult) obj;
- return (mType == other.mType
+ return (mResult == other.mResult
&& mAttemptsRemaining == other.mAttemptsRemaining);
}
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 41b3ee672f46..dedb1afa2495 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1102,7 +1102,8 @@ public class ServiceState implements Parcelable {
.append(", isUsingCarrierAggregation=").append(isUsingCarrierAggregation())
.append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
.append(", mNetworkRegistrationInfos=").append(mNetworkRegistrationInfos)
- .append(", mNrFrequencyRange=").append(mNrFrequencyRange)
+ .append(", mNrFrequencyRange=").append(Build.IS_DEBUGGABLE
+ ? mNrFrequencyRange : FREQUENCY_RANGE_UNKNOWN)
.append(", mOperatorAlphaLongRaw=").append(mOperatorAlphaLongRaw)
.append(", mOperatorAlphaShortRaw=").append(mOperatorAlphaShortRaw)
.append(", mIsDataRoamingFromRegistration=")
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 7f87019dbbe2..83e63ef29e2c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1365,6 +1365,7 @@ public class SubscriptionManager {
* include those that were inserted before, maybe empty but not null.
* @hide
*/
+ @NonNull
@UnsupportedAppUsage
public List<SubscriptionInfo> getAllSubscriptionInfoList() {
if (VDBG) logd("[getAllSubscriptionInfoList]+");
@@ -1382,7 +1383,7 @@ public class SubscriptionManager {
}
if (result == null) {
- result = new ArrayList<>();
+ result = Collections.emptyList();
}
return result;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 425addc70dae..4eacad3fd0ac 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4661,7 +4661,7 @@ public class TelephonyManager {
* be implemented instead.
*/
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void setVisualVoicemailEnabled(PhoneAccountHandle phoneAccountHandle, boolean enabled){
}
@@ -4676,7 +4676,7 @@ public class TelephonyManager {
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public boolean isVisualVoicemailEnabled(PhoneAccountHandle phoneAccountHandle){
return false;
}
@@ -4695,7 +4695,7 @@ public class TelephonyManager {
* @hide
*/
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
@Nullable
public Bundle getVisualVoicemailSettings(){
try {
@@ -8621,7 +8621,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public int checkCarrierPrivilegesForPackage(String pkgName) {
try {
ITelephony telephony = getITelephony();
@@ -8637,7 +8637,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public int checkCarrierPrivilegesForPackageAnyPhone(String pkgName) {
try {
ITelephony telephony = getITelephony();
@@ -8713,7 +8713,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void dial(String number) {
try {
ITelephony telephony = getITelephony();
@@ -8772,7 +8772,7 @@ public class TelephonyManager {
*/
@Deprecated
@SystemApi
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void silenceRinger() {
// No-op
}
@@ -8871,9 +8871,13 @@ public class TelephonyManager {
return false;
}
- /** @hide */
+ /**
+ * @deprecated use {@link #supplyIccLockPin(String)} instead.
+ * @hide
+ */
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @Deprecated
public int[] supplyPinReportResult(String pin) {
try {
ITelephony telephony = getITelephony();
@@ -8885,65 +8889,91 @@ public class TelephonyManager {
return new int[0];
}
- /** @hide */
+ /**
+ * @deprecated use {@link #supplyIccLockPuk(String, String)} instead.
+ * @hide
+ */
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @Deprecated
public int[] supplyPukReportResult(String puk, String pin) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
return telephony.supplyPukReportResultForSubscriber(getSubId(), puk, pin);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#]", e);
+ Log.e(TAG, "Error calling ITelephony#supplyPukReportResultForSubscriber", e);
}
return new int[0];
}
/**
- * Used when the user attempts to enter their pin.
+ * Supplies a PIN to unlock the ICC and returns the corresponding {@link PinResult}.
+ * Used when the user enters their ICC unlock PIN to attempt an unlock.
*
- * @param pin The user entered pin.
- * @return The result of the pin.
+ * @param pin The user entered PIN.
+ * @return The result of the PIN.
+ * @throws SecurityException if the caller doesn't have the permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @hide
*/
- @Nullable
+ @SystemApi
+ @NonNull
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public PinResult supplyPinReportPinResult(@NonNull String pin) {
+ public PinResult supplyIccLockPin(@NonNull String pin) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
int[] result = telephony.supplyPinReportResultForSubscriber(getSubId(), pin);
return new PinResult(result[0], result[1]);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#supplyPinReportResultForSubscriber", e);
+ Log.e(TAG, "Error calling ITelephony#supplyIccLockPin", e);
+ e.rethrowFromSystemServer();
}
- return null;
+ return PinResult.getDefaultFailedResult();
}
/**
- * Used when the user attempts to enter the puk or their pin.
+ * Supplies a PUK and PIN to unlock the ICC and returns the corresponding {@link PinResult}.
+ * Used when the user enters their ICC unlock PUK and PIN to attempt an unlock.
+ *
+ * @param puk The product unlocking key.
+ * @param pin The user entered PIN.
+ * @return The result of the PUK and PIN.
+ * @throws SecurityException if the caller doesn't have the permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
*
- * @param puk The product unblocking key.
- * @param pin The user entered pin.
- * @return The result of the pin.
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @hide
*/
- @Nullable
+ @SystemApi
+ @NonNull
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public PinResult supplyPukReportPinResult(@NonNull String puk, @NonNull String pin) {
+ public PinResult supplyIccLockPuk(@NonNull String puk, @NonNull String pin) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
int[] result = telephony.supplyPukReportResultForSubscriber(getSubId(), puk, pin);
return new PinResult(result[0], result[1]);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#]", e);
+ Log.e(TAG, "Error calling ITelephony#supplyIccLockPuk", e);
+ e.rethrowFromSystemServer();
}
- return null;
+ return PinResult.getDefaultFailedResult();
}
/**
@@ -9380,11 +9410,22 @@ public class TelephonyManager {
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
* given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
*
- * @return one of {@link #CDMA_ROAMING_MODE_RADIO_DEFAULT}, {@link #CDMA_ROAMING_MODE_HOME},
- * {@link #CDMA_ROAMING_MODE_AFFILIATED}, {@link #CDMA_ROAMING_MODE_ANY}.
+ * @return the CDMA roaming mode.
+ * @throws SecurityException if the caller does not have the permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ *
+ * @see #CDMA_ROAMING_MODE_RADIO_DEFAULT
+ * @see #CDMA_ROAMING_MODE_HOME
+ * @see #CDMA_ROAMING_MODE_AFFILIATED
+ * @see #CDMA_ROAMING_MODE_ANY
+ *
+ * <p>Requires permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @CdmaRoamingMode int getCdmaRoamingMode() {
int mode = CDMA_ROAMING_MODE_RADIO_DEFAULT;
@@ -9392,9 +9433,12 @@ public class TelephonyManager {
ITelephony telephony = getITelephony();
if (telephony != null) {
mode = telephony.getCdmaRoamingMode(getSubId());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
Log.e(TAG, "Error calling ITelephony#getCdmaRoamingMode", ex);
+ ex.rethrowFromSystemServer();
}
return mode;
}
@@ -9405,25 +9449,36 @@ public class TelephonyManager {
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
* given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
*
- * @param mode should be one of {@link #CDMA_ROAMING_MODE_RADIO_DEFAULT},
- * {@link #CDMA_ROAMING_MODE_HOME}, {@link #CDMA_ROAMING_MODE_AFFILIATED},
- * {@link #CDMA_ROAMING_MODE_ANY}.
+ * @param mode CDMA roaming mode.
+ * @throws SecurityException if the caller does not have the permission.
+ * @throws IllegalStateException if the Telephony process or radio is not currently available.
*
- * @return {@code true} if successed.
+ * @see #CDMA_ROAMING_MODE_RADIO_DEFAULT
+ * @see #CDMA_ROAMING_MODE_HOME
+ * @see #CDMA_ROAMING_MODE_AFFILIATED
+ * @see #CDMA_ROAMING_MODE_ANY
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public boolean setCdmaRoamingMode(@CdmaRoamingMode int mode) {
+ public void setCdmaRoamingMode(@CdmaRoamingMode int mode) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.setCdmaRoamingMode(getSubId(), mode);
+ boolean result = telephony.setCdmaRoamingMode(getSubId(), mode);
+ if (!result) throw new IllegalStateException("radio is unavailable.");
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
Log.e(TAG, "Error calling ITelephony#setCdmaRoamingMode", ex);
+ ex.rethrowFromSystemServer();
}
- return false;
}
/** @hide */
@@ -9435,48 +9490,94 @@ public class TelephonyManager {
@Retention(RetentionPolicy.SOURCE)
public @interface CdmaSubscription{}
- /** Used for CDMA subscription mode, it'll be UNKNOWN if there is no Subscription source.
+ /**
+ * Used for CDMA subscription mode, it'll be UNKNOWN if there is no Subscription source.
* @hide
*/
+ @SystemApi
public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1;
- /** Used for CDMA subscription mode: RUIM/SIM (default)
+ /**
+ * Used for CDMA subscription mode: RUIM/SIM (default)
* @hide
*/
+ @SystemApi
public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0;
- /** Used for CDMA subscription mode: NV -> non-volatile memory
+ /**
+ * Used for CDMA subscription mode: NV -> non-volatile memory
* @hide
*/
+ @SystemApi
public static final int CDMA_SUBSCRIPTION_NV = 1;
- /** @hide */
- public static final int PREFERRED_CDMA_SUBSCRIPTION = CDMA_SUBSCRIPTION_RUIM_SIM;
+ /**
+ * Gets the subscription mode for CDMA phone.
+ *
+ * @return the CDMA subscription mode.
+ * @throws SecurityException if the caller does not have the permission.
+ * @throws IllegalStateException if the Telephony process or radio is not currently available.
+ *
+ * @see #CDMA_SUBSCRIPTION_UNKNOWN
+ * @see #CDMA_SUBSCRIPTION_RUIM_SIM
+ * @see #CDMA_SUBSCRIPTION_NV
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public @CdmaSubscription int getCdmaSubscriptionMode() {
+ int mode = CDMA_SUBSCRIPTION_RUIM_SIM;
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ mode = telephony.getCdmaSubscriptionMode(getSubId());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Error calling ITelephony#getCdmaSubscriptionMode", ex);
+ ex.rethrowFromSystemServer();
+ }
+ return mode;
+ }
/**
* Sets the subscription mode for CDMA phone to the given mode {@code mode}.
*
- * @param mode CDMA subscription mode
- *
- * @return {@code true} if successed.
+ * @param mode CDMA subscription mode.
+ * @throws SecurityException if the caller does not have the permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
*
* @see #CDMA_SUBSCRIPTION_UNKNOWN
* @see #CDMA_SUBSCRIPTION_RUIM_SIM
* @see #CDMA_SUBSCRIPTION_NV
*
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public boolean setCdmaSubscriptionMode(@CdmaSubscription int mode) {
+ public void setCdmaSubscriptionMode(@CdmaSubscription int mode) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.setCdmaSubscriptionMode(getSubId(), mode);
+ boolean result = telephony.setCdmaSubscriptionMode(getSubId(), mode);
+ if (!result) throw new IllegalStateException("radio is unavailable.");
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
Log.e(TAG, "Error calling ITelephony#setCdmaSubscriptionMode", ex);
+ ex.rethrowFromSystemServer();
}
- return false;
}
/**
@@ -13557,18 +13658,22 @@ public class TelephonyManager {
}
/**
- * The IccLock state or password was changed successfully.
+ * Indicates that the ICC PIN lock state or PIN was changed successfully.
* @hide
*/
public static final int CHANGE_ICC_LOCK_SUCCESS = Integer.MAX_VALUE;
/**
- * Check whether ICC pin lock is enabled.
- * This is a sync call which returns the cached pin enabled state.
- *
- * @return {@code true} if ICC lock enabled, {@code false} if ICC lock disabled.
+ * Check whether ICC PIN lock is enabled.
+ * This is a sync call which returns the cached PIN enabled state.
*
+ * @return {@code true} if ICC PIN lock enabled, {@code false} if disabled.
* @throws SecurityException if the caller doesn't have the permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @hide
*/
@@ -13580,81 +13685,124 @@ public class TelephonyManager {
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.isIccLockEnabled(getSubId());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException e) {
Log.e(TAG, "isIccLockEnabled RemoteException", e);
+ e.rethrowFromSystemServer();
}
return false;
}
/**
- * Set the ICC pin lock enabled or disabled.
- *
- * If enable/disable ICC pin lock successfully, a value of {@link Integer#MAX_VALUE} is
- * returned.
- * If an incorrect old password is specified, the return value will indicate how many more
- * attempts the user can make to change the password before the SIM is locked.
- * Using PUK code to unlock SIM if enter the incorrect old password 3 times.
- *
- * @param enabled "true" for locked, "false" for unlocked.
- * @param password needed to change the ICC pin state, aka. Pin1
- * @return an integer representing the status of IccLock enabled or disabled in the following
- * three cases:
- * - {@link TelephonyManager#CHANGE_ICC_LOCK_SUCCESS} if enabled or disabled IccLock
- * successfully.
- * - Positive number and zero for remaining password attempts.
- * - Negative number for other failure cases (such like enabling/disabling PIN failed).
+ * Enable or disable the ICC PIN lock.
*
+ * @param enabled "true" for locked, "false" for unlocked.
+ * @param pin needed to change the ICC PIN lock, aka. Pin1.
+ * @return the result of enabling or disabling the ICC PIN lock.
* @throws SecurityException if the caller doesn't have the permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @hide
*/
+ @SystemApi
+ @NonNull
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public int setIccLockEnabled(boolean enabled, @NonNull String password) {
- checkNotNull(password, "setIccLockEnabled password can't be null.");
+ public PinResult setIccLockEnabled(boolean enabled, @NonNull String pin) {
+ checkNotNull(pin, "setIccLockEnabled pin can't be null.");
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.setIccLockEnabled(getSubId(), enabled, password);
+ int result = telephony.setIccLockEnabled(getSubId(), enabled, pin);
+ if (result == CHANGE_ICC_LOCK_SUCCESS) {
+ return new PinResult(PinResult.PIN_RESULT_TYPE_SUCCESS, 0);
+ } else if (result < 0) {
+ return PinResult.getDefaultFailedResult();
+ } else {
+ return new PinResult(PinResult.PIN_RESULT_TYPE_INCORRECT, result);
+ }
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException e) {
Log.e(TAG, "setIccLockEnabled RemoteException", e);
+ e.rethrowFromSystemServer();
}
- return 0;
+ return PinResult.getDefaultFailedResult();
}
/**
- * Change the ICC password used in ICC pin lock.
- *
- * If the password was changed successfully, a value of {@link Integer#MAX_VALUE} is returned.
- * If an incorrect old password is specified, the return value will indicate how many more
- * attempts the user can make to change the password before the SIM is locked.
- * Using PUK code to unlock SIM if enter the incorrect old password 3 times.
- *
- * @param oldPassword is the old password
- * @param newPassword is the new password
- * @return an integer representing the status of IccLock changed in the following three cases:
- * - {@link TelephonyManager#CHANGE_ICC_LOCK_SUCCESS} if changed IccLock successfully.
- * - Positive number and zero for remaining password attempts.
- * - Negative number for other failure cases (such like enabling/disabling PIN failed).
+ * Change the ICC lock PIN.
*
+ * @param oldPin is the old PIN
+ * @param newPin is the new PIN
+ * @return The result of changing the ICC lock PIN.
* @throws SecurityException if the caller doesn't have the permission.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @hide
*/
+ @SystemApi
+ @NonNull
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public int changeIccLockPassword(@NonNull String oldPassword, @NonNull String newPassword) {
- checkNotNull(oldPassword, "changeIccLockPassword oldPassword can't be null.");
- checkNotNull(newPassword, "changeIccLockPassword newPassword can't be null.");
+ public PinResult changeIccLockPin(@NonNull String oldPin, @NonNull String newPin) {
+ checkNotNull(oldPin, "changeIccLockPin oldPin can't be null.");
+ checkNotNull(newPin, "changeIccLockPin newPin can't be null.");
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.changeIccLockPassword(getSubId(), oldPassword, newPassword);
+ int result = telephony.changeIccLockPassword(getSubId(), oldPin, newPin);
+ if (result == CHANGE_ICC_LOCK_SUCCESS) {
+ return new PinResult(PinResult.PIN_RESULT_TYPE_SUCCESS, 0);
+ } else if (result < 0) {
+ return PinResult.getDefaultFailedResult();
+ } else {
+ return new PinResult(PinResult.PIN_RESULT_TYPE_INCORRECT, result);
+ }
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException e) {
- Log.e(TAG, "changeIccLockPassword RemoteException", e);
+ Log.e(TAG, "changeIccLockPin RemoteException", e);
+ e.rethrowFromSystemServer();
}
- return 0;
+ return PinResult.getDefaultFailedResult();
+ }
+
+ /**
+ * Get carrier bandwidth. In case of Dual connected network this will report
+ * bandwidth per primary and secondary network.
+ * @return CarrierBandwidth with bandwidth of both primary and secondary carrier.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @NonNull
+ public CarrierBandwidth getCarrierBandwidth() {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ return service.getCarrierBandwidth(getSubId());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "getCarrierBandwidth RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+
+ //Should not reach. Adding return statement to make compiler happy
+ return null;
}
/**
@@ -13974,6 +14122,15 @@ public class TelephonyManager {
}
/**
+ * Setup sITelephony for testing.
+ * @hide
+ */
+ @VisibleForTesting
+ public static void setupITelephonyForTest(ITelephony telephony) {
+ sITelephony = telephony;
+ }
+
+ /**
* Whether device can connect to 5G network when two SIMs are active.
* @hide
* TODO b/153669716: remove or make system API.
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index ff9329ef9742..d58fa912dce2 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -18,6 +18,8 @@ package android.telephony.data;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.annotation.SystemApi;
import android.content.ContentValues;
import android.database.Cursor;
import android.hardware.radio.V1_5.ApnTypes;
@@ -26,6 +28,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.provider.Telephony;
import android.provider.Telephony.Carriers;
+import android.telephony.Annotation;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.NetworkType;
import android.telephony.ServiceState;
@@ -133,6 +136,25 @@ public class ApnSetting implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface Skip464XlatStatus {}
+ /** @hide */
+ @StringDef(value = {
+ TYPE_ALL_STRING,
+ TYPE_CBS_STRING,
+ TYPE_DEFAULT_STRING,
+ TYPE_DUN_STRING,
+ TYPE_EMERGENCY_STRING,
+ TYPE_FOTA_STRING,
+ TYPE_HIPRI_STRING,
+ TYPE_IA_STRING,
+ TYPE_IMS_STRING,
+ TYPE_MCX_STRING,
+ TYPE_MMS_STRING,
+ TYPE_SUPL_STRING,
+ TYPE_XCAP_STRING,
+ }, prefix = "TYPE_", suffix = "_STRING")
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ApnTypeString {}
+
/**
* APN types for data connections. These are usage categories for an APN
* entry. One APN entry may support multiple APN types, eg, a single APN
@@ -140,99 +162,133 @@ public class ApnSetting implements Parcelable {
* connections.<br/>
* APN_TYPE_ALL is a special type to indicate that this APN entry can
* service all data connections.
- * <p>
- * Note: The goal is to deprecate this. Due to the Carrier Table being used
- * directly, this isn't feasible right now.
*
* @hide
*/
+ @SystemApi
public static final String TYPE_ALL_STRING = "*";
/**
* APN type for default data traffic
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_DEFAULT_STRING = "default";
/**
- * APN type for MMS traffic
+ * APN type for MMS (Multimedia Messaging Service) traffic.
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_MMS_STRING = "mms";
/**
- * APN type for SUPL assisted GPS
+ * APN type for SUPL (Secure User Plane Location) assisted GPS.
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_SUPL_STRING = "supl";
/**
- * APN type for DUN traffic
+ * APN type for DUN (Dial-up networking) traffic
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_DUN_STRING = "dun";
/**
- * APN type for HiPri traffic
+ * APN type for high-priority traffic
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_HIPRI_STRING = "hipri";
/**
- * APN type for FOTA
+ * APN type for FOTA (Firmware over-the-air) traffic.
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_FOTA_STRING = "fota";
/**
- * APN type for IMS
+ * APN type for IMS (IP Multimedia Subsystem) traffic.
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_IMS_STRING = "ims";
/**
- * APN type for CBS
+ * APN type for CBS (Carrier Branded Services) traffic.
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_CBS_STRING = "cbs";
/**
- * APN type for IA Initial Attach APN
+ * APN type for the IA (Initial Attach) APN
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_IA_STRING = "ia";
/**
* APN type for Emergency PDN. This is not an IA apn, but is used
* for access to carrier services in an emergency call situation.
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_EMERGENCY_STRING = "emergency";
/**
- * APN type for Mission Critical Services
+ * APN type for Mission Critical Services.
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_MCX_STRING = "mcx";
/**
- * APN type for XCAP
+ * APN type for XCAP (XML Configuration Access Protocol) traffic.
*
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_XCAP_STRING = "xcap";
@@ -1426,16 +1482,43 @@ public class ApnSetting implements Parcelable {
}
/**
- * @param apnType APN type
- * @return APN type in string format
+ * Converts the integer representation of APN type to its string representation.
+ *
+ * @param apnType APN type as an integer
+ * @return String representation of the APN type, or an empty string if the provided integer is
+ * not a valid APN type.
* @hide
*/
- public static String getApnTypeString(int apnType) {
+ @SystemApi
+ public static @NonNull @ApnTypeString String getApnTypeString(@Annotation.ApnType int apnType) {
if (apnType == TYPE_ALL) {
return "*";
}
String apnTypeString = APN_TYPE_INT_MAP.get(apnType);
- return apnTypeString == null ? "Unknown" : apnTypeString;
+ return apnTypeString == null ? "" : apnTypeString;
+ }
+
+ /**
+ * Same as {@link #getApnTypeString(int)}, but returns "Unknown" instead of an empty string
+ * when provided with an invalid int for compatibility purposes.
+ * @hide
+ */
+ public static @NonNull String getApnTypeStringInternal(@Annotation.ApnType int apnType) {
+ String result = getApnTypeString(apnType);
+ return TextUtils.isEmpty(result) ? "Unknown" : result;
+ }
+
+ /**
+ * Converts the string representation of an APN type to its integer representation.
+ *
+ * @param apnType APN type as a string
+ * @return Integer representation of the APN type, or 0 if the provided string is not a valid
+ * APN type.
+ * @hide
+ */
+ @SystemApi
+ public static @Annotation.ApnType int getApnTypeInt(@NonNull @ApnTypeString String apnType) {
+ return APN_TYPE_STRING_MAP.getOrDefault(apnType.toLowerCase(), 0);
}
/**
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 3e2a6eec37c4..993e07a55794 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -110,10 +110,10 @@ public final class DataCallResponse implements Parcelable {
public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 3;
/**
- * Indicates that data retry interval is not specified. Platform can determine when to
+ * Indicates that data retry duration is not specified. Platform can determine when to
* perform data setup appropriately.
*/
- public static final int RETRY_INTERVAL_UNDEFINED = -1;
+ public static final int RETRY_DURATION_UNDEFINED = -1;
private final @DataFailureCause int mCause;
private final long mSuggestedRetryTime;
@@ -236,19 +236,25 @@ public final class DataCallResponse implements Parcelable {
/**
* @return The suggested data retry time in milliseconds.
*
- * @deprecated Use {@link #getRetryIntervalMillis()} instead.
+ * @deprecated Use {@link #getRetryDurationMillis()} instead.
*/
@Deprecated
public int getSuggestedRetryTime() {
+ // To match the pre-deprecated getSuggestedRetryTime() behavior.
+ if (mSuggestedRetryTime == RETRY_DURATION_UNDEFINED) {
+ return 0;
+ } else if (mSuggestedRetryTime > Integer.MAX_VALUE) {
+ return Integer.MAX_VALUE;
+ }
return (int) mSuggestedRetryTime;
}
/**
- * @return The network suggested data retry interval in milliseconds. {@code Long.MAX_VALUE}
- * indicates data retry should not occur. {@link #RETRY_INTERVAL_UNDEFINED} indicates network
- * did not suggest any retry interval.
+ * @return The network suggested data retry duration in milliseconds. {@code Long.MAX_VALUE}
+ * indicates data retry should not occur. {@link #RETRY_DURATION_UNDEFINED} indicates network
+ * did not suggest any retry duration.
*/
- public long getRetryIntervalMillis() {
+ public long getRetryDurationMillis() {
return mSuggestedRetryTime;
}
@@ -466,7 +472,7 @@ public final class DataCallResponse implements Parcelable {
public static final class Builder {
private @DataFailureCause int mCause;
- private long mSuggestedRetryTime = RETRY_INTERVAL_UNDEFINED;
+ private long mSuggestedRetryTime = RETRY_DURATION_UNDEFINED;
private int mId;
@@ -515,7 +521,7 @@ public final class DataCallResponse implements Parcelable {
* @param suggestedRetryTime The suggested data retry time in milliseconds.
* @return The same instance of the builder.
*
- * @deprecated Use {@link #setRetryIntervalMillis(long)} instead.
+ * @deprecated Use {@link #setRetryDurationMillis(long)} instead.
*/
@Deprecated
public @NonNull Builder setSuggestedRetryTime(int suggestedRetryTime) {
@@ -524,13 +530,13 @@ public final class DataCallResponse implements Parcelable {
}
/**
- * Set the network suggested data retry interval.
+ * Set the network suggested data retry duration.
*
- * @param retryIntervalMillis The suggested data retry interval in milliseconds.
+ * @param retryDurationMillis The suggested data retry duration in milliseconds.
* @return The same instance of the builder.
*/
- public @NonNull Builder setRetryIntervalMillis(long retryIntervalMillis) {
- mSuggestedRetryTime = retryIntervalMillis;
+ public @NonNull Builder setRetryDurationMillis(long retryDurationMillis) {
+ mSuggestedRetryTime = retryDurationMillis;
return this;
}
diff --git a/telephony/java/android/telephony/ims/AudioCodecAttributes.aidl b/telephony/java/android/telephony/ims/AudioCodecAttributes.aidl
new file mode 100644
index 000000000000..bbab548bcd37
--- /dev/null
+++ b/telephony/java/android/telephony/ims/AudioCodecAttributes.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.telephony.ims;
+
+parcelable AudioCodecAttributes;
diff --git a/telephony/java/android/telephony/ims/AudioCodecAttributes.java b/telephony/java/android/telephony/ims/AudioCodecAttributes.java
new file mode 100644
index 000000000000..7b6ab00b93e4
--- /dev/null
+++ b/telephony/java/android/telephony/ims/AudioCodecAttributes.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 android.telephony.ims;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Range;
+
+/**
+ * Parcelable object to handle audio codec attributes.
+ * It provides the audio codec bitrate, bandwidth and their upper/lower bound.
+ *
+ * @hide
+ */
+@SystemApi
+public final class AudioCodecAttributes implements Parcelable {
+ // The audio codec bitrate in kbps.
+ private float mBitrateKbps;
+ // The range of the audio codec bitrate in kbps.
+ private Range<Float> mBitrateRangeKbps;
+ // The audio codec bandwidth in kHz.
+ private float mBandwidthKhz;
+ // The range of the audio codec bandwidth in kHz.
+ private Range<Float> mBandwidthRangeKhz;
+
+
+ /**
+ * Constructor.
+ *
+ * @param bitrateKbps The audio codec bitrate in kbps.
+ * @param bitrateRangeKbps The range of the audio codec bitrate in kbps.
+ * @param bandwidthKhz The audio codec bandwidth in kHz.
+ * @param bandwidthRangeKhz The range of the audio codec bandwidth in kHz.
+ */
+
+ public AudioCodecAttributes(float bitrateKbps, @NonNull Range<Float> bitrateRangeKbps,
+ float bandwidthKhz, @NonNull Range<Float> bandwidthRangeKhz) {
+ mBitrateKbps = bitrateKbps;
+ mBitrateRangeKbps = bitrateRangeKbps;
+ mBandwidthKhz = bandwidthKhz;
+ mBandwidthRangeKhz = bandwidthRangeKhz;
+ }
+
+ private AudioCodecAttributes(Parcel in) {
+ mBitrateKbps = in.readFloat();
+ mBitrateRangeKbps = new Range<>(in.readFloat(), in.readFloat());
+ mBandwidthKhz = in.readFloat();
+ mBandwidthRangeKhz = new Range<>(in.readFloat(), in.readFloat());
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeFloat(mBitrateKbps);
+ out.writeFloat(mBitrateRangeKbps.getLower());
+ out.writeFloat(mBitrateRangeKbps.getUpper());
+ out.writeFloat(mBandwidthKhz);
+ out.writeFloat(mBandwidthRangeKhz.getLower());
+ out.writeFloat(mBandwidthRangeKhz.getUpper());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Creator<AudioCodecAttributes> CREATOR =
+ new Creator<AudioCodecAttributes>() {
+ @Override
+ public AudioCodecAttributes createFromParcel(Parcel in) {
+ return new AudioCodecAttributes(in);
+ }
+
+ @Override
+ public AudioCodecAttributes[] newArray(int size) {
+ return new AudioCodecAttributes[size];
+ }
+ };
+
+ /**
+ * @return the exact value of the audio codec bitrate in kbps.
+ */
+ public float getBitrateKbps() {
+ return mBitrateKbps;
+ }
+
+ /**
+ * @return the range of the audio codec bitrate in kbps
+ */
+ public @NonNull Range<Float> getBitrateRangeKbps() {
+ return mBitrateRangeKbps;
+ }
+
+ /**
+ * @return the exact value of the audio codec bandwidth in kHz.
+ */
+ public float getBandwidthKhz() {
+ return mBandwidthKhz;
+ }
+
+ /**
+ * @return the range of the audio codec bandwidth in kHz.
+ */
+ public @NonNull Range<Float> getBandwidthRangeKhz() {
+ return mBandwidthRangeKhz;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "{ bitrateKbps=" + mBitrateKbps
+ + ", bitrateRangeKbps=" + mBitrateRangeKbps
+ + ", bandwidthKhz=" + mBandwidthKhz
+ + ", bandwidthRangeKhz=" + mBandwidthRangeKhz + " }";
+ }
+}
diff --git a/telephony/java/android/telephony/ims/DelegateMessageCallback.java b/telephony/java/android/telephony/ims/DelegateMessageCallback.java
new file mode 100644
index 000000000000..beec4a680d78
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateMessageCallback.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+import android.annotation.NonNull;
+import android.telephony.ims.stub.SipDelegate;
+
+/**
+ * Callback interface provided to the SipTransport implementation to notify a remote application of
+ * the following:
+ * <ul>
+ * <li>A new incoming SIP message associated with the feature tags the SipDelegate registered
+ * with has been received or an in-dialog request to this SipDelegate has been received.</li>
+ * <li>Acknowledge that an outgoing SIP message from the RCS application has been sent
+ * successfully or notify the application of the reason why it was not sent</li>
+ * </ul>
+ * @hide
+ */
+public interface DelegateMessageCallback {
+
+ /**
+ * Send a new incoming SIP message to the remote application for processing.
+ */
+ void onMessageReceived(@NonNull SipMessage message);
+
+ /**
+ * Notify the remote application that a previous request to send a SIP message using
+ * {@link SipDelegate#sendMessage} has succeeded.
+ *
+ * @param viaTransactionId The transaction ID found in the via header field of the
+ * previously sent {@link SipMessage}.
+ */
+ void onMessageSent(@NonNull String viaTransactionId);
+
+ /**
+ * Notify the remote application that a previous request to send a SIP message using
+ * {@link SipDelegate#sendMessage} has failed.
+ *
+ * @param viaTransactionId The Transaction ID found in the via header field of the previously
+ * sent {@link SipMessage}.
+ * @param reason The reason for the failure.
+ */
+ void onMessageSendFailure(@NonNull String viaTransactionId,
+ @SipDelegateManager.MessageFailureReason int reason);
+}
diff --git a/telephony/java/android/telephony/ims/DelegateRegistrationState.aidl b/telephony/java/android/telephony/ims/DelegateRegistrationState.aidl
new file mode 100644
index 000000000000..756ea920d06a
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateRegistrationState.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.telephony.ims;
+
+parcelable DelegateRegistrationState;
diff --git a/telephony/java/android/telephony/ims/DelegateRegistrationState.java b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
new file mode 100644
index 000000000000..4facfa77de21
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateRegistrationState.java
@@ -0,0 +1,327 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Contains the full state of the IMS feature tags associated with a SipDelegate and managed by the
+ * ImsService.
+ * @hide
+ */
+public final class DelegateRegistrationState implements Parcelable {
+
+ /**
+ * This feature tag has been deregistered for an unknown reason. Outgoing out-of-dialog SIP
+ * messages associated with feature tags that are not registered will fail.
+ */
+ public static final int DEREGISTERED_REASON_UNKNOWN = 0;
+
+ /**
+ * This feature tag has been deregistered because it is not provisioned to be used on this radio
+ * access technology or PDN. Outgoing out-of-dialog SIP messages associated with feature tags
+ * that are not registered will fail.
+ * <p>
+ * There may be new incoming SIP dialog requests on a feature that that is not provisioned. It
+ * is still expected that the SipDelegateConnection responds to the request.
+ */
+ public static final int DEREGISTERED_REASON_NOT_PROVISIONED = 1;
+
+ /**
+ * This feature tag has been deregistered because IMS has been deregistered. All outgoing SIP
+ * messages will fail until IMS registration occurs.
+ */
+ public static final int DEREGISTERED_REASON_NOT_REGISTERED = 2;
+
+ /**
+ * This feature tag is being deregistered because the PDN that the IMS registration is on is
+ *changing.
+ * All open SIP dialogs need to be closed before the PDN change can proceed.
+ */
+ public static final int DEREGISTERING_REASON_PDN_CHANGE = 3;
+
+ /**
+ * This feature tag is being deregistered due to a provisioning change. This can be triggered by
+ * many things, such as a provisioning change triggered by the carrier network, a radio access
+ * technology change by the modem causing a different set of feature tags to be provisioned, or
+ * a user triggered hange, such as data being enabled/disabled.
+ * <p>
+ * All open SIP dialogs associated with the new deprovisioned feature tag need to be closed
+ * before the IMS registration modification can proceed.
+ */
+ public static final int DEREGISTERING_REASON_PROVISIONING_CHANGE = 4;
+
+ /**
+ * This feature tag is deregistering because the SipDelegate associated with this feature tag
+ * needs to change its supported feature set.
+ * <p>
+ * All open SIP Dialogs associated with this feature tag must be closed before this operation
+ * can proceed.
+ */
+ public static final int DEREGISTERING_REASON_FEATURE_TAGS_CHANGING = 5;
+
+ /**
+ * This feature tag is deregistering because the SipDelegate is in the process of being
+ * destroyed.
+ * <p>
+ * All open SIP Dialogs associated with this feature tag must be closed before this operation
+ * can proceed.
+ */
+ public static final int DEREGISTERING_REASON_DESTROY_PENDING = 6;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "DEREGISTERED_REASON_", value = {
+ DEREGISTERED_REASON_UNKNOWN,
+ DEREGISTERED_REASON_NOT_PROVISIONED,
+ DEREGISTERED_REASON_NOT_REGISTERED
+ })
+ public @interface DeregisteredReason {}
+
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "DEREGISTERING_REASON_", value = {
+ DEREGISTERING_REASON_PDN_CHANGE,
+ DEREGISTERING_REASON_PROVISIONING_CHANGE,
+ DEREGISTERING_REASON_FEATURE_TAGS_CHANGING,
+ DEREGISTERING_REASON_DESTROY_PENDING
+ })
+ public @interface DeregisteringReason {}
+
+ private final ArrayList<String> mRegisteredTags = new ArrayList<>();
+ private final ArrayList<FeatureTagState> mDeregisteringTags = new ArrayList<>();
+ private final ArrayList<FeatureTagState> mDeregisteredTags = new ArrayList<>();
+
+ /**
+ * Builder used to create new instances of {@link DelegateRegistrationState}.
+ */
+ public static class Builder {
+
+ private final DelegateRegistrationState mState;
+
+ /* Create a new instance of {@link Builder} */
+ public Builder() {
+ mState = new DelegateRegistrationState();
+ }
+
+ /**
+ * Add a feature tag that is currently included in the current network IMS Registration.
+ * @param featureTag The IMS media feature tag included in the current IMS registration.
+ * @return The in-progress Builder instance for RegistrationState.
+ */
+ public Builder addRegisteredFeatureTag(@NonNull String featureTag) {
+ if (!mState.mRegisteredTags.contains(featureTag)) {
+ mState.mRegisteredTags.add(featureTag);
+ }
+ return this;
+ }
+
+ /**
+ * Add a list of feature tags that are currently included in the current network IMS
+ * Registration.
+ * @param featureTags The IMS media feature tags included in the current IMS registration.
+ * @return The in-progress Builder instance for RegistrationState.
+ */
+ public Builder addRegisteredFeatureTags(@NonNull Set<String> featureTags) {
+ mState.mRegisteredTags.addAll(featureTags);
+ return this;
+ }
+
+ /**
+ * Add a feature tag that is in the current network IMS Registration, but is in the progress
+ * of being deregistered and requires action from the RCS application before the IMS
+ * registration can be modified.
+ *
+ * See {@link DeregisteringReason} for more information regarding what is required by the
+ * RCS application to proceed.
+ *
+ * @param featureTag The media feature tag that has limited or no availability due to its
+ * current deregistering state.
+ * @param reason The reason why the media feature tag has moved to the deregistering state.
+ * The availability of the feature tag depends on the {@link DeregisteringReason}.
+ * @return The in-progress Builder instance for RegistrationState.
+ */
+ public Builder addDeregisteringFeatureTag(@NonNull String featureTag,
+ @DeregisteringReason int reason) {
+ boolean ftExists = mState.mDeregisteringTags.stream().anyMatch(
+ f -> f.getFeatureTag().equals(featureTag));
+ if (!ftExists) {
+ mState.mDeregisteringTags.add(new FeatureTagState(featureTag, reason));
+ }
+ return this;
+ }
+
+ /**
+ * Add a feature tag that is currently not included in the network RCS registration. See
+ * {@link DeregisteredReason} for more information regarding the reason for why the feature
+ * tag is not registered.
+ * @param featureTag The media feature tag that is not registered.
+ * @param reason The reason why the media feature tag has been deregistered.
+ * @return The in-progress Builder instance for RegistrationState.
+ */
+ public Builder addDeregisteredFeatureTag(@NonNull String featureTag,
+ @DeregisteredReason int reason) {
+ boolean ftExists = mState.mDeregisteredTags.stream().anyMatch(
+ f -> f.getFeatureTag().equals(featureTag));
+ if (!ftExists) {
+ mState.mDeregisteredTags.add(new FeatureTagState(featureTag, reason));
+ }
+ return this;
+ }
+
+ /**
+ * @return the finalized instance.
+ */
+ public DelegateRegistrationState build() {
+ return mState;
+ }
+ }
+
+ /**
+ * The builder should be used to construct a new instance of this class.
+ */
+ private DelegateRegistrationState() {}
+
+ /**
+ * Used for unparcelling only.
+ */
+ private DelegateRegistrationState(Parcel source) {
+ source.readList(mRegisteredTags, null /*classloader*/);
+ readStateFromParcel(source, mDeregisteringTags);
+ readStateFromParcel(source, mDeregisteredTags);
+ }
+
+ /**
+ * Get the feature tags that this SipDelegate is associated with that are currently part of the
+ * network IMS registration. SIP Messages both in and out of a SIP Dialog may be sent and
+ * received using these feature tags.
+ * @return A Set of feature tags that the SipDelegate has associated with that are included in
+ * the network IMS registration.
+ */
+ public @NonNull Set<String> getRegisteredFeatureTags() {
+ return new ArraySet<>(mRegisteredTags);
+ }
+
+ /**
+ * Get the feature tags that this SipDelegate is associated with that are currently part of the
+ * network IMS registration but are in the process of being deregistered.
+ * <p>
+ * Any incoming SIP messages associated with a feature tag included in this list will still be
+ * delivered. Outgoing SIP messages that are still in-dialog will be delivered to the
+ * SipDelegate, but outgoing out-of-dialog SIP messages with a feature tag that is included in
+ * this list will fail.
+ * <p>
+ * The SipDelegate will stay in this state for a limited period of time while it waits for the
+ * RCS application to perform a specific action. More details on the actions that can cause this
+ * state as well as the expected response are included in the reason codes and can be found in
+ * {@link DeregisteringReason}.
+ * @return A Set of feature tags that the SipDelegate has associated with that are included in
+ * the network IMS registration but are in the process of deregistering.
+ */
+ public @NonNull Set<FeatureTagState> getDeregisteringFeatureTags() {
+ return new ArraySet<>(mDeregisteringTags);
+ }
+
+ /**
+ * Get the list of feature tags that are associated with this SipDelegate but are not currently
+ * included in the network IMS registration.
+ * <p>
+ * See {@link DeregisteredReason} codes for more information related to the reasons why this may
+ * occur.
+ * <p>
+ * Due to network race conditions, there may still be onditions where an incoming out-of-dialog
+ * SIP message is delivered for a feature tag that is considered deregistered. Due to this
+ * condition, in-dialog outgoing SIP messages for deregistered feature tags will still be
+ * allowed as long as they are in response to a dialog started by a remote party. Any outgoing
+ * out-of-dialog SIP messages associated with feature tags included in this list will fail to be
+ * sent.
+ * @return A list of feature tags that the SipDelegate has associated with that not included in
+ * the network IMS registration.
+ */
+ public @NonNull Set<FeatureTagState> getDeregisteredFeatureTags() {
+ return new ArraySet<>(mDeregisteredTags);
+ }
+
+ public static final Creator<DelegateRegistrationState> CREATOR =
+ new Creator<DelegateRegistrationState>() {
+ @Override
+ public DelegateRegistrationState createFromParcel(Parcel source) {
+ return new DelegateRegistrationState(source);
+ }
+
+ @Override
+ public DelegateRegistrationState[] newArray(int size) {
+ return new DelegateRegistrationState[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeList(mRegisteredTags);
+ writeStateToParcel(dest, mDeregisteringTags);
+ writeStateToParcel(dest, mDeregisteredTags);
+ }
+
+ private void writeStateToParcel(Parcel dest, List<FeatureTagState> state) {
+ dest.writeInt(state.size());
+ for (FeatureTagState s : state) {
+ dest.writeString(s.getFeatureTag());
+ dest.writeInt(s.getState());
+ }
+ }
+
+ private void readStateFromParcel(Parcel source, List<FeatureTagState> emptyState) {
+ int len = source.readInt();
+ for (int i = 0; i < len; i++) {
+ String ft = source.readString();
+ int reason = source.readInt();
+ emptyState.add(new FeatureTagState(ft, reason));
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DelegateRegistrationState that = (DelegateRegistrationState) o;
+ return mRegisteredTags.equals(that.mRegisteredTags)
+ && mDeregisteringTags.equals(that.mDeregisteringTags)
+ && mDeregisteredTags.equals(that.mDeregisteredTags);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRegisteredTags, mDeregisteringTags, mDeregisteredTags);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/DelegateRequest.aidl b/telephony/java/android/telephony/ims/DelegateRequest.aidl
new file mode 100644
index 000000000000..60c990f8258f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateRequest.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.telephony.ims;
+
+parcelable DelegateRequest;
diff --git a/telephony/java/android/telephony/ims/DelegateRequest.java b/telephony/java/android/telephony/ims/DelegateRequest.java
new file mode 100644
index 000000000000..f384901d58bd
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateRequest.java
@@ -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.
+ */
+
+package android.telephony.ims;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.ims.stub.SipDelegate;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Contains information required for the creation of a {@link SipDelegate} and the associated
+ * SipDelegateConnection given back to the requesting application.
+ * @hide
+ */
+public final class DelegateRequest implements Parcelable {
+
+ private final ArrayList<String> mFeatureTags;
+
+ /**
+ * Create a new DelegateRequest, which will be used to create a SipDelegate by the ImsService.
+ * @param featureTags The list of IMS feature tags that will be associated with the SipDelegate
+ * created using this DelegateRequest. All feature tags are expected to be in
+ * the format defined in RCC.07 section 2.6.1.3.
+ */
+ public DelegateRequest(@NonNull Set<String> featureTags) {
+ if (featureTags == null) {
+ throw new IllegalStateException("Invalid arguments, featureTags List can not be null");
+ }
+ mFeatureTags = new ArrayList<>(featureTags);
+ }
+
+ /**
+ * @return the list of IMS feature tag associated with this DelegateRequest in the format
+ * defined in RCC.07 section 2.6.1.3.
+ */
+ public Set<String> getFeatureTags() {
+ return new ArraySet<>(mFeatureTags);
+ }
+
+ /**
+ * Internal constructor used only for unparcelling.
+ */
+ private DelegateRequest(Parcel in) {
+ mFeatureTags = new ArrayList<>();
+ in.readList(mFeatureTags, null /*classLoader*/);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeList(mFeatureTags);
+ }
+
+ public static final @NonNull Creator<DelegateRequest> CREATOR = new Creator<DelegateRequest>() {
+ @Override
+ public DelegateRequest createFromParcel(Parcel source) {
+ return new DelegateRequest(source);
+ }
+
+ @Override
+ public DelegateRequest[] newArray(int size) {
+ return new DelegateRequest[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DelegateRequest that = (DelegateRequest) o;
+ return mFeatureTags.equals(that.mFeatureTags);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFeatureTags);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/DelegateStateCallback.java b/telephony/java/android/telephony/ims/DelegateStateCallback.java
new file mode 100644
index 000000000000..0f1afc42249e
--- /dev/null
+++ b/telephony/java/android/telephony/ims/DelegateStateCallback.java
@@ -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.
+ */
+
+package android.telephony.ims;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.telephony.ims.stub.SipDelegate;
+import android.telephony.ims.stub.SipTransportImplBase;
+
+import java.util.List;
+
+/**
+ * Callback interface to notify a remote application of the following:
+ * <ul>
+ * <li>the {@link SipDelegate} associated with this callback has been created or destroyed in
+ * response to a creation or destruction request from the framework</li>
+ * <li>the SIP IMS configuration associated with this {@link SipDelegate} has changed</li>
+ * <li>the IMS registration of the feature tags associated with this {@link SipDelegate} have
+ * changed.</li>
+ * </ul>
+ * @hide
+ */
+public interface DelegateStateCallback {
+
+ /**
+ * This must be called by the ImsService after {@link SipTransportImplBase#createSipDelegate} is
+ * called by the framework to notify the framework and remote application that the
+ * {@link SipDelegate} has been successfully created.
+ *
+ * @param delegate The SipDelegate created to service the DelegateRequest.
+ * @param deniedTags A List of {@link FeatureTagState}, which contains the feature tags
+ * associated with this {@link SipDelegate} that have no access to send/receive SIP messages
+ * as well as a reason for why the feature tag is denied. For more information on the reason
+ * why the feature tag was denied access, see the
+ * {@link SipDelegateManager.DeniedReason} reasons. This is considered a permanent denial due
+ * to this {@link SipDelegate} not supporting a feature or this ImsService already
+ * implementing this feature elsewhere. If all features of this {@link SipDelegate} are
+ * denied, {@link #onCreated(SipDelegate, List)} should still be called as the framework will
+ * later call {@link SipTransportImplBase#destroySipDelegate(SipDelegate, int)} to clean the
+ * delegate up.
+ */
+ void onCreated(@NonNull SipDelegate delegate, @Nullable List<FeatureTagState> deniedTags);
+
+ /**
+ * This must be called by the ImsService after the framework calls
+ * {@link SipTransportImplBase#destroySipDelegate} to notify the framework and remote
+ * application that the procedure to destroy the {@link SipDelegate} has been completed.
+ * @param reasonCode The reason for closing this delegate.
+ */
+ void onDestroyed(@SipDelegateManager.SipDelegateDestroyReason int reasonCode);
+
+ /**
+ * Call to notify the remote application of a configuration change associated with this
+ * {@link SipDelegate}.
+ * <p>
+ * The remote application will not be able to proceed sending SIP messages until after this
+ * configuration is sent the first time, so this configuration should be sent as soon as the
+ * {@link SipDelegate} has access to these configuration parameters.
+ * <p>
+ * Incoming SIP messages should not be routed to the remote application until AFTER this
+ * configuration change is sent to ensure that the remote application can respond correctly.
+ * Similarly, if there is an event that triggers the IMS configuration to change, incoming SIP
+ * messages routing should be delayed until the {@link SipDelegate} sends the IMS configuration
+ * change event to reduce conditions where the remote application is using a stale IMS
+ * configuration.
+ */
+ void onImsConfigurationChanged(@NonNull SipDelegateImsConfiguration config);
+
+ /**
+ * Call to notify the remote application that the {@link SipDelegate} has modified the IMS
+ * registration state of the RCS feature tags that were requested as part of the initial
+ * {@link DelegateRequest}.
+ * <p>
+ * See {@link DelegateRegistrationState} for more information about how IMS Registration state
+ * should be communicated the associated SipDelegateConnection in cases such as
+ * IMS deregistration, handover, PDN change, provisioning changes, etc…
+ * <p>
+ * Note: Even after the status of the feature tags are updated here to deregistered, the
+ * SipDelegate must still be able to handle these messages and call
+ * {@link DelegateMessageCallback#onMessageSendFailure} to notify the RCS application that the
+ * message was not sent.
+ *
+ * @param registrationState The current network IMS registration state for all feature tags
+ * associated with this SipDelegate.
+ */
+ void onFeatureTagRegistrationChanged(@NonNull DelegateRegistrationState registrationState);
+}
diff --git a/telephony/java/android/telephony/ims/FeatureTagState.aidl b/telephony/java/android/telephony/ims/FeatureTagState.aidl
new file mode 100644
index 000000000000..bce55742461c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/FeatureTagState.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.telephony.ims;
+
+parcelable FeatureTagState;
diff --git a/telephony/java/android/telephony/ims/FeatureTagState.java b/telephony/java/android/telephony/ims/FeatureTagState.java
new file mode 100644
index 000000000000..060be6f2510d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/FeatureTagState.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 android.telephony.ims;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.ims.stub.DelegateConnectionStateCallback;
+import android.telephony.ims.stub.SipDelegate;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Maps an IMS media feature tag 3gpp universal resource name (URN) previously mapped to a
+ * {@link SipDelegate} in the associated {@link DelegateRequest} to its current availability
+ * state as set by the ImsService managing the related IMS registration.
+ *
+ * This class is only used to report more information about a IMS feature tag that is not fully
+ * available at this time.
+ * <p>
+ * Please see {@link DelegateRegistrationState}, {@link DelegateStateCallback}, and
+ * {@link DelegateConnectionStateCallback} for more information about how this class is used to
+ * convey the state of IMS feature tags that were requested by {@link DelegateRequest} but are not
+ * currently available.
+ * @hide
+ */
+public final class FeatureTagState implements Parcelable {
+
+ private final String mFeatureTag;
+ private final int mState;
+
+ /**
+ * Associate an IMS feature tag with its current state. See {@link DelegateRegistrationState}
+ * and {@link DelegateConnectionStateCallback#onFeatureTagStatusChanged(
+ * DelegateRegistrationState, List)} and
+ * {@link DelegateStateCallback#onCreated(SipDelegate, List)} for examples on how and when this
+ * is used.
+ *
+ * @param featureTag The IMS feature tag that is deregistered, in the process of
+ * deregistering, or denied.
+ * @param state The {@link DelegateRegistrationState.DeregisteredReason},
+ * {@link DelegateRegistrationState.DeregisteringReason}, or
+ * {@link SipDelegateManager.DeniedReason} associated with this feature tag.
+ */
+ public FeatureTagState(@NonNull String featureTag, int state) {
+ mFeatureTag = featureTag;
+ mState = state;
+ }
+
+ /**
+ * Used for constructing instances during un-parcelling.
+ */
+ private FeatureTagState(Parcel source) {
+ mFeatureTag = source.readString();
+ mState = source.readInt();
+ }
+
+ /**
+ * @return The IMS feature tag string that is in the process of deregistering,
+ * deregistered, or denied.
+ */
+ public @NonNull String getFeatureTag() {
+ return mFeatureTag;
+ }
+
+ /**
+ * @return The reason for why the feature tag is currently in the process of deregistering,
+ * has been deregistered, or has been denied. See {@link DelegateRegistrationState} and
+ * {@link DelegateConnectionStateCallback} for more information.
+ */
+ public int getState() {
+ return mState;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mFeatureTag);
+ dest.writeInt(mState);
+ }
+
+ public static final Creator<FeatureTagState> CREATOR = new Creator<FeatureTagState>() {
+ @Override
+ public FeatureTagState createFromParcel(Parcel source) {
+ return new FeatureTagState(source);
+ }
+
+ @Override
+ public FeatureTagState[] newArray(int size) {
+ return new FeatureTagState[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ FeatureTagState that = (FeatureTagState) o;
+ return mState == that.mState
+ && mFeatureTag.equals(that.mFeatureTag);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mFeatureTag, mState);
+ }
+
+ @Override
+ public String toString() {
+ return "FeatureTagState{" + "mFeatureTag='" + mFeatureTag + ", mState=" + mState + '}';
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 5b54719afbfb..1b51936e873b 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -29,6 +29,8 @@ import android.telecom.VideoProfile;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.emergency.EmergencyNumber.EmergencyCallRouting;
import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
+import android.telephony.ims.feature.MmTelFeature;
+import android.util.ArraySet;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -38,7 +40,10 @@ import com.android.internal.telephony.util.TelephonyUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
/**
* A Parcelable object to handle the IMS call profile, which provides the service, call type, and
@@ -445,6 +450,8 @@ public final class ImsCallProfile implements Parcelable {
/** Indicates if we have known the intent of the user for the call is emergency */
private boolean mHasKnownUserIntentEmergency = false;
+ private Set<RtpHeaderExtensionType> mAcceptedRtpHeaderExtensionTypes = new ArraySet<>();
+
/**
* Extras associated with this {@link ImsCallProfile}.
* <p>
@@ -683,6 +690,7 @@ public final class ImsCallProfile implements Parcelable {
out.writeBoolean(mHasKnownUserIntentEmergency);
out.writeInt(mRestrictCause);
out.writeInt(mCallerNumberVerificationStatus);
+ out.writeArray(mAcceptedRtpHeaderExtensionTypes.toArray());
}
private void readFromParcel(Parcel in) {
@@ -697,9 +705,13 @@ public final class ImsCallProfile implements Parcelable {
mHasKnownUserIntentEmergency = in.readBoolean();
mRestrictCause = in.readInt();
mCallerNumberVerificationStatus = in.readInt();
+ Object[] accepted = in.readArray(RtpHeaderExtensionType.class.getClassLoader());
+ mAcceptedRtpHeaderExtensionTypes = Arrays.stream(accepted)
+ .map(o -> (RtpHeaderExtensionType) o).collect(Collectors.toSet());
}
- public static final @android.annotation.NonNull Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() {
+ public static final @android.annotation.NonNull Creator<ImsCallProfile> CREATOR =
+ new Creator<ImsCallProfile>() {
@Override
public ImsCallProfile createFromParcel(Parcel in) {
return new ImsCallProfile(in);
@@ -1086,4 +1098,33 @@ public final class ImsCallProfile implements Parcelable {
public boolean hasKnownUserIntentEmergency() {
return mHasKnownUserIntentEmergency;
}
+
+ /**
+ * Gets the {@link RtpHeaderExtensionType}s which have been accepted by both ends of the call.
+ * <p>
+ * According to RFC8285, RTP header extensions available to a call are determined using the
+ * offer/accept phase of the SDP protocol (see RFC4566).
+ * <p>
+ * The offered header extension types supported by the framework and exposed to the
+ * {@link ImsService} via {@link MmTelFeature#changeOfferedRtpHeaderExtensionTypes(Set)}.
+ *
+ * @return the {@link RtpHeaderExtensionType}s which were accepted by the other end of the call.
+ */
+ public @NonNull Set<RtpHeaderExtensionType> getAcceptedRtpHeaderExtensionTypes() {
+ return mAcceptedRtpHeaderExtensionTypes;
+ }
+
+ /**
+ * Sets the accepted {@link RtpHeaderExtensionType}s for this call.
+ * <p>
+ * According to RFC8285, RTP header extensions available to a call are determined using the
+ * offer/accept phase of the SDP protocol (see RFC4566).
+ *
+ * @param rtpHeaderExtensions
+ */
+ public void setAcceptedRtpHeaderExtensionTypes(@NonNull Set<RtpHeaderExtensionType>
+ rtpHeaderExtensions) {
+ mAcceptedRtpHeaderExtensionTypes.clear();
+ mAcceptedRtpHeaderExtensionTypes.addAll(rtpHeaderExtensions);
+ }
}
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index 8857b9b36d0c..a3efb799029a 100755
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -22,11 +22,16 @@ import android.os.Message;
import android.os.RemoteException;
import android.telephony.CallQuality;
import android.telephony.ims.aidl.IImsCallSessionListener;
+import android.util.ArraySet;
import android.util.Log;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsVideoCallProvider;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
/**
* Provides the call initiation/termination, and media exchange between two IMS endpoints.
* It directly communicates with IMS service which implements the IMS protocol behavior.
@@ -468,11 +473,31 @@ public class ImsCallSession {
}
/**
+ * Informs the framework of a DTMF digit which was received from the network.
+ * <p>
+ * According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833 sec 3.10</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to
+ * 12 ~ 15.
+ * @param digit the DTMF digit
+ */
+ public void callSessionDtmfReceived(char digit) {
+ // no-op
+ }
+
+ /**
* Called when the IMS service reports a change to the call quality.
*/
public void callQualityChanged(CallQuality callQuality) {
// no-op
}
+
+ /**
+ * Called when the IMS service reports incoming RTP header extension data.
+ */
+ public void callSessionRtpHeaderExtensionsReceived(
+ @NonNull Set<RtpHeaderExtension> extensions) {
+ // no-op
+ }
}
private final IImsCallSession miSession;
@@ -1119,6 +1144,31 @@ public class ImsCallSession {
}
/**
+ * Requests that {@code rtpHeaderExtensions} are sent as a header extension with the next
+ * RTP packet sent by the IMS stack.
+ * <p>
+ * The {@link RtpHeaderExtensionType}s negotiated during SDP (Session Description Protocol)
+ * signalling determine the {@link RtpHeaderExtension}s which can be sent using this method.
+ * See RFC8285 for more information.
+ * <p>
+ * By specification, the RTP header extension is an unacknowledged transmission and there is no
+ * guarantee that the header extension will be delivered by the network to the other end of the
+ * call.
+ * @param rtpHeaderExtensions The header extensions to be included in the next RTP header.
+ */
+ public void sendRtpHeaderExtensions(@NonNull Set<RtpHeaderExtension> rtpHeaderExtensions) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.sendRtpHeaderExtensions(
+ new ArrayList<RtpHeaderExtension>(rtpHeaderExtensions));
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* A listener type for receiving notification on IMS call session events.
* When an event is generated for an {@link IImsCallSession},
* the application is notified by having one of the methods called on
@@ -1477,6 +1527,17 @@ public class ImsCallSession {
}
/**
+ * DTMF digit received.
+ * @param dtmf The DTMF digit.
+ */
+ @Override
+ public void callSessionDtmfReceived(char dtmf) {
+ if (mListener != null) {
+ mListener.callSessionDtmfReceived(dtmf);
+ }
+ }
+
+ /**
* Call quality updated
*/
@Override
@@ -1485,6 +1546,19 @@ public class ImsCallSession {
mListener.callQualityChanged(callQuality);
}
}
+
+ /**
+ * RTP header extension data received.
+ * @param extensions The header extension data.
+ */
+ @Override
+ public void callSessionRtpHeaderExtensionsReceived(
+ @NonNull List<RtpHeaderExtension> extensions) {
+ if (mListener != null) {
+ mListener.callSessionRtpHeaderExtensionsReceived(
+ new ArraySet<RtpHeaderExtension>(extensions));
+ }
+ }
}
/**
diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
index 2fdd195bbb26..86bb5d9f0b09 100644
--- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java
+++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
@@ -28,6 +28,10 @@ import android.telephony.ims.stub.ImsCallSessionImplBase;
import com.android.ims.internal.IImsCallSession;
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.Set;
+
/**
* Listener interface for notifying the Framework's {@link ImsCallSession} for updates to an ongoing
* IMS call.
@@ -683,6 +687,59 @@ public class ImsCallSessionListener {
}
/**
+ * The {@link ImsService} calls this method to inform the framework of a DTMF digit which was
+ * received from the network.
+ * <p>
+ * According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833 sec 3.10</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15.
+ * <p>
+ * <em>Note:</em> Alpha DTMF digits are converted from lower-case to upper-case.
+ *
+ * @param dtmf The DTMF digit received, '0'-'9', *, #, A, B, C, or D.
+ * @throws IllegalArgumentException If an invalid DTMF character is provided.
+ */
+ public void callSessionDtmfReceived(char dtmf) {
+ if (!(dtmf >= '0' && dtmf <= '9'
+ || dtmf >= 'A' && dtmf <= 'D'
+ || dtmf >= 'a' && dtmf <= 'd'
+ || dtmf == '*'
+ || dtmf == '#')) {
+ throw new IllegalArgumentException("DTMF digit must be 0-9, *, #, A, B, C, D");
+ }
+ try {
+ mListener.callSessionDtmfReceived(Character.toUpperCase(dtmf));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * The {@link ImsService} calls this method to inform the framework of RTP header extension data
+ * which was received from the network.
+ * <p>
+ * The set of {@link RtpHeaderExtension} data are identified by local identifiers which were
+ * negotiated during SDP signalling. See RFC8285,
+ * {@link ImsCallProfile#getAcceptedRtpHeaderExtensionTypes()} and
+ * {@link RtpHeaderExtensionType} for more information.
+ * <p>
+ * By specification, the RTP header extension is an unacknowledged transmission and there is no
+ * guarantee that the header extension will be delivered by the network to the other end of the
+ * call.
+ *
+ * @param extensions The RTP header extension data received.
+ */
+ public void callSessionRtpHeaderExtensionsReceived(
+ @NonNull Set<RtpHeaderExtension> extensions) {
+ Objects.requireNonNull(extensions, "extensions are required.");
+ try {
+ mListener.callSessionRtpHeaderExtensionsReceived(
+ new ArrayList<RtpHeaderExtension>(extensions));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Notifies the result of transfer request.
* @hide
*/
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 76c1fafe05fb..218875e347c7 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -29,6 +29,7 @@ import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.telephony.AccessNetworkConstants;
+import android.telephony.BinderCacheManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyFrameworkInitializer;
@@ -213,6 +214,7 @@ public class ImsMmTelManager implements RegistrationManager {
}
private final int mSubId;
+ private final BinderCacheManager<ITelephony> mBinderCache;
/**
* Create an instance of {@link ImsMmTelManager} for the subscription id specified.
@@ -242,7 +244,8 @@ public class ImsMmTelManager implements RegistrationManager {
throw new IllegalArgumentException("Invalid subscription ID");
}
- return new ImsMmTelManager(subId);
+ return new ImsMmTelManager(subId, new BinderCacheManager<>(
+ ImsMmTelManager::getITelephonyInterface));
}
/**
@@ -250,8 +253,9 @@ public class ImsMmTelManager implements RegistrationManager {
* @hide
*/
@VisibleForTesting
- public ImsMmTelManager(int subId) {
+ public ImsMmTelManager(int subId, BinderCacheManager<ITelephony> binderCache) {
mSubId = subId;
+ mBinderCache = binderCache;
}
/**
@@ -1367,7 +1371,11 @@ public class ImsMmTelManager implements RegistrationManager {
}
}
- private static ITelephony getITelephony() {
+ private ITelephony getITelephony() {
+ return mBinderCache.getBinder();
+ }
+
+ private static ITelephony getITelephonyInterface() {
ITelephony binder = ITelephony.Stub.asInterface(
TelephonyFrameworkInitializer
.getTelephonyServiceManager()
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 5a32075f6aa8..074aefe2e800 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -28,6 +28,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Settings;
import android.telephony.AccessNetworkConstants;
+import android.telephony.BinderCacheManager;
import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -149,14 +150,17 @@ public class ImsRcsManager {
private final int mSubId;
private final Context mContext;
+ private final BinderCacheManager<IImsRcsController> mBinderCache;
/**
* Use {@link ImsManager#getImsRcsManager(int)} to create an instance of this class.
* @hide
*/
- public ImsRcsManager(Context context, int subId) {
+ public ImsRcsManager(Context context, int subId,
+ BinderCacheManager<IImsRcsController> binderCache) {
mSubId = subId;
mContext = context;
+ mBinderCache = binderCache;
}
/**
diff --git a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
index 2792f790e13b..d924baee5ab9 100644
--- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
@@ -17,6 +17,7 @@
package android.telephony.ims;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
@@ -90,6 +91,9 @@ public final class ImsStreamMediaProfile implements Parcelable {
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public int mAudioDirection;
+ // Audio codec attributes
+ private AudioCodecAttributes mAudioCodecAttributes;
+
// Video related information
/** @hide */
public int mVideoQuality;
@@ -191,6 +195,7 @@ public final class ImsStreamMediaProfile implements Parcelable {
public void copyFrom(ImsStreamMediaProfile profile) {
mAudioQuality = profile.mAudioQuality;
mAudioDirection = profile.mAudioDirection;
+ mAudioCodecAttributes = profile.mAudioCodecAttributes;
mVideoQuality = profile.mVideoQuality;
mVideoDirection = profile.mVideoDirection;
mRttMode = profile.mRttMode;
@@ -199,12 +204,13 @@ public final class ImsStreamMediaProfile implements Parcelable {
@NonNull
@Override
public String toString() {
- return "{ audioQuality=" + mAudioQuality +
- ", audioDirection=" + mAudioDirection +
- ", videoQuality=" + mVideoQuality +
- ", videoDirection=" + mVideoDirection +
- ", rttMode=" + mRttMode +
- ", hasRttAudioSpeech=" + mIsReceivingRttAudio + " }";
+ return "{ audioQuality=" + mAudioQuality
+ + ", audioDirection=" + mAudioDirection
+ + ", audioCodecAttribute=" + mAudioCodecAttributes
+ + ", videoQuality=" + mVideoQuality
+ + ", videoDirection=" + mVideoDirection
+ + ", rttMode=" + mRttMode
+ + ", hasRttAudioSpeech=" + mIsReceivingRttAudio + " }";
}
@Override
@@ -216,6 +222,7 @@ public final class ImsStreamMediaProfile implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mAudioQuality);
out.writeInt(mAudioDirection);
+ out.writeTypedObject(mAudioCodecAttributes, flags);
out.writeInt(mVideoQuality);
out.writeInt(mVideoDirection);
out.writeInt(mRttMode);
@@ -225,6 +232,7 @@ public final class ImsStreamMediaProfile implements Parcelable {
private void readFromParcel(Parcel in) {
mAudioQuality = in.readInt();
mAudioDirection = in.readInt();
+ mAudioCodecAttributes = in.readTypedObject(AudioCodecAttributes.CREATOR);
mVideoQuality = in.readInt();
mVideoDirection = in.readInt();
mRttMode = in.readInt();
@@ -275,6 +283,23 @@ public final class ImsStreamMediaProfile implements Parcelable {
return mAudioDirection;
}
+ /**
+ * Get the audio codec attributes {@link AudioCodecAttributes} which may be {@code null} if
+ * ImsService doesn't support this information.
+ * @return audio codec attributes
+ */
+ public @Nullable AudioCodecAttributes getAudioCodecAttributes() {
+ return mAudioCodecAttributes;
+ }
+
+ /**
+ * Set the audio codec attributes {@link AudioCodecAttributes} which includes bitrate and
+ * bandwidth information.
+ */
+ public void setAudioCodecAttributes(@NonNull AudioCodecAttributes audioCodecAttributes) {
+ mAudioCodecAttributes = audioCodecAttributes;
+ }
+
public int getVideoQuality() {
return mVideoQuality;
}
diff --git a/telephony/java/android/telephony/ims/RtpHeaderExtension.aidl b/telephony/java/android/telephony/ims/RtpHeaderExtension.aidl
new file mode 100644
index 000000000000..cbf79d352ad8
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RtpHeaderExtension.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.telephony.ims;
+
+parcelable RtpHeaderExtension; \ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/RtpHeaderExtension.java b/telephony/java/android/telephony/ims/RtpHeaderExtension.java
new file mode 100644
index 000000000000..f9ab7016facb
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RtpHeaderExtension.java
@@ -0,0 +1,137 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * A representation of an RTP header extension.
+ * <p>
+ * Per RFC8285, an RTP header extension consists of both a local identifier in the range 1-14, an
+ * 8-bit length indicator and a number of extension data bytes equivalent to the stated length.
+ * @hide
+ */
+@SystemApi
+public final class RtpHeaderExtension implements Parcelable {
+ private int mLocalIdentifier;
+ private byte[] mExtensionData;
+
+ /**
+ * Creates a new {@link RtpHeaderExtension}.
+ * @param localIdentifier The local identifier for this RTP header extension.
+ * @param extensionData The data for this RTP header extension.
+ * @throws IllegalArgumentException if {@code extensionId} is not in the range 1-14.
+ * @throws NullPointerException if {@code extensionData} is null.
+ */
+ public RtpHeaderExtension(@IntRange(from = 1, to = 14) int localIdentifier,
+ @NonNull byte[] extensionData) {
+ if (localIdentifier < 1 || localIdentifier > 13) {
+ throw new IllegalArgumentException("localIdentifier must be in range 1-14");
+ }
+ if (extensionData == null) {
+ throw new NullPointerException("extensionDa is required.");
+ }
+ mLocalIdentifier = localIdentifier;
+ mExtensionData = extensionData;
+ }
+
+ /**
+ * Creates a new instance of {@link RtpHeaderExtension} from a parcel.
+ * @param in The parceled data to read.
+ */
+ private RtpHeaderExtension(@NonNull Parcel in) {
+ mLocalIdentifier = in.readInt();
+ mExtensionData = in.createByteArray();
+ }
+
+ /**
+ * The local identifier for the RTP header extension.
+ * <p>
+ * Per RFC8285, the extension ID is a value in the range 1-14 (0 is reserved for padding and
+ * 15 is reserved for the one-byte header form.
+ * <p>
+ * Within the current call, this extension ID will match one of the
+ * {@link RtpHeaderExtensionType#getLocalIdentifier()}s.
+ *
+ * @return The local identifier for this RTP header extension.
+ */
+ @IntRange(from = 1, to = 14)
+ public int getLocalIdentifier() {
+ return mLocalIdentifier;
+ }
+
+ /**
+ * The data payload for the RTP header extension.
+ * <p>
+ * Per RFC8285 Sec 4.3, an RTP header extension includes an 8-bit length field which indicate
+ * how many bytes of data are present in the RTP header extension. The extension includes this
+ * many bytes of actual data.
+ * <p>
+ * We represent this as a byte array who's length is equivalent to the 8-bit length field.
+ * @return RTP header extension data payload. The payload may be up to 255 bytes in length.
+ */
+ public @NonNull byte[] getExtensionData() {
+ return mExtensionData;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mLocalIdentifier);
+ dest.writeByteArray(mExtensionData);
+ }
+
+ public static final @NonNull Creator<RtpHeaderExtension> CREATOR =
+ new Creator<RtpHeaderExtension>() {
+ @Override
+ public RtpHeaderExtension createFromParcel(@NonNull Parcel in) {
+ return new RtpHeaderExtension(in);
+ }
+
+ @Override
+ public RtpHeaderExtension[] newArray(int size) {
+ return new RtpHeaderExtension[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RtpHeaderExtension that = (RtpHeaderExtension) o;
+ return mLocalIdentifier == that.mLocalIdentifier
+ && Arrays.equals(mExtensionData, that.mExtensionData);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mLocalIdentifier);
+ result = 31 * result + Arrays.hashCode(mExtensionData);
+ return result;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RtpHeaderExtensionType.aidl b/telephony/java/android/telephony/ims/RtpHeaderExtensionType.aidl
new file mode 100644
index 000000000000..3e62ffff5127
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RtpHeaderExtensionType.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.telephony.ims;
+
+parcelable RtpHeaderExtensionType; \ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/RtpHeaderExtensionType.java b/telephony/java/android/telephony/ims/RtpHeaderExtensionType.java
new file mode 100644
index 000000000000..e1d39c217395
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RtpHeaderExtensionType.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 android.telephony.ims;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Defines a mapping between a local identifier and a {@link Uri} which identifies an RTP header
+ * extension.
+ * <p>
+ * According to RFC8285, SDP (Session Description Protocol) signalling for a call provides a means
+ * for the supported RTP header extensions for a call to be negotiated at call initiation time.
+ * The types of RTP header extensions potentially usable in a session are identified by a local
+ * identifier ({@link #getLocalIdentifier()}) when RTP header extensions are present on RTP packets.
+ * A {@link Uri} ({@link #getUri()}) provides a unique identifier for the RTP header extension
+ * format which parties in a call can use to identify supported RTP header extensions.
+ * @hide
+ */
+@SystemApi
+public final class RtpHeaderExtensionType implements Parcelable {
+ private int mLocalIdentifier;
+ private Uri mUri;
+
+ /**
+ * Create a new RTP header extension type.
+ * @param localIdentifier the local identifier.
+ * @param uri the {@link Uri} identifying the RTP header extension type.
+ * @throws IllegalArgumentException if {@code localIdentifier} is out of the expected range.
+ * @throws NullPointerException if {@code uri} is null.
+ */
+ public RtpHeaderExtensionType(@IntRange(from = 1, to = 14) int localIdentifier,
+ @NonNull Uri uri) {
+ if (localIdentifier < 1 || localIdentifier > 13) {
+ throw new IllegalArgumentException("localIdentifier must be in range 1-14");
+ }
+ if (uri == null) {
+ throw new NullPointerException("uri is required.");
+ }
+ mLocalIdentifier = localIdentifier;
+ mUri = uri;
+ }
+
+ private RtpHeaderExtensionType(Parcel in) {
+ mLocalIdentifier = in.readInt();
+ mUri = in.readParcelable(Uri.class.getClassLoader());
+ }
+
+ public static final @NonNull Creator<RtpHeaderExtensionType> CREATOR =
+ new Creator<RtpHeaderExtensionType>() {
+ @Override
+ public RtpHeaderExtensionType createFromParcel(@NonNull Parcel in) {
+ return new RtpHeaderExtensionType(in);
+ }
+
+ @Override
+ public @NonNull RtpHeaderExtensionType[] newArray(int size) {
+ return new RtpHeaderExtensionType[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mLocalIdentifier);
+ dest.writeParcelable(mUri, flags);
+ }
+
+ /**
+ * The local identifier for this RTP header extension type.
+ * <p>
+ * {@link RtpHeaderExtension}s which indicate a {@link RtpHeaderExtension#getLocalIdentifier()}
+ * matching this local identifier will have the format specified by {@link #getUri()}.
+ * <p>
+ * Per RFC8285, the extension ID is a value in the range 1-14 (0 is reserved for padding and
+ * 15 is reserved for the one-byte header form.
+ *
+ * @return The local identifier associated with this {@link #getUri()}.
+ */
+ public @IntRange(from = 1, to = 14) int getLocalIdentifier() {
+ return mLocalIdentifier;
+ }
+
+ /**
+ * A {@link Uri} which identifies the format of the RTP extension header.
+ * <p>
+ * According to RFC8285 section 5, URIs MUST be absolute and SHOULD contain a month/date pair
+ * in the form mmyyyy to indicate versioning of the extension. Extension headers defined in an
+ * RFC are typically defined using URNs starting with {@code urn:ietf:params:rtp-hdrext:}.
+ * For example, RFC6464 defines {@code urn:ietf:params:rtp-hdrext:ssrc-audio-level} which is an
+ * RTP header extension for communicating client to mixer audio level indications.
+ *
+ * @return A unique {@link Uri} identifying the format of the RTP extension header.
+ */
+ public @NonNull Uri getUri() {
+ return mUri;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RtpHeaderExtensionType that = (RtpHeaderExtensionType) o;
+ return mLocalIdentifier == that.mLocalIdentifier
+ && mUri.equals(that.mUri);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mLocalIdentifier, mUri);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/SipDelegateConnection.java b/telephony/java/android/telephony/ims/SipDelegateConnection.java
new file mode 100644
index 000000000000..6bfdc2c6d48a
--- /dev/null
+++ b/telephony/java/android/telephony/ims/SipDelegateConnection.java
@@ -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 android.telephony.ims;
+
+import android.annotation.NonNull;
+import android.telephony.ims.stub.SipDelegate;
+
+/**
+ * Represents a connection to the remote {@link SipDelegate} that is managed by the
+ * {@link ImsService} implementing IMS for the subscription that is associated with it.
+ * <p>
+ * The remote delegate will handle messages sent by this {@link SipDelegateConnection}, notifying
+ * the associated {@link DelegateMessageCallback} when the message was either sent successfully or
+ * failed to be sent.
+ * <p>
+ * It is also the responsibility of this {@link SipDelegateConnection} to acknowledge when incoming
+ * SIP messages have been received successfully via
+ * {@link DelegateMessageCallback#onMessageReceived(SipMessage)} or when there was an error
+ * receiving the message using {@link #notifyMessageReceived(String)} and
+ * {@link #notifyMessageReceiveError(String, int)}.
+ *
+ * @see SipDelegateManager#createSipDelegate
+ * @hide
+ */
+public interface SipDelegateConnection {
+
+ /**
+ * Send a SIP message to the SIP delegate to be sent over the carrier’s network. The
+ * {@link SipMessage} will either be acknowledged with
+ * {@link DelegateMessageCallback#onMessageSent(String)} upon successful sending of this message
+ * or {@link DelegateMessageCallback#onMessageSendFailure(String, int)} if there was an error
+ * sending the message.
+ * @param sipMessage The SipMessage to be sent.
+ * @param configVersion The SipDelegateImsConfiguration version used to construct the
+ * SipMessage. See {@link SipDelegateImsConfiguration#getVersion} for more
+ * information on this parameter and why it is used.
+ */
+ void sendMessage(@NonNull SipMessage sipMessage, int configVersion);
+
+ /**
+ * Notify the {@link SipDelegate} that a SIP message received from
+ * {@link DelegateMessageCallback#onMessageReceived(SipMessage)} has been received successfully
+ * and is being processed.
+ * @param viaTransactionId Per RFC3261 Sec 8.1.1.7 the transaction ID associated with the Via
+ * branch parameter.
+ */
+ void notifyMessageReceived(@NonNull String viaTransactionId);
+
+ /**
+ * Notify the SIP delegate that the SIP message has been received from
+ * {@link DelegateMessageCallback#onMessageReceived(SipMessage)}, however there was an error
+ * processing it.
+ * @param viaTransactionId Per RFC3261 Sec 8.1.1.7 the transaction ID associated with the Via
+ * branch parameter.
+ * @param reason The reason why the error occurred.
+ */
+ void notifyMessageReceiveError(@NonNull String viaTransactionId,
+ @SipDelegateManager.MessageFailureReason int reason);
+}
diff --git a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.aidl b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.aidl
new file mode 100644
index 000000000000..44ae1b130046
--- /dev/null
+++ b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.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.telephony.ims;
+
+parcelable SipDelegateImsConfiguration;
diff --git a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
new file mode 100644
index 000000000000..8abd0ee94865
--- /dev/null
+++ b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
@@ -0,0 +1,499 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PersistableBundle;
+import android.telephony.ims.stub.SipDelegate;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The IMS registration and other attributes that the {@link SipDelegateConnection} used by the
+ * IMS application will need to be aware of to correctly generate outgoing {@link SipMessage}s.
+ * <p>
+ * The IMS service must generate new instances of this configuration as the IMS configuration
+ * managed by the IMS service changes. Along with each {@link SipDelegateImsConfiguration} instance
+ * containing the configuration is the "version", which should be incremented every time a new
+ * {@link SipDelegateImsConfiguration} instance is created. The {@link SipDelegateConnection} will
+ * include the version of the {@link SipDelegateImsConfiguration} instance that it used in order for
+ * the {@link SipDelegate} to easily identify if the IMS application used a now stale configuration
+ * to generate the {@link SipMessage} and return
+ * {@link SipDelegateManager#MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION} in
+ * {@link DelegateMessageCallback#onMessageSendFailure(String, int)} so that the IMS application can
+ * regenerate that {@link SipMessage} using the correct {@link SipDelegateImsConfiguration}
+ * instance.
+ * <p>
+ * Every time the IMS configuration state changes in the IMS service, a full configuration should
+ * be generated. The new {@link SipDelegateImsConfiguration} instance should not be an incremental
+ * update.
+ * @hide
+ */
+public class SipDelegateImsConfiguration implements Parcelable {
+
+ /**
+ * IPV4 Address type.
+ * <p>
+ * Used as a potential value for {@link #KEY_SIP_CONFIG_IPTYPE_STRING}.
+ */
+ public static final String IPTYPE_IPV4 = "IPV4";
+
+ /**
+ * IPV6 Address type.
+ * <p>
+ * Used as a potential value for {@link #KEY_SIP_CONFIG_IPTYPE_STRING}.
+ */
+ public static final String IPTYPE_IPV6 = "IPV6";
+
+ /**
+ * The SIP transport uses UDP.
+ * <p>
+ * Used as a potential value for {@link #KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING}.
+ */
+ public static final String SIP_TRANSPORT_UDP = "UDP";
+
+ /**
+ * The SIP transport uses TCP.
+ * <p>
+ * Used as a potential value for {@link #KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING}.
+ */
+ public static final String SIP_TRANSPORT_TCP = "TCP";
+
+ /**
+ * Flag specifying if SIP compact form is enabled
+ */
+ public static final String KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL =
+ "sip_config_is_compact_form_enabled_bool";
+
+ /**
+ * Flag specifying if SIP keepalives are enabled
+ */
+ public static final String KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL =
+ "sip_config_is_keepalive_enabled_bool";
+
+ /**
+ * Maximum SIP payload to be sent on UDP. If the SIP message payload is greater than max udp
+ * payload size, then TCP must be used
+ */
+ public static final String KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT =
+ "sip_config_udp_max_payload_size_int";
+
+ /**
+ * Transport protocol used for SIP signaling.
+ * Available options are: {@link #SIP_TRANSPORT_UDP }, {@link #SIP_TRANSPORT_TCP }
+ */
+ public static final String KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING =
+ "sip_config_protocol_type_string";
+
+ /**
+ * IMS public user identifier string
+ */
+ public static final String KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING =
+ "sip_config_ue_public_user_id_string";
+
+ /**
+ * IMS private user identifier string
+ */
+ public static final String KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING =
+ "sip_config_ue_private_user_id_string";
+
+ /**
+ * IMS home domain string
+ */
+ public static final String KEY_SIP_CONFIG_HOME_DOMAIN_STRING = "sip_config_home_domain_string";
+
+ /**
+ * IMEI string. Application can include the Instance-ID feature tag " +sip.instance" in the
+ * Contact header with a value of the device IMEI in the form "urn:gsma:imei:<device IMEI>".
+ */
+ public static final String KEY_SIP_CONFIG_IMEI_STRING = "sip_config_imei_string";
+
+ /**
+ * IP address type for SIP signaling.
+ * Available options are: {@link #IPTYPE_IPV6}, {@link #IPTYPE_IPV4}
+ */
+ public static final String KEY_SIP_CONFIG_IPTYPE_STRING = "sip_config_iptype_string";
+
+ /**
+ * Local IPaddress used for SIP signaling.
+ */
+ public static final String KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING =
+ "sip_config_ue_default_ipaddress_string";
+
+ /**
+ * Local port used for sending SIP traffic
+ */
+ public static final String KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT =
+ "sip_config_ue_default_port_int";
+
+ /**
+ * SIP server / PCSCF default ip address
+ */
+ public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING =
+ "sip_config_server_default_ipaddress_string";
+
+ /**
+ * SIP server / PCSCF port used for sending SIP traffic
+ */
+ public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT =
+ "sip_config_server_default_port_int";
+
+ /**
+ * Flag specifying if Network Address Translation is enabled and UE is behind a NAT.
+ */
+ public static final String KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL =
+ "sip_config_is_nat_enabled_bool";
+
+ /**
+ * UE's public IPaddress when UE is behind a NAT.
+ * <p>
+ * This key will not exist if {@link #KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL} is {@code false}.
+ */
+ public static final String KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING =
+ "sip_config_ue_public_ipaddress_with_nat_string";
+
+ /**
+ * UE's public SIP port when UE is behind a NAT.
+ * <p>
+ * This key will not exist if {@link #KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL} is {@code false}.
+ */
+ public static final String KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT =
+ "sip_config_ue_public_port_with_nat_int";
+
+ /**
+ * Flag specifying if Globally routable user-agent uri (GRUU) is enabled as per TS 23.808
+ */
+ public static final String KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL =
+ "sip_config_is_gruu_enabled_bool";
+
+ /**
+ * UE's Globally routable user-agent uri if this feature is enabled.
+ * <p>
+ * This key will not exist if {@link #KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL} is {@code false}.
+ */
+ public static final String KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING =
+ "sip_config_ue_public_gruu_string";
+
+ /**
+ * Flag specifying if SIP over IPSec is enabled.
+ */
+ public static final String KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL =
+ "sip_config_is_ipsec_enabled_bool";
+ /**
+ * UE's SIP port used to send traffic when IPSec is enabled.
+ * <p>
+ * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+ */
+ public static final String KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT =
+ "sip_config_ue_ipsec_client_port_int";
+
+ /**
+ * UE's SIP port used to receive traffic when IPSec is enabled.
+ * <p>
+ * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+ */
+ public static final String KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT =
+ "sip_config_ue_ipsec_server_port_int";
+
+ /**
+ * UE's SIP port used for the previous IPsec security association if IPSec is enabled.
+ * <p>
+ * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+ */
+ public static final String KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT =
+ "sip_config_ue_ipsec_old_client_port_int";
+
+ /**
+ * Port number used by the SIP server to send SIP traffic when IPSec is enabled.
+ * <p>
+ * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+ */
+ public static final String KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT =
+ "sip_config_server_ipsec_client_port_int";
+
+ /**
+ * Port number used by the SIP server to receive incoming SIP traffic when IPSec is enabled.
+ * <p>
+ * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+ */
+ public static final String KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT =
+ "sip_config_server_ipsec_server_port_int";
+
+ /**
+ * Port number used by the SIP server to send SIP traffic on the previous IPSec security
+ * association when IPSec is enabled.
+ * <p>
+ * This key will not exist if {@link #KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL} is {@code false}.
+ */
+ public static final String KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT =
+ "sip_config_server_ipsec_old_client_port_int";
+ /**
+ * SIP Authentication header string
+ */
+ public static final String KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING =
+ "sip_config_auhentication_header_string";
+
+ /**
+ * SIP Authentication nonce string
+ */
+ public static final String KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING =
+ "sip_config_authentication_nonce_string";
+
+ /**
+ * SIP service route header string
+ */
+ public static final String KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING =
+ "sip_config_service_route_header_string";
+
+ /**
+ * SIP security verify header string
+ */
+ public static final String KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING =
+ "sip_config_security_verify_header_string";
+
+ /**
+ * SIP Path header string
+ */
+ public static final String KEY_SIP_CONFIG_PATH_HEADER_STRING =
+ "sip_config_path_header_string";
+
+ /**
+ * SIP User part string in contact header
+ */
+ public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING =
+ "sip_config_uri_user_part_string";
+
+ /**
+ * SIP P-access-network-info header string
+ */
+ public static final String KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING =
+ "sip_config_p_access_network_info_header_string";
+
+ /**
+ * SIP P-last-access-network-info header string
+ */
+ public static final String KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING =
+ "sip_config_p_last_access_network_info_header_string";
+
+ /**
+ * SIP P-associated-uri header string
+ */
+ public static final String KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING =
+ "sip_config_p_associated_uri_header_string";
+
+ /**@hide*/
+ @StringDef(prefix = "KEY_SIP_CONFIG", suffix = "_STRING", value = {
+ KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING,
+ KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING,
+ KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING,
+ KEY_SIP_CONFIG_HOME_DOMAIN_STRING,
+ KEY_SIP_CONFIG_IMEI_STRING,
+ KEY_SIP_CONFIG_IPTYPE_STRING,
+ KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING,
+ KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING,
+ KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING,
+ KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING,
+ KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING,
+ KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING,
+ KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING,
+ KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING,
+ KEY_SIP_CONFIG_PATH_HEADER_STRING,
+ KEY_SIP_CONFIG_URI_USER_PART_STRING,
+ KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING,
+ KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING,
+ KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StringConfigKey {}
+
+ /**@hide*/
+ @StringDef(prefix = "KEY_SIP_CONFIG", suffix = "_INT", value = {
+ KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT,
+ KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT,
+ KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT,
+ KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT,
+ KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT,
+ KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT,
+ KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT,
+ KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT,
+ KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT,
+ KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface IntConfigKey {}
+
+ /**@hide*/
+ @StringDef(prefix = "KEY_SIP_CONFIG", suffix = "_BOOL", value = {
+ KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL,
+ KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL,
+ KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL,
+ KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL,
+ KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BooleanConfigKey {}
+
+ /**
+ * Builder class to be used when constructing a new SipDelegateImsConfiguration.
+ */
+ public static class Builder {
+ private final long mVersion;
+ private final PersistableBundle mBundle;
+
+ /**
+ * Creates an empty implementation of SipDelegateImsConfiguration.
+ * @param version The version associated with the SipDelegateImsConfiguration being built.
+ * See {@link #getVersion} for more information.
+ */
+ public Builder(int version) {
+ mVersion = version;
+ mBundle = new PersistableBundle();
+ }
+ /**
+ * Clones an existing implementation of SipDelegateImsConfiguration to handle situations
+ * where only a small number of parameters have changed from the previous configuration.
+ * <p>
+ * Automatically increments the version of this configuration by 1. See {@link #getVersion}
+ * for more information.
+ */
+ public Builder(@NonNull SipDelegateImsConfiguration config) {
+ mVersion = config.getVersion() + 1;
+ mBundle = config.copyBundle();
+ }
+ /**
+ * Put a string value into this configuration bundle for the given key.
+ */
+ public Builder putString(@StringConfigKey String key, String value) {
+ mBundle.putString(key, value);
+ return this;
+ }
+
+ /**
+ * Replace the existing default value with a new value for a given key.
+ */
+ public Builder putInt(@IntConfigKey String key, int value) {
+ mBundle.putInt(key, value);
+ return this;
+ }
+
+ /**
+ * Replace the existing default value with a new value for a given key.
+ */
+ public Builder putBoolean(@BooleanConfigKey String key, boolean value) {
+ mBundle.putBoolean(key, value);
+ return this;
+ }
+
+ /**
+ * @return a new SipDelegateImsConfiguration from this Builder.
+ */
+ public SipDelegateImsConfiguration build() {
+ return new SipDelegateImsConfiguration(mVersion, mBundle);
+ }
+ }
+
+ private final long mVersion;
+ private final PersistableBundle mBundle;
+
+ private SipDelegateImsConfiguration(long version, PersistableBundle bundle) {
+ mVersion = version;
+ mBundle = bundle;
+ }
+
+ private SipDelegateImsConfiguration(Parcel source) {
+ mVersion = source.readLong();
+ mBundle = source.readPersistableBundle();
+ }
+
+ /**
+ * @return the string value associated with a given key or {@code null} if it doesn't exist.
+ */
+ public @StringConfigKey String getString(String key) {
+ return mBundle.getString(key);
+ }
+
+ /**
+ * @return the Integer value associated with a given key or {@code null} if the value doesn't
+ * exist.
+ */
+ public @IntConfigKey Integer getInt(String key) {
+ if (!mBundle.containsKey(key)) {
+ return null;
+ }
+ return mBundle.getInt(key);
+ }
+
+ /**
+ * @return the Integer value associated with a given key or {@code null} if the value doesn't
+ * exist.
+ */
+ public @BooleanConfigKey Boolean getBoolen(String key) {
+ if (!mBundle.containsKey(key)) {
+ return null;
+ }
+ return mBundle.getBoolean(key);
+ }
+
+ /**
+ * @return a shallow copy of the full configuration.
+ */
+ public PersistableBundle copyBundle() {
+ return new PersistableBundle(mBundle);
+ }
+
+ /**
+ * An integer representing the version number of this SipDelegateImsConfiguration.
+ * {@link SipMessage}s that are created using this configuration will also have a this
+ * version number associated with them, which will allow the IMS service to validate that the
+ * {@link SipMessage} was using the latest configuration during creation and not a stale
+ * configuration due to race conditions between the configuration being updated and the RCS
+ * application not receiving the updated configuration before generating a new message.
+ *
+ * @return the version number associated with this {@link SipDelegateImsConfiguration}.
+ */
+ public long getVersion() {
+ return mVersion;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mVersion);
+ dest.writePersistableBundle(mBundle);
+ }
+
+ public static final Creator<SipDelegateImsConfiguration> CREATOR =
+ new Creator<SipDelegateImsConfiguration>() {
+ @Override
+ public SipDelegateImsConfiguration createFromParcel(Parcel source) {
+ return new SipDelegateImsConfiguration(source);
+ }
+
+ @Override
+ public SipDelegateImsConfiguration[] newArray(int size) {
+ return new SipDelegateImsConfiguration[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java
index 82c8a9cd58f4..337b7d49323d 100644
--- a/telephony/java/android/telephony/ims/SipDelegateManager.java
+++ b/telephony/java/android/telephony/ims/SipDelegateManager.java
@@ -17,29 +17,251 @@
package android.telephony.ims;
import android.Manifest;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.telephony.BinderCacheManager;
import android.telephony.CarrierConfigManager;
-import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.aidl.IImsRcsController;
+import android.telephony.ims.aidl.SipDelegateConnectionAidlWrapper;
+import android.telephony.ims.stub.DelegateConnectionMessageCallback;
+import android.telephony.ims.stub.DelegateConnectionStateCallback;
+import android.telephony.ims.stub.SipDelegate;
import com.android.internal.annotations.VisibleForTesting;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
/**
- * Manages the creation and destruction of SipDelegates, which allow an IMS application to forward
- * SIP messages for the purposes of providing a single IMS registration to the carrier's IMS network
- * from multiple sources.
+ * Manages the creation and destruction of SipDelegates for the {@link ImsService} managing IMS
+ * for the subscription ID that this SipDelegateManager has been created for.
+ *
+ * This allows multiple IMS applications to forward SIP messages to/from their application for the
+ * purposes of providing a single IMS registration to the carrier's IMS network from potentially
+ * many IMS stacks implementing a subset of the supported MMTEL/RCS features.
* @hide
*/
@SystemApi
public class SipDelegateManager {
+ /**
+ * The SIP message has failed being sent or received for an unknown reason.
+ * <p>
+ * The caller should retry a message that failed with this response.
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_UNKNOWN = 0;
+
+ /**
+ * The remote service associated with this connection has died and the message was not
+ * properly sent/received.
+ * <p>
+ * This is considered a permanent error and the system will automatically begin the teardown and
+ * destruction of the SipDelegate. No further messages should be sent on this transport.
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_DELEGATE_DEAD = 1;
+
+ /**
+ * The message has not been sent/received because the delegate is in the process of closing and
+ * has become unavailable. No further messages should be sent/received on this delegate.
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_DELEGATE_CLOSED = 2;
+
+ /**
+ * The SIP message has an invalid start line and the message can not be sent.
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_INVALID_START_LINE = 3;
+
+ /**
+ * One or more of the header fields in the header section of the outgoing SIP message is invalid
+ * and the SIP message can not be sent.
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS = 4;
+
+ /**
+ * The body content of the SIP message is invalid and the message can not be sent.
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT = 5;
+
+ /**
+ * The feature tag associated with the outgoing message does not match any known feature tags
+ * and this message can not be sent.
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG = 6;
+
+ /**
+ * The feature tag associated with the outgoing message is not enabled for the associated
+ * SipDelegateConnection and can not be sent.
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE = 7;
+
+ /**
+ * The link to the network has been lost and the outgoing message has failed to send.
+ * <p>
+ * This message should be retried when connectivity to the network is re-established. See
+ * {@link android.net.ConnectivityManager.NetworkCallback} for how this can be determined.
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE = 8;
+
+ /**
+ * The outgoing SIP message has not been sent due to the SipDelegate not being registered for
+ * IMS at this time.
+ * <p>
+ * This is considered a temporary failure, the message should not be retried until an IMS
+ * registration change callback is received via
+ * {@link DelegateConnectionStateCallback#onFeatureTagStatusChanged}
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_NOT_REGISTERED = 9;
+
+ /**
+ * The outgoing SIP message has not been sent because the {@link SipDelegateImsConfiguration}
+ * version associated with the outgoing {@link SipMessage} is now stale and has failed
+ * validation checks.
+ * <p>
+ * The @link SipMessage} should be recreated using the newest
+ * {@link SipDelegateImsConfiguration} and sent again.
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION = 10;
+
+ /**
+ * The outgoing SIP message has not been sent because the internal state of the associated
+ * {@link SipDelegate} is changing and has temporarily brought the transport down.
+ * <p>
+ * This is considered a temporary error and the {@link SipDelegateConnection} should resend the
+ * message once {@link DelegateRegistrationState#DEREGISTERING_REASON_FEATURE_TAGS_CHANGING} is
+ * no longer reported.
+ * @hide
+ */
+ public static final int MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION = 11;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "MESSAGE_FAILURE_REASON_", value = {
+ MESSAGE_FAILURE_REASON_UNKNOWN,
+ MESSAGE_FAILURE_REASON_DELEGATE_DEAD,
+ MESSAGE_FAILURE_REASON_DELEGATE_CLOSED,
+ MESSAGE_FAILURE_REASON_INVALID_START_LINE,
+ MESSAGE_FAILURE_REASON_INVALID_HEADER_FIELDS,
+ MESSAGE_FAILURE_REASON_INVALID_BODY_CONTENT,
+ MESSAGE_FAILURE_REASON_INVALID_FEATURE_TAG,
+ MESSAGE_FAILURE_REASON_TAG_NOT_ENABLED_FOR_DELEGATE,
+ MESSAGE_FAILURE_REASON_NETWORK_NOT_AVAILABLE,
+ MESSAGE_FAILURE_REASON_NOT_REGISTERED,
+ MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION,
+ MESSAGE_FAILURE_REASON_INTERNAL_DELEGATE_STATE_TRANSITION
+ })
+ public @interface MessageFailureReason {}
+
+
+ /**
+ * Access to use this feature tag has been denied for an unknown reason.
+ * @hide
+ */
+ public static final int DENIED_REASON_UNKNOWN = 0;
+
+ /**
+ * This feature tag is allowed to be used by this SipDelegateConnection, but it is in use by
+ * another SipDelegateConnection and can not be associated with this delegate. The feature tag
+ * will stay in this state until the feature tag is release by the other application.
+ * @hide
+ */
+ public static final int DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE = 1;
+
+ /**
+ * Access to use this feature tag has been denied because this application does not have the
+ * permissions required to access this feature tag.
+ * @hide
+ */
+ public static final int DENIED_REASON_NOT_ALLOWED = 2;
+
+ /**
+ * Access to use this feature tag has been denied because single registration is not allowed by
+ * the carrier at this time. The application should fall back to dual registration if
+ * applicable.
+ * @hide
+ */
+ public static final int DENIED_REASON_SINGLE_REGISTRATION_NOT_ALLOWED = 3;
+
+ /**
+ * This feature tag is not recognized as a valid feature tag by the SipDelegate and has been
+ * denied.
+ * @hide
+ */
+ public static final int DENIED_REASON_INVALID = 4;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "DENIED_REASON_", value = {
+ DENIED_REASON_UNKNOWN,
+ DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE,
+ DENIED_REASON_NOT_ALLOWED,
+ DENIED_REASON_SINGLE_REGISTRATION_NOT_ALLOWED,
+ DENIED_REASON_INVALID
+ })
+ public @interface DeniedReason {}
+
+ /**
+ * The SipDelegate has closed due to an unknown reason.
+ * @hide
+ */
+ public static final int SIP_DELEGATE_DESTROY_REASON_UNKNOWN = 0;
+
+ /**
+ * The SipDelegate has closed because the IMS service has died unexpectedly.
+ * @hide
+ */
+ public static final int SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD = 1;
+
+ /**
+ * The SipDelegate has closed because the IMS application has requested that the connection be
+ * destroyed.
+ * @hide
+ */
+ public static final int SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP = 2;
+
+ /**
+ * The SipDelegate has closed because the IMS service does not support the creation of
+ * SipDelegates.
+ * @hide
+ */
+ public static final int SIP_DELEGATE_DESTROY_REASON_SERVICE_NOT_SUPPORTED = 3;
+
+ /**
+ * The SipDelegate has been closed due to the user disabling RCS.
+ * @hide
+ */
+ public static final int SIP_DELEGATE_DESTROY_REASON_USER_DISABLED_RCS = 4;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "SIP_DELEGATE_DESTROY_REASON", value = {
+ SIP_DELEGATE_DESTROY_REASON_UNKNOWN,
+ SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD,
+ SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP,
+ SIP_DELEGATE_DESTROY_REASON_SERVICE_NOT_SUPPORTED,
+ SIP_DELEGATE_DESTROY_REASON_USER_DISABLED_RCS
+ })
+ public @interface SipDelegateDestroyReason {}
+
private final Context mContext;
private final int mSubId;
+ private final BinderCacheManager<IImsRcsController> mBinderCache;
/**
* Only visible for testing. To instantiate an instance of this class, please use
@@ -47,9 +269,11 @@ public class SipDelegateManager {
* @hide
*/
@VisibleForTesting
- public SipDelegateManager(Context context, int subId) {
+ public SipDelegateManager(Context context, int subId,
+ BinderCacheManager<IImsRcsController> binderCache) {
mContext = context;
mSubId = subId;
+ mBinderCache = binderCache;
}
/**
@@ -69,7 +293,7 @@ public class SipDelegateManager {
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isSupported() throws ImsException {
try {
- IImsRcsController controller = getIImsRcsController();
+ IImsRcsController controller = mBinderCache.getBinder();
if (controller == null) {
throw new ImsException("Telephony server is down",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
@@ -83,11 +307,90 @@ public class SipDelegateManager {
}
}
- private IImsRcsController getIImsRcsController() {
- IBinder binder = TelephonyFrameworkInitializer
- .getTelephonyServiceManager()
- .getTelephonyImsServiceRegisterer()
- .get();
- return IImsRcsController.Stub.asInterface(binder);
+ /**
+ * Request that the ImsService implementation create a SipDelegate, which will configure the
+ * ImsService to forward SIP traffic that matches the filtering criteria set in supplied
+ * {@link DelegateRequest} to the application that the supplied callbacks are registered for.
+ * <p>
+ * This API requires that the caller is running as part of a long-running process and will
+ * always be available to handle incoming messages. One mechanism that can be used for this is
+ * the {@link android.service.carrier.CarrierMessagingClientService}, which the framework keeps
+ * a persistent binding to when the app is the default SMS application.
+ * @param request The parameters that are associated with the SipDelegate creation request that
+ * will be used to create the SipDelegate connection.
+ * @param executor The executor that will be used to call the callbacks associated with this
+ * SipDelegate.
+ * @param dc The callback that will be used to notify the listener of the creation/destruction
+ * of the remote SipDelegate as well as changes to the state of the remote SipDelegate
+ * connection.
+ * @param mc The callback that will be used to notify the listener of new incoming SIP messages
+ * as well as the status of messages that were sent by the associated
+ * SipDelegateConnection.
+ * @throws ImsException Thrown if there was a problem communicating with the ImsService
+ * associated with this SipDelegateManager. See {@link ImsException#getCode()}.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void createSipDelegate(@NonNull DelegateRequest request, @NonNull Executor executor,
+ @NonNull DelegateConnectionStateCallback dc,
+ @NonNull DelegateConnectionMessageCallback mc) throws ImsException {
+ if (request == null || executor == null || dc == null || mc == null) {
+ throw new IllegalArgumentException("Invalid arguments passed into createSipDelegate");
+ }
+ try {
+ SipDelegateConnectionAidlWrapper wrapper =
+ new SipDelegateConnectionAidlWrapper(executor, dc, mc);
+ IImsRcsController controller = mBinderCache.listenOnBinder(wrapper,
+ wrapper::binderDied);
+ if (controller == null) {
+ throw new ImsException("Telephony server is down",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ controller.createSipDelegate(mSubId, request, wrapper.getStateCallbackBinder(),
+ wrapper.getMessageCallbackBinder());
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
+ } catch (RemoteException e) {
+ throw new ImsException(e.getMessage(),
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
+ * Destroy a previously created {@link SipDelegateConnection} that was created using
+ * {@link #createSipDelegate}.
+ * <p>
+ * This will also clean up all related callbacks in the associated ImsService.
+ * @param delegateConnection The SipDelegateConnection to destroy.
+ * @param reason The reason for why this SipDelegateConnection was destroyed.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void destroySipDelegate(@NonNull SipDelegateConnection delegateConnection,
+ @SipDelegateDestroyReason int reason) {
+
+ if (delegateConnection == null) {
+ throw new IllegalArgumentException("invalid argument passed into destroySipDelegate");
+ }
+ if (delegateConnection instanceof SipDelegateConnectionAidlWrapper) {
+ SipDelegateConnectionAidlWrapper w =
+ (SipDelegateConnectionAidlWrapper) delegateConnection;
+ try {
+ IImsRcsController c = mBinderCache.removeRunnable(w);
+ c.destroySipDelegate(mSubId, w.getSipDelegateBinder(), reason);
+ } catch (RemoteException e) {
+ // Connection to telephony died, but this will signal destruction of SipDelegate
+ // eventually anyway, so return normally.
+ try {
+ w.getStateCallbackBinder().onDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
+ } catch (RemoteException ignore) {
+ // Local to process.
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("Unknown SipDelegateConnection implementation passed"
+ + " into this method");
+ }
}
}
diff --git a/telephony/java/android/telephony/ims/SipMessage.aidl b/telephony/java/android/telephony/ims/SipMessage.aidl
new file mode 100644
index 000000000000..5140f8ac357f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/SipMessage.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.telephony.ims;
+
+parcelable SipMessage;
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
new file mode 100644
index 000000000000..c3b1be2d7fc8
--- /dev/null
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -0,0 +1,155 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a partially encoded SIP message. See RFC 3261 for more information on how SIP
+ * messages are structured and used.
+ * <p>
+ * The SIP message is represented in a partially encoded form in order to allow for easier
+ * verification and should not be used as a generic SIP message container.
+ * @hide
+ */
+public final class SipMessage implements Parcelable {
+ // Should not be set to true for production!
+ private static final boolean IS_DEBUGGING = Build.IS_ENG;
+
+ private static final String[] SIP_REQUEST_METHODS = new String[] {"INVITE", "ACK", "OPTIONS",
+ "BYE", "CANCEL", "REGISTER"};
+
+ private final String mStartLine;
+ private final String mHeaderSection;
+ private final byte[] mContent;
+
+ /**
+ * Represents a partially encoded SIP message.
+ *
+ * @param startLine The start line of the message, containing either the request-line or
+ * status-line.
+ * @param headerSection A String containing the full unencoded SIP message header.
+ * @param content UTF-8 encoded SIP message body.
+ */
+ public SipMessage(@NonNull String startLine, @NonNull String headerSection,
+ @NonNull byte[] content) {
+ if (startLine == null || headerSection == null || content == null) {
+ throw new IllegalArgumentException("One or more null parameters entered");
+ }
+ mStartLine = startLine;
+ mHeaderSection = headerSection;
+ mContent = content;
+ }
+
+ /**
+ * Private constructor used only for unparcelling.
+ */
+ private SipMessage(Parcel source) {
+ mStartLine = source.readString();
+ mHeaderSection = source.readString();
+ mContent = new byte[source.readInt()];
+ source.readByteArray(mContent);
+ }
+ /**
+ * @return The start line of the SIP message, which contains either the request-line or
+ * status-line.
+ */
+ public @NonNull String getStartLine() {
+ return mStartLine;
+ }
+
+ /**
+ * @return The full, unencoded header section of the SIP message.
+ */
+ public @NonNull String getHeaderSection() {
+ return mHeaderSection;
+ }
+
+ /**
+ * @return only the UTF-8 encoded SIP message body.
+ */
+ public @NonNull byte[] getContent() {
+ return mContent;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mStartLine);
+ dest.writeString(mHeaderSection);
+ dest.writeInt(mContent.length);
+ dest.writeByteArray(mContent);
+ }
+
+ public static final Creator<SipMessage> CREATOR = new Creator<SipMessage>() {
+ @Override
+ public SipMessage createFromParcel(Parcel source) {
+ return new SipMessage(source);
+ }
+
+ @Override
+ public SipMessage[] newArray(int size) {
+ return new SipMessage[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ StringBuilder b = new StringBuilder();
+ b.append("StartLine: [");
+ if (IS_DEBUGGING) {
+ b.append(mStartLine);
+ } else {
+ b.append(sanitizeStartLineRequest(mStartLine));
+ }
+ b.append("], [");
+ b.append("Header: [");
+ if (IS_DEBUGGING) {
+ b.append(mHeaderSection);
+ } else {
+ // only identify transaction id/call ID when it is available.
+ b.append("***");
+ }
+ b.append("], ");
+ b.append("Content: [NOT SHOWN]");
+ return b.toString();
+ }
+
+ /**
+ * Start lines containing requests are formatted: METHOD SP Request-URI SP SIP-Version CRLF.
+ * Detect if this is a REQUEST and redact Request-URI portion here, as it contains PII.
+ */
+ private String sanitizeStartLineRequest(String startLine) {
+ String[] splitLine = startLine.split(" ");
+ if (splitLine == null || splitLine.length == 0) {
+ return "(INVALID STARTLINE)";
+ }
+ for (String method : SIP_REQUEST_METHODS) {
+ if (splitLine[0].contains(method)) {
+ return splitLine[0] + " <Request-URI> " + splitLine[2];
+ }
+ }
+ return startLine;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
index 36d2067ad016..ed895b77a164 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
@@ -21,9 +21,12 @@ import android.telephony.ims.ImsStreamMediaProfile;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsConferenceState;
+import android.telephony.ims.RtpHeaderExtension;
import com.android.ims.internal.IImsCallSession;
import android.telephony.ims.ImsSuppServiceNotification;
+import java.util.List;
+
/**
* A listener type for receiving notification on IMS call session events.
* When an event is generated for an {@link IImsCallSession}, the application is notified
@@ -153,9 +156,17 @@ oneway interface IImsCallSessionListener {
void callSessionTransferred();
void callSessionTransferFailed(in ImsReasonInfo reasonInfo);
+ void callSessionDtmfReceived(char dtmf);
+
/**
* Notifies of a change to the call quality.
* @param callQuality then updated call quality
*/
void callQualityChanged(in CallQuality callQuality);
+
+ /**
+ * Notifies of incoming RTP header extensions from the network.
+ * @param extensions the RTP header extensions received.
+ */
+ void callSessionRtpHeaderExtensionsReceived(in List<RtpHeaderExtension> extensions);
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl b/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl
index b9a6b3c38a92..37fec7a73634 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl
@@ -21,6 +21,7 @@ import android.telephony.ims.aidl.IImsMmTelListener;
import android.telephony.ims.aidl.IImsSmsListener;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.feature.CapabilityChangeRequest;
+import android.telephony.ims.RtpHeaderExtensionType;
import android.telephony.ims.ImsCallProfile;
import com.android.ims.internal.IImsCallSession;
@@ -29,6 +30,8 @@ import com.android.ims.internal.IImsMultiEndpoint;
import com.android.ims.internal.IImsRegistrationListener;
import com.android.ims.internal.IImsUt;
+import java.util.List;
+
/**
* See MmTelFeature for more information.
* {@hide}
@@ -37,6 +40,7 @@ interface IImsMmTelFeature {
void setListener(IImsMmTelListener l);
int getFeatureState();
ImsCallProfile createCallProfile(int callSessionType, int callType);
+ void changeOfferedRtpHeaderExtensionTypes(in List<RtpHeaderExtensionType> types);
IImsCallSession createCallSession(in ImsCallProfile profile);
int shouldProcessCall(in String[] uris);
IImsUt getUtInterface();
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index 8e84e9373f65..f218e35a5a9b 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -17,10 +17,15 @@
package android.telephony.ims.aidl;
import android.net.Uri;
+import android.telephony.ims.DelegateRequest;
import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
-import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
+import android.telephony.ims.aidl.ISipDelegate;
+import android.telephony.ims.aidl.ISipDelegateMessageCallback;
+import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback;
import com.android.ims.ImsFeatureContainer;
import com.android.ims.internal.IImsServiceFeatureCallback;
@@ -58,6 +63,10 @@ interface IImsRcsController {
// SipDelegateManager
boolean isSipDelegateSupported(int subId);
+ void createSipDelegate(int subId, in DelegateRequest request,
+ ISipDelegateConnectionStateCallback delegateState,
+ ISipDelegateMessageCallback delegateMessage);
+ void destroySipDelegate(int subId, ISipDelegate connection, int reason);
// Internal commands that should not be made public
void registerRcsFeatureCallback(int slotId, in IImsServiceFeatureCallback callback);
diff --git a/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl b/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl
new file mode 100644
index 000000000000..477ee958e1e8
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/ISipDelegate.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims.aidl;
+
+import android.telephony.ims.SipMessage;
+
+/**
+ * See {@link SipDelegate} and {@link SipDelegateConnection} for docs regarding this callback.
+ * {@hide}
+ */
+oneway interface ISipDelegate {
+ void sendMessage(in SipMessage sipMessage, int configVersion);
+ void notifyMessageReceived(in String viaTransactionId);
+ void notifyMessageReceiveError(in String viaTransactionId, int reason);
+
+ // only used by SipDelegate.
+ void closeDialog(in String callId);
+}
diff --git a/telephony/java/android/telephony/ims/aidl/ISipDelegateConnectionStateCallback.aidl b/telephony/java/android/telephony/ims/aidl/ISipDelegateConnectionStateCallback.aidl
new file mode 100644
index 000000000000..ddfcb9994cb8
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/ISipDelegateConnectionStateCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims.aidl;
+
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.aidl.ISipDelegate;
+
+/**
+ * See {@link SipDelegateConnectionStateCallback} for docs regarding this callback.
+ * {@hide}
+ */
+oneway interface ISipDelegateConnectionStateCallback {
+ void onCreated(ISipDelegate c);
+ void onFeatureTagStatusChanged(in DelegateRegistrationState registrationState,
+ in List<FeatureTagState> deniedFeatureTags);
+ void onImsConfigurationChanged(in SipDelegateImsConfiguration registeredSipConfig);
+ void onDestroyed(int reason);
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java b/telephony/java/android/telephony/ims/aidl/ISipDelegateMessageCallback.aidl
index d84b2f958feb..30b7d6c70647 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java
+++ b/telephony/java/android/telephony/ims/aidl/ISipDelegateMessageCallback.aidl
@@ -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,20 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui;
+package android.telephony.ims.aidl;
-import com.android.systemui.dagger.DefaultActivityBinder;
-import com.android.systemui.dagger.DefaultBroadcastReceiverBinder;
-import com.android.systemui.dagger.DefaultServiceBinder;
-
-import dagger.Module;
+import android.telephony.ims.SipMessage;
/**
- * Supply Activities, Services, and SystemUI Objects for CarSystemUI.
+ * See {@link DelegateMessageCallback} and {@link DelegateConnectionMessageCallback} for docs
+ * regarding this callback.
+ * {@hide}
*/
-@Module(includes = {
- DefaultActivityBinder.class,
- DefaultBroadcastReceiverBinder.class,
- DefaultServiceBinder.class})
-public class CarComponentBinder {
+oneway interface ISipDelegateMessageCallback {
+ void onMessageReceived(in SipMessage message);
+ void onMessageSent(in String viaTransactionId);
+ void onMessageSendFailure(in String viaTransactionId, int reason);
}
diff --git a/telephony/java/android/telephony/ims/aidl/ISipDelegateStateCallback.aidl b/telephony/java/android/telephony/ims/aidl/ISipDelegateStateCallback.aidl
new file mode 100644
index 000000000000..609ee260cbab
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/ISipDelegateStateCallback.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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.telephony.ims.aidl;
+
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.aidl.ISipDelegate;
+
+/**
+ * See {@link SipDelegateStateCallback} for docs regarding this callback.
+ * {@hide}
+ */
+oneway interface ISipDelegateStateCallback {
+ void onCreated(ISipDelegate c, in List<FeatureTagState> deniedFeatureTags);
+ void onFeatureTagRegistrationChanged(in DelegateRegistrationState registrationState);
+ void onImsConfigurationChanged(in SipDelegateImsConfiguration registeredSipConfig);
+ void onDestroyed(int reason);
+}
diff --git a/telephony/java/android/telephony/ims/aidl/ISipTransport.aidl b/telephony/java/android/telephony/ims/aidl/ISipTransport.aidl
index fe233430ffad..cd888391c584 100644
--- a/telephony/java/android/telephony/ims/aidl/ISipTransport.aidl
+++ b/telephony/java/android/telephony/ims/aidl/ISipTransport.aidl
@@ -16,9 +16,17 @@
package android.telephony.ims.aidl;
+import android.telephony.ims.DelegateRequest;
+import android.telephony.ims.aidl.ISipDelegate;
+import android.telephony.ims.aidl.ISipDelegateMessageCallback;
+import android.telephony.ims.aidl.ISipDelegateStateCallback;
+
/**
* Interface for commands to the SIP Transport implementation.
* {@hide}
*/
-interface ISipTransport {
+oneway interface ISipTransport {
+ void createSipDelegate(in DelegateRequest request, ISipDelegateStateCallback dc,
+ ISipDelegateMessageCallback mc);
+ void destroySipDelegate(ISipDelegate delegate, int reason);
}
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
new file mode 100644
index 000000000000..a7f62cc32be1
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -0,0 +1,192 @@
+/*
+ * 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.telephony.ims.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.telephony.ims.DelegateMessageCallback;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.DelegateStateCallback;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.telephony.ims.stub.SipDelegate;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Implementation of callbacks by wrapping the internal AIDL from telephony. Also implements
+ * ISipDelegate internally when {@link DelegateStateCallback#onCreated(SipDelegate, List)} is called
+ * in order to trampoline events back to telephony.
+ * @hide
+ */
+public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMessageCallback {
+
+ private final ISipDelegate.Stub mDelegateBinder = new ISipDelegate.Stub() {
+ @Override
+ public void sendMessage(SipMessage sipMessage, int configVersion) {
+ SipDelegate d = mDelegate;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> d.sendMessage(sipMessage, configVersion));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void notifyMessageReceived(String viaTransactionId) {
+ SipDelegate d = mDelegate;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> d.notifyMessageReceived(viaTransactionId));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ }
+
+ @Override
+ public void notifyMessageReceiveError(String viaTransactionId, int reason) {
+ SipDelegate d = mDelegate;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> d.notifyMessageReceiveError(viaTransactionId, reason));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ }
+
+ @Override
+ public void closeDialog(String callId) {
+ SipDelegate d = mDelegate;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> d.closeDialog(callId));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ };
+
+ private final ISipDelegateMessageCallback mMessageBinder;
+ private final ISipDelegateStateCallback mStateBinder;
+ private final Executor mExecutor;
+
+ private volatile SipDelegate mDelegate;
+
+ public SipDelegateAidlWrapper(Executor executor, ISipDelegateStateCallback stateBinder,
+ ISipDelegateMessageCallback messageBinder) {
+ mExecutor = executor;
+ mStateBinder = stateBinder;
+ mMessageBinder = messageBinder;
+ }
+
+ @Override
+ public void onMessageReceived(SipMessage message) {
+ try {
+ mMessageBinder.onMessageReceived(message);
+ } catch (RemoteException e) {
+ // BinderDied will be called on SipTransport instance to trigger destruction. Notify
+ // failure message failure locally for now.
+ SipDelegate d = mDelegate;
+ if (d != null) {
+ notifyLocalMessageFailedToBeReceived(message,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
+ }
+ }
+ }
+
+ @Override
+ public void onMessageSent(String viaTransactionId) {
+ try {
+ mMessageBinder.onMessageSent(viaTransactionId);
+ } catch (RemoteException e) {
+ // BinderDied will trigger destroySipDelegate, so just ignore this locally.
+ }
+ }
+
+ @Override
+ public void onMessageSendFailure(String viaTransactionId, int reason) {
+ try {
+ mMessageBinder.onMessageSendFailure(viaTransactionId, reason);
+ } catch (RemoteException e) {
+ // BinderDied will trigger destroySipDelegate, so just ignore this locally.
+ }
+ }
+
+ @Override
+ public void onCreated(@NonNull SipDelegate delegate,
+ @Nullable List<FeatureTagState> deniedTags) {
+ mDelegate = delegate;
+ try {
+ mStateBinder.onCreated(mDelegateBinder, deniedTags);
+ } catch (RemoteException e) {
+ // BinderDied will trigger destroySipDelegate, so just ignore this locally.
+ }
+ }
+
+ @Override
+ public void onFeatureTagRegistrationChanged(DelegateRegistrationState registrationState) {
+ try {
+ mStateBinder.onFeatureTagRegistrationChanged(registrationState);
+ } catch (RemoteException e) {
+ // BinderDied will trigger destroySipDelegate, so just ignore this locally.
+ }
+ }
+
+ @Override
+ public void onImsConfigurationChanged(@NonNull SipDelegateImsConfiguration config) {
+ try {
+ mStateBinder.onImsConfigurationChanged(config);
+ } catch (RemoteException e) {
+ // BinderDied will trigger destroySipDelegate, so just ignore this locally.
+ }
+ }
+
+ @Override
+ public void onDestroyed(int reasonCode) {
+ mDelegate = null;
+ try {
+ mStateBinder.onDestroyed(reasonCode);
+ } catch (RemoteException e) {
+ // Do not worry about this if the remote side is already dead.
+ }
+ }
+
+ public SipDelegate getDelegate() {
+ return mDelegate;
+ }
+
+ public ISipDelegate getDelegateBinder() {
+ return mDelegateBinder;
+ }
+
+ private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
+ //TODO: parse transaction ID or throw IllegalArgumentException if the SipMessage
+ // transaction ID can not be parsed.
+ SipDelegate d = mDelegate;
+ if (d != null) {
+ mExecutor.execute(() -> d.notifyMessageReceiveError(null, reason));
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
new file mode 100644
index 000000000000..3bd1a462b31a
--- /dev/null
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
@@ -0,0 +1,260 @@
+/*
+ * 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.telephony.ims.aidl;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateConnection;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+import android.telephony.ims.stub.DelegateConnectionMessageCallback;
+import android.telephony.ims.stub.DelegateConnectionStateCallback;
+import android.telephony.ims.stub.SipDelegate;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Wrapper class implementing {@link SipDelegateConnection} using AIDL, which is returned to the
+ * local process. Also holds a reference to incoming connection message and state AIDL impl to
+ * trampoline events to callbacks as well as notify the local process in the event that the remote
+ * process becomes unavailable.
+ * <p>
+ * When the remote {@link SipDelegate} is created, this instance tracks the
+ * {@link ISipDelegate} associated with it and implements the
+ * {@link SipDelegateConnection} sent back to the local callback.
+ * @hide
+ */
+public class SipDelegateConnectionAidlWrapper implements SipDelegateConnection,
+ IBinder.DeathRecipient {
+ private static final String LOG_TAG = "SipDelegateCAW";
+
+ private final ISipDelegateConnectionStateCallback.Stub mStateBinder =
+ new ISipDelegateConnectionStateCallback.Stub() {
+ @Override
+ public void onCreated(ISipDelegate c) {
+ associateSipDelegate(c);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mStateCallback.onCreated(SipDelegateConnectionAidlWrapper.this));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onFeatureTagStatusChanged(DelegateRegistrationState registrationState,
+ List<FeatureTagState> deniedFeatureTags) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mStateCallback.onFeatureTagStatusChanged(registrationState,
+ new ArraySet<>(deniedFeatureTags)));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onImsConfigurationChanged(SipDelegateImsConfiguration registeredSipConfig) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mStateCallback.onImsConfigurationChanged(registeredSipConfig));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onDestroyed(int reason) {
+ invalidateSipDelegateBinder();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mStateCallback.onDestroyed(reason));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ };
+
+ private final ISipDelegateMessageCallback.Stub mMessageBinder =
+ new ISipDelegateMessageCallback.Stub() {
+ @Override
+ public void onMessageReceived(SipMessage message) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mMessageCallback.onMessageReceived(message));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onMessageSent(String viaTransactionId) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mMessageCallback.onMessageSent(viaTransactionId));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onMessageSendFailure(String viaTransactionId, int reason) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mMessageCallback.onMessageSendFailure(viaTransactionId, reason));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ };
+
+
+ private final Executor mExecutor;
+ private final DelegateConnectionStateCallback mStateCallback;
+ private final DelegateConnectionMessageCallback mMessageCallback;
+ private final AtomicReference<ISipDelegate> mDelegateBinder =
+ new AtomicReference<>();
+
+ /**
+ * Wrap the local state and message callbacks, calling the implementation of these interfaces
+ * when the remote process calls these methods.
+ */
+ public SipDelegateConnectionAidlWrapper(Executor executor,
+ DelegateConnectionStateCallback stateCallback,
+ DelegateConnectionMessageCallback messageCallback) {
+ mExecutor = executor;
+ mStateCallback = stateCallback;
+ mMessageCallback = messageCallback;
+ }
+
+ @Override
+ public void sendMessage(SipMessage sipMessage, int configVersion) {
+ try {
+ ISipDelegate conn = getSipDelegateBinder();
+ if (conn == null) {
+ notifyLocalMessageFailedToSend(sipMessage,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_CLOSED);
+ return;
+ }
+ conn.sendMessage(sipMessage, configVersion);
+ } catch (RemoteException e) {
+ notifyLocalMessageFailedToSend(sipMessage,
+ SipDelegateManager.MESSAGE_FAILURE_REASON_DELEGATE_DEAD);
+ }
+ }
+
+ @Override
+ public void notifyMessageReceived(String viaTransactionId) {
+ try {
+ ISipDelegate conn = getSipDelegateBinder();
+ if (conn == null) {
+ return;
+ }
+ conn.notifyMessageReceived(viaTransactionId);
+ } catch (RemoteException e) {
+ // Nothing to do here, app will eventually get remote death callback.
+ }
+ }
+
+ @Override
+ public void notifyMessageReceiveError(String viaTransactionId, int reason) {
+ try {
+ ISipDelegate conn = getSipDelegateBinder();
+ if (conn == null) {
+ return;
+ }
+ conn.notifyMessageReceiveError(viaTransactionId, reason);
+ } catch (RemoteException e) {
+ // Nothing to do here, app will eventually get remote death callback.
+ }
+ }
+
+ // Also called upon IImsRcsController death (telephony process dies).
+ @Override
+ public void binderDied() {
+ invalidateSipDelegateBinder();
+ mExecutor.execute(() -> mStateCallback.onDestroyed(
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD));
+ }
+
+ /**
+ * @return Implementation of state binder.
+ */
+ public ISipDelegateConnectionStateCallback getStateCallbackBinder() {
+ return mStateBinder;
+ }
+
+ /**
+ * @return Implementation of message binder.
+ */
+ public ISipDelegateMessageCallback getMessageCallbackBinder() {
+ return mMessageBinder;
+ }
+
+ /**
+ * @return The ISipDelegateConnection associated with this wrapper.
+ */
+ public ISipDelegate getSipDelegateBinder() {
+ return mDelegateBinder.get();
+ }
+
+ private void associateSipDelegate(ISipDelegate c) {
+ if (c != null) {
+ try {
+ c.asBinder().linkToDeath(this, 0 /*flags*/);
+ } catch (RemoteException e) {
+ // already dead.
+ c = null;
+ }
+ }
+ mDelegateBinder.set(c);
+ }
+
+ private void invalidateSipDelegateBinder() {
+ ISipDelegate oldVal = mDelegateBinder.getAndUpdate((unused) -> null);
+ if (oldVal != null) {
+ try {
+ oldVal.asBinder().unlinkToDeath(this, 0 /*flags*/);
+ } catch (NoSuchElementException e) {
+ Log.i(LOG_TAG, "invalidateSipDelegateBinder: " + e);
+ }
+ }
+ }
+
+ private void notifyLocalMessageFailedToSend(SipMessage m, int reason) {
+ //TODO: parse transaction ID or throw IllegalArgumentException if the SipMessage
+ // transaction ID can not be parsed.
+ mExecutor.execute(() ->
+ mMessageCallback.onMessageSendFailure(null, reason));
+ }
+}
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
index 4b8f39817f88..8dcd711a96a9 100755
--- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
@@ -30,11 +30,14 @@ import android.telephony.ims.ImsConferenceState;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsStreamMediaProfile;
import android.telephony.ims.ImsSuppServiceNotification;
+import android.telephony.ims.RtpHeaderExtension;
import android.telephony.ims.aidl.IImsCallSessionListener;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsVideoCallProvider;
+import java.util.List;
+
/**
* Compat implementation of ImsCallSessionImplBase for older implementations.
*
@@ -405,6 +408,15 @@ public class ImsCallSessionImplBase extends IImsCallSession.Stub {
}
/**
+ * Device sends RTP header extensions.
+ * @param headerExtensions The header extensions to send.
+ */
+ @Override
+ public void sendRtpHeaderExtensions(@NonNull List<RtpHeaderExtension> headerExtensions) {
+ // no-op; not supported in compat layer.
+ }
+
+ /**
* There are two different ImsCallSessionListeners that need to reconciled here, we need to
* convert the "old" version of the com.android.ims.internal.IImsCallSessionListener to the
* "new" version of the Listener android.telephony.ims.ImsCallSessionListener when calling
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index b0a7b62c88ab..96ca0225040f 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -509,6 +509,7 @@ public abstract class ImsFeature {
* @return true if the capability is enabled, false otherwise.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract boolean queryCapabilityConfiguration(int capability, int radioTech);
/**
@@ -547,5 +548,6 @@ public abstract class ImsFeature {
* @return Binder instance that the framework will use to communicate with this feature.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
protected abstract IInterface getBinder();
}
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 508d1a79d27e..e8234178be9d 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -27,6 +27,8 @@ import android.telecom.TelecomManager;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsService;
+import android.telephony.ims.RtpHeaderExtensionType;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsMmTelFeature;
import android.telephony.ims.aidl.IImsMmTelListener;
@@ -37,6 +39,7 @@ import android.telephony.ims.stub.ImsMultiEndpointImplBase;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.telephony.ims.stub.ImsSmsImplBase;
import android.telephony.ims.stub.ImsUtImplBase;
+import android.util.ArraySet;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsEcbm;
@@ -45,6 +48,8 @@ import com.android.ims.internal.IImsUt;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.Set;
/**
* Base implementation for Voice and SMS (IR-92) and Video (IR-94) IMS support.
@@ -93,6 +98,18 @@ public class MmTelFeature extends ImsFeature {
}
@Override
+ public void changeOfferedRtpHeaderExtensionTypes(List<RtpHeaderExtensionType> types)
+ throws RemoteException {
+ synchronized (mLock) {
+ try {
+ MmTelFeature.this.changeOfferedRtpHeaderExtensionTypes(new ArraySet<>(types));
+ } catch (Exception e) {
+ throw new RemoteException(e.getMessage());
+ }
+ }
+ }
+
+ @Override
public IImsCallSession createCallSession(ImsCallProfile profile) throws RemoteException {
synchronized (mLock) {
return createCallSessionInterface(profile);
@@ -623,6 +640,24 @@ public class MmTelFeature extends ImsFeature {
}
/**
+ * Called by the framework to report a change to the RTP header extension types which should be
+ * offered during SDP negotiation (see RFC8285 for more information).
+ * <p>
+ * The {@link ImsService} should report the RTP header extensions which were accepted during
+ * SDP negotiation using {@link ImsCallProfile#setAcceptedRtpHeaderExtensionTypes(Set)}.
+ *
+ * @param extensionTypes The RTP header extensions the framework wishes to offer during
+ * outgoing and incoming call setup. An empty list indicates that there
+ * are no framework defined RTP header extension types to offer.
+ * @hide
+ */
+ @SystemApi
+ public void changeOfferedRtpHeaderExtensionTypes(
+ @NonNull Set<RtpHeaderExtensionType> extensionTypes) {
+ // Base implementation - should be overridden if RTP header extension handling is supported.
+ }
+
+ /**
* @hide
*/
public IImsCallSession createCallSessionInterface(ImsCallProfile profile)
diff --git a/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java b/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java
new file mode 100644
index 000000000000..59f9601299b2
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/DelegateConnectionMessageCallback.java
@@ -0,0 +1,54 @@
+/*
+ * 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.telephony.ims.stub;
+
+import android.annotation.NonNull;
+import android.telephony.ims.SipDelegateConnection;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+
+/**
+ * The callback associated with a {@link SipDelegateConnection}, which handles newly received
+ * messages as well as the result of sending a SIP message.
+ * @hide
+ */
+public interface DelegateConnectionMessageCallback {
+
+ /**
+ * A new {@link SipMessage} has been received from the delegate.
+ * @param message the {@link SipMessage} routed to this RCS application.
+ */
+ void onMessageReceived(@NonNull SipMessage message);
+
+ /**
+ * A message previously sent to the SIP delegate using
+ * {@link SipDelegateConnection#sendMessage} has been successfully sent.
+ * @param viaTransactionId The transaction ID found in the via header field of the
+ * previously sent {@link SipMessage}.
+ */
+ void onMessageSent(@NonNull String viaTransactionId);
+
+ /**
+ * A message previously sent to the SIP delegate using
+ * {@link SipDelegateConnection#sendMessage} has failed to be sent.
+ * @param viaTransactionId The Transaction ID found in the via header field of the
+ * previously sent {@link SipMessage}.
+ * @param reason The reason for the failure.
+ */
+ void onMessageSendFailure(String viaTransactionId,
+ @SipDelegateManager.MessageFailureReason int reason);
+}
diff --git a/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
new file mode 100644
index 000000000000..976180538b18
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
@@ -0,0 +1,147 @@
+/*
+ * 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.telephony.ims.stub;
+
+import android.annotation.NonNull;
+import android.telephony.ims.DelegateRegistrationState;
+import android.telephony.ims.DelegateRequest;
+import android.telephony.ims.FeatureTagState;
+import android.telephony.ims.SipDelegateConnection;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateManager;
+
+import java.util.Set;
+
+/**
+ * The callback associated with a {@link SipDelegateConnection} that manages the state of the
+ * SipDelegateConnection.
+ * <p>
+ * After {@link SipDelegateManager#createSipDelegate} is used to request a new
+ * {@link SipDelegateConnection} be created, {@link #onCreated} will be called with the
+ * {@link SipDelegateConnection} instance that must be used to communicate with the remote
+ * {@link SipDelegate}.
+ * <p>
+ * After, {@link #onFeatureTagStatusChanged} will always be called at least once with the current
+ * status of the feature tags that have been requested. The application may receive multiple
+ * {@link #onFeatureTagStatusChanged} callbacks over the lifetime of the associated
+ * {@link SipDelegateConnection}, which will signal changes to how SIP messages associated with
+ * those feature tags will be handled.
+ * <p>
+ * In order to start sending SIP messages, the SIP configuration parameters will need to be
+ * received, so the messaging application should make no assumptions about these parameters and wait
+ * until {@link #onImsConfigurationChanged(SipDelegateImsConfiguration)} has been called. This is
+ * guaranteed to happen after the first {@link #onFeatureTagStatusChanged} if there is at least one
+ * feature tag that has been successfully associated with the {@link SipDelegateConnection}. If all
+ * feature tags were denied, no IMS configuration will be sent.
+ * <p>
+ * The {@link SipDelegateConnection} will stay associated with this RCS application until either the
+ * RCS application calls {@link SipDelegateManager#destroySipDelegate} or telephony destroys the
+ * {@link SipDelegateConnection}. In both cases, {@link #onDestroyed(int)} will be called.
+ * Telephony destroying the {@link SipDelegateConnection} instance is rare and will only happen in
+ * rare cases, such as if telephony itself or IMS service dies unexpectedly. See
+ * {@link SipDelegateManager.SipDelegateDestroyReason} reasons for more information on all of the
+ * cases that will trigger the {@link SipDelegateConnection} to be destroyed.
+ *
+ * @hide
+ */
+public interface DelegateConnectionStateCallback {
+
+ /**
+ * A {@link SipDelegateConnection} has been successfully created for the
+ * {@link DelegateRequest} used when calling {@link SipDelegateManager#createSipDelegate}.
+ */
+ void onCreated(@NonNull SipDelegateConnection c);
+
+ /**
+ * The status of the RCS feature tags that were requested as part of the initial
+ * {@link DelegateRequest}.
+ * <p>
+ * There are four states that each RCS feature tag can be in: registered, deregistering,
+ * deregistered, and denied.
+ * <p>
+ * When a feature tag is considered registered, SIP messages associated with that feature tag
+ * may be sent and received freely.
+ * <p>
+ * When a feature tag is deregistering, the network IMS registration still contains the feature
+ * tag, however the IMS service and associated {@link SipDelegate} is in the progress of
+ * modifying the IMS registration to remove this feature tag and requires the application to
+ * perform an action before the IMS registration can change. The specific action required for
+ * the SipDelegate to continue modifying the IMS registration can be found in the definition of
+ * each {@link DelegateRegistrationState.DeregisteringReason}.
+ * <p>
+ * When a feature tag is in the deregistered state, new out-of-dialog SIP messages for that
+ * feature tag will be rejected, however due to network race conditions, the RCS application
+ * should still be able to handle new out-of-dialog SIP requests from the network. This may not
+ * be possible, however, if the IMS registration itself was lost. See the
+ * {@link DelegateRegistrationState.DeregisteredReason} reasons for more information on how SIP
+ * messages are handled in each of these cases.
+ * <p>
+ * If a feature tag is denied, no incoming messages will be routed to the associated
+ * {@link DelegateConnectionMessageCallback} and all outgoing SIP messages related to this
+ * feature tag will be rejected. See {@link SipDelegateManager.DeniedReason}
+ * reasons for more information about the conditions when this will happen.
+ * <p>
+ * The set of feature tags contained in the registered, deregistering, deregistered, and denied
+ * lists will always equal the set of feature tags requested in the initial
+ * {@link DelegateRequest}.
+ * <p>
+ * Transitions of feature tags from registered, deregistering, and deregistered and vice-versa
+ * may happen quite often, however transitions to/from denied are rare and only occur if the
+ * user has changed the role of your application to add/remove support for one or more requested
+ * feature tags or carrier provisioning has enabled or disabled single registration entirely.
+ * Please see {@link SipDelegateManager.DeniedReason} reasons for an explanation of each of
+ * these cases as well as what may cause them to change.
+ *
+ * @param registrationState The new IMS registration state of each of the feature tags
+ * associated with the {@link SipDelegate}.
+ * @param deniedFeatureTags A list of {@link FeatureTagState} objects, each containing a feature
+ * tag associated with this {@link SipDelegateConnection} that has no access to
+ * send/receive SIP messages as well as a reason for why the feature tag is denied. For more
+ * information on the reason why the feature tag was denied access, see the
+ * {@link SipDelegateManager.DeniedReason} reasons.
+ */
+ void onFeatureTagStatusChanged(@NonNull DelegateRegistrationState registrationState,
+ @NonNull Set<FeatureTagState> deniedFeatureTags);
+
+
+ /**
+ * IMS configuration of the underlying IMS stack used by this IMS application for construction
+ * of the SIP messages that will be sent over the carrier's network.
+ * <p>
+ * There should never be assumptions made about the configuration of the underling IMS stack and
+ * the IMS application should wait for this indication before sending out any outgoing SIP
+ * messages.
+ * <p>
+ * Configuration may change due to IMS registration changes as well as
+ * other optional events on the carrier network. If IMS stack is already registered at the time
+ * of callback registration, then this method shall be invoked with the current configuration.
+ * Otherwise, there may be a delay in this method being called if initial IMS registration has
+ * not compleed yet.
+ *
+ * @param registeredSipConfig The configuration of the IMS stack registered on the IMS network.
+ */
+ void onImsConfigurationChanged(@NonNull SipDelegateImsConfiguration registeredSipConfig);
+
+ /**
+ * The previously created {@link SipDelegateConnection} instance delivered via
+ * {@link #onCreated(SipDelegateConnection)} has been destroyed. This interface should no longer
+ * be used for any SIP message handling.
+ *
+ * @param reason The reason for the failure.
+ */
+ void onDestroyed(@SipDelegateManager.SipDelegateDestroyReason int reason);
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index 1cebdd582b58..a3a6cb864fa5 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -26,10 +26,17 @@ import android.telephony.ims.ImsCallSessionListener;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsStreamMediaProfile;
import android.telephony.ims.ImsVideoCallProvider;
+import android.telephony.ims.RtpHeaderExtension;
+import android.telephony.ims.RtpHeaderExtensionType;
import android.telephony.ims.aidl.IImsCallSessionListener;
+import android.util.ArraySet;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsVideoCallProvider;
+
+import java.util.List;
+import java.util.Set;
+
/**
* Base implementation of IImsCallSession, which implements stub versions of the methods available.
*
@@ -277,6 +284,12 @@ public class ImsCallSessionImplBase implements AutoCloseable {
public void sendRttMessage(String rttMessage) {
ImsCallSessionImplBase.this.sendRttMessage(rttMessage);
}
+
+ @Override
+ public void sendRtpHeaderExtensions(@NonNull List<RtpHeaderExtension> extensions) {
+ ImsCallSessionImplBase.this.sendRtpHeaderExtensions(
+ new ArraySet<RtpHeaderExtension>(extensions));
+ }
};
/**
@@ -636,6 +649,22 @@ public class ImsCallSessionImplBase implements AutoCloseable {
public void sendRttMessage(String rttMessage) {
}
+ /**
+ * Device requests that {@code rtpHeaderExtensions} are sent as a header extension with the next
+ * RTP packet sent by the IMS stack.
+ * <p>
+ * The {@link RtpHeaderExtensionType}s negotiated during SDP (Session Description Protocol)
+ * signalling determine the {@link RtpHeaderExtension}s which can be sent using this method.
+ * See RFC8285 for more information.
+ * <p>
+ * By specification, the RTP header extension is an unacknowledged transmission and there is no
+ * guarantee that the header extension will be delivered by the network to the other end of the
+ * call.
+ * @param rtpHeaderExtensions The RTP header extensions to be included in the next RTP header.
+ */
+ public void sendRtpHeaderExtensions(@NonNull Set<RtpHeaderExtension> rtpHeaderExtensions) {
+ }
+
/** @hide */
public IImsCallSession getServiceImpl() {
return mServiceImpl;
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 12abdd1d7e11..a6f5c45445f5 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -17,6 +17,8 @@
package android.telephony.ims.stub;
import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.Uri;
import android.os.RemoteException;
@@ -126,6 +128,57 @@ public class ImsRegistrationImplBase {
}
/**
+ * Called by the framework to request that the ImsService perform the network registration
+ * of all SIP delegates associated with this ImsService.
+ * <p>
+ * If the SIP delegate feature tag configuration has changed, then this method will be
+ * called in order to let the ImsService know that it can pick up these changes in the IMS
+ * registration.
+ * @hide
+ */
+ public void updateSipDelegateRegistration() {
+ // Stub implementation, ImsService should implement this
+ }
+
+
+ /**
+ * Called by the framework to request that the ImsService perform the network deregistration of
+ * all SIP delegates associated with this ImsService.
+ * <p>
+ * This is typically called in situations where the user has changed the configuration of the
+ * device (for example, the default messaging application) and the framework is reconfiguring
+ * the tags associated with each IMS application.
+ * <p>
+ * This should not affect the registration of features managed by the ImsService itself, such as
+ * feature tags related to MMTEL registration.
+ * @hide
+ */
+ public void triggerSipDelegateDeregistration() {
+ // Stub implementation, ImsService should implement this
+ }
+
+ /**
+ * Called by the framework to notify the ImsService that a SIP delegate connection has received
+ * a SIP message containing a permanent failure response (such as a 403) or an indication that a
+ * SIP response timer has timed out in response to an outgoing SIP message. This method will be
+ * called when this condition occurs to trigger the ImsService to tear down the full IMS
+ * registration and re-register again.
+ *
+ * @param sipCode The SIP error code that represents a permanent failure that was received in
+ * response to a request generated by the IMS application. See RFC3261 7.2 for the general
+ * classes of responses available here, however the codes that generate this condition may
+ * be carrier specific.
+ * @param sipReason The reason associated with the SIP error code. {@code null} if there was no
+ * reason associated with the error.
+ * @hide
+ */
+ public void triggerNetworkReregistration(@IntRange(from = 100, to = 699) int sipCode,
+ @Nullable String sipReason) {
+ // Stub implementation, ImsService should implement this
+ }
+
+
+ /**
* Notify the framework that the device is connected to the IMS network.
*
* @param imsRadioTech the radio access technology. Valid values are defined as
diff --git a/telephony/java/android/telephony/ims/stub/SipDelegate.java b/telephony/java/android/telephony/ims/stub/SipDelegate.java
new file mode 100644
index 000000000000..3ec97095eb00
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/SipDelegate.java
@@ -0,0 +1,91 @@
+/*
+ * 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.telephony.ims.stub;
+
+import android.annotation.NonNull;
+import android.telephony.ims.DelegateMessageCallback;
+import android.telephony.ims.ImsService;
+import android.telephony.ims.SipDelegateImsConfiguration;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.SipMessage;
+
+/**
+ * The {@link SipDelegate} is implemented by the {@link ImsService} and allows a privileged
+ * IMS application to use this delegate to send SIP messages as well as acknowledge the receipt of
+ * incoming SIP messages delivered to the application over the existing IMS registration, allowing
+ * for a single IMS registration for multiple IMS applications.
+ * <p>
+ * Once the SIP delegate is created for that application,
+ * {@link ImsRegistrationImplBase#updateSipDelegateRegistration()} will be called, indicating that
+ * the application is finished setting up SipDelegates and the existing IMS registration may be
+ * modified to include the features managed by these SipDelegates.
+ * <p>
+ * This SipDelegate will need to notify the remote application of the registration of these features
+ * as well as the associated {@link SipDelegateImsConfiguration} before the application can start
+ * sending/receiving SIP messages via the transport. See
+ * {@link android.telephony.ims.DelegateStateCallback} for more information.
+ * @hide
+ */
+public interface SipDelegate {
+
+ /**
+ * The framework calls this method when a remote RCS application wishes to send a new outgoing
+ * SIP message.
+ * <p>
+ * Once sent, this SIP delegate should notify the remote application of the success or
+ * failure using {@link DelegateMessageCallback#onMessageSent(String)} or
+ * {@link DelegateMessageCallback#onMessageSendFailure(String, int)}.
+ * @param message The SIP message to be sent over the operator’s network.
+ * @param configVersion The SipDelegateImsConfiguration version used to construct the
+ * SipMessage. See {@link SipDelegateImsConfiguration} for more information. If the
+ * version specified here does not match the most recently constructed
+ * {@link SipDelegateImsConfiguration}, this message should fail validation checks and
+ * {@link DelegateMessageCallback#onMessageSendFailure} should be called with code
+ * {@link SipDelegateManager#MESSAGE_FAILURE_REASON_STALE_IMS_CONFIGURATION}.
+ */
+ void sendMessage(@NonNull SipMessage message, int configVersion);
+
+ /**
+ * The framework is requesting that routing resources associated with the SIP dialog using the
+ * provided Call-ID to be cleaned up.
+ * <p>
+ * Typically a SIP Dialog close event will be signalled by that dialog receiving a BYE or 200 OK
+ * message, however, in some cases, the framework will request that the ImsService close the
+ * dialog due to the open dialog holding up an event such as applying a provisioning change or
+ * handing over to another transport type.
+ * @param callId The call-ID header value associated with the ongoing SIP Dialog that the
+ * framework is requesting be closed.
+ */
+ void closeDialog(@NonNull String callId);
+
+ /**
+ * The remote application has received the SIP message and is processing it.
+ * @param viaTransactionId The Transaction ID found in the via header field of the
+ * previously sent {@link SipMessage}.
+ */
+ void notifyMessageReceived(@NonNull String viaTransactionId);
+
+ /**
+ * The remote application has either not received the SIP message or there was an error
+ * processing it.
+ * @param viaTransactionId The Transaction ID found in the via header field of the
+ * previously sent {@link SipMessage}.
+ * @param reason The reason why the message was not correctly received.
+ */
+ void notifyMessageReceiveError(@NonNull String viaTransactionId,
+ @SipDelegateManager.MessageFailureReason int reason);
+}
diff --git a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
index b2b2914b3739..b48f6317e413 100644
--- a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
@@ -18,27 +18,75 @@ package android.telephony.ims.stub;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.os.Binder;
+import android.os.IBinder;
+import android.telephony.ims.DelegateMessageCallback;
+import android.telephony.ims.DelegateRequest;
+import android.telephony.ims.DelegateStateCallback;
+import android.telephony.ims.SipDelegateManager;
+import android.telephony.ims.aidl.ISipDelegate;
+import android.telephony.ims.aidl.ISipDelegateMessageCallback;
+import android.telephony.ims.aidl.ISipDelegateStateCallback;
import android.telephony.ims.aidl.ISipTransport;
+import android.telephony.ims.aidl.SipDelegateAidlWrapper;
+import android.util.Log;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
- * Manages the creation and destruction of SipDelegates in order to proxy SIP traffic to other
- * IMS applications in order to support IMS single registration.
+ * The ImsService implements this class to manage the creation and destruction of
+ * {@link SipDelegate}s.
+ *
+ * {@link SipDelegate}s allow the ImsService to forward SIP traffic generated and consumed by IMS
+ * applications as a delegate to the associated carrier's IMS Network in order to support using a
+ * single IMS registration for all MMTEL and RCS signalling traffic.
* @hide
*/
@SystemApi
public class SipTransportImplBase {
+ private static final String LOG_TAG = "SipTransportIB";
- private final Executor mBinderExecutor;
- private final ISipTransport mSipTransportImpl = new ISipTransport.Stub() {
+ private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ mBinderExecutor.execute(() -> binderDiedInternal());
+ }
+ };
+ private final ISipTransport.Stub mSipTransportImpl = new ISipTransport.Stub() {
+ @Override
+ public void createSipDelegate(DelegateRequest request, ISipDelegateStateCallback dc,
+ ISipDelegateMessageCallback mc) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mBinderExecutor.execute(() -> createSipDelegateInternal(request, dc, mc));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void destroySipDelegate(ISipDelegate delegate, int reason) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mBinderExecutor.execute(() -> destroySipDelegateInternal(delegate, reason));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
};
+ private final Executor mBinderExecutor;
+ private final ArrayList<SipDelegateAidlWrapper> mDelegates = new ArrayList<>();
+
/**
* Create an implementation of SipTransportImplBase.
*
- * @param executor The executor that remote calls from the framework should be called on.
+ * @param executor The executor that remote calls from the framework will be called on. This
+ * includes the methods here as well as the methods in {@link SipDelegate}.
*/
public SipTransportImplBase(@NonNull Executor executor) {
if (executor == null) {
@@ -49,6 +97,79 @@ public class SipTransportImplBase {
}
/**
+ * Called by the Telephony framework to request the creation of a new {@link SipDelegate}.
+ * <p>
+ * The implementation must call {@link DelegateStateCallback#onCreated(SipDelegate, List)} with
+ * the {@link SipDelegate} that is associated with the {@link DelegateRequest}.
+ * <p>
+ * This method will be called on the Executor specified in
+ * {@link SipTransportImplBase#SipTransportImplBase(Executor)}.
+ *
+ * @param request A SIP delegate request containing the parameters that the remote RCS
+ * application wishes to use.
+ * @param dc A callback back to the remote application to be used to communicate state callbacks
+ * for the SipDelegate.
+ * @param mc A callback back to the remote application to be used to send SIP messages to the
+ * remote application and acknowledge the sending of outgoing SIP messages.
+ * @hide
+ */
+ public void createSipDelegate(@NonNull DelegateRequest request,
+ @NonNull DelegateStateCallback dc, @NonNull DelegateMessageCallback mc) {
+ throw new UnsupportedOperationException("destroySipDelegate not implemented!");
+ }
+
+ /**
+ * Destroys the SipDelegate associated with a remote IMS application.
+ * <p>
+ * After the delegate is destroyed, {@link DelegateStateCallback#onDestroyed(int)} must be
+ * called to notify listeners of its destruction to release associated resources.
+ * <p>
+ * This method will be called on the Executor specified in
+ * {@link SipTransportImplBase#SipTransportImplBase(Executor)}.
+ * @param delegate The delegate to be destroyed.
+ * @param reason The reason the remote connection to this {@link SipDelegate} is being
+ * destroyed.
+ * @hide
+ */
+ public void destroySipDelegate(@NonNull SipDelegate delegate,
+ @SipDelegateManager.SipDelegateDestroyReason int reason) {
+ throw new UnsupportedOperationException("destroySipDelegate not implemented!");
+ }
+
+ private void createSipDelegateInternal(DelegateRequest r, ISipDelegateStateCallback cb,
+ ISipDelegateMessageCallback mc) {
+ SipDelegateAidlWrapper wrapper = new SipDelegateAidlWrapper(mBinderExecutor, cb, mc);
+ mDelegates.add(wrapper);
+ createSipDelegate(r, wrapper, wrapper);
+ }
+
+ private void destroySipDelegateInternal(ISipDelegate d, int reason) {
+ SipDelegateAidlWrapper result = null;
+ for (SipDelegateAidlWrapper w : mDelegates) {
+ if (Objects.equals(d, w.getDelegateBinder())) {
+ result = w;
+ break;
+ }
+ }
+
+ if (result != null) {
+ mDelegates.remove(result);
+ destroySipDelegate(result.getDelegate(), reason);
+ } else {
+ Log.w(LOG_TAG, "destroySipDelegateInternal, could not findSipDelegate corresponding to "
+ + d);
+ }
+ }
+
+ private void binderDiedInternal() {
+ for (SipDelegateAidlWrapper w : mDelegates) {
+ destroySipDelegate(w.getDelegate(),
+ SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+ }
+ mDelegates.clear();
+ }
+
+ /**
* @return The IInterface used by the framework.
* @hide
*/
diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
index ab14e82b7087..e3a8aeed7ad5 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
@@ -20,6 +20,8 @@ import android.os.Message;
import android.telephony.ims.aidl.IImsCallSessionListener;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsStreamMediaProfile;
+import android.telephony.ims.RtpHeaderExtension;
+
import com.android.ims.internal.IImsVideoCallProvider;
/**
@@ -297,4 +299,10 @@ interface IImsCallSession {
* @param rttMessage RTT message to be sent
*/
void sendRttMessage(in String rttMessage);
+
+ /*
+ * Device sends RTP header extension(s).
+ * @param extensions the header extensions to be sent
+ */
+ void sendRtpHeaderExtensions(in List<RtpHeaderExtension> extensions);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index a38d5b6f2141..0bd485139331 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -31,6 +31,7 @@ import android.service.carrier.CarrierIdentifier;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telephony.CallForwardingInfo;
+import android.telephony.CarrierBandwidth;
import android.telephony.CarrierRestrictionRules;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
@@ -1798,6 +1799,14 @@ interface ITelephony {
boolean setCdmaRoamingMode(int subId, int mode);
/**
+ * Gets the subscription mode for the CDMA phone with the subscription id {@code subId}.
+ *
+ * @param the subscription id.
+ * @return the subscription mode for CDMA phone.
+ */
+ int getCdmaSubscriptionMode(int subId);
+
+ /**
* Sets the subscription mode for CDMA phone with the subscription {@code subId} to the given
* subscription mode {@code mode}.
*
@@ -2232,4 +2241,10 @@ interface ITelephony {
* @return true if dual connectivity is enabled else false
*/
boolean isNrDualConnectivityEnabled(int subId);
+
+ /**
+ * Get carrier bandwidth per primary and secondary carrier
+ * @return CarrierBandwidth with bandwidth of both primary and secondary carrier.
+ */
+ CarrierBandwidth getCarrierBandwidth(int subId);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index d3c27dc4f255..91607462c29f 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -576,6 +576,7 @@ public interface RILConstants {
int RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION = 1048;
int RIL_UNSOL_NETWORK_SCAN_RESULT = 1049;
int RIL_UNSOL_KEEPALIVE_STATUS = 1050;
+ int RIL_UNSOL_UNTHROTTLE_APN = 1052;
/* The following unsols are not defined in RIL.h */
int RIL_UNSOL_HAL_NON_RIL_BASE = 1100;
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
index 1adbc2dc182c..f49d4fcab5f2 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.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -98,8 +98,8 @@ public class HierrarchicalDataClassBase implements Parcelable {
};
@DataClass.Generated(
- time = 1603836848866L,
- codegenVersion = "1.0.18",
+ time = 1604522375155L,
+ codegenVersion = "1.0.20",
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 a4fdcd18aa3d..e8cce23fa324 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.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -120,8 +120,8 @@ public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
};
@DataClass.Generated(
- time = 1603836849753L,
- codegenVersion = "1.0.18",
+ time = 1604522376059L,
+ codegenVersion = "1.0.20",
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 f0d728e2f604..9de65522fccd 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.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -412,10 +412,10 @@ public class ParcelAllTheThingsDataClass implements Parcelable {
}
@DataClass.Generated(
- time = 1603836847927L,
- codegenVersion = "1.0.18",
+ time = 1604522374190L,
+ codegenVersion = "1.0.20",
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)")
+ 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 @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
private void __metadata() {}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index a3f458beebcc..5a3e273275ed 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -344,7 +344,7 @@ public final class SampleDataClass implements Parcelable {
- // Code below generated by codegen v1.0.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -1874,10 +1874,10 @@ public final class SampleDataClass implements Parcelable {
}
@DataClass.Generated(
- time = 1603836845952L,
- codegenVersion = "1.0.18",
+ time = 1604522372172L,
+ codegenVersion = "1.0.20",
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_ON\npublic static final int STATE_OFF\npublic static final int STATE_UNDEFINED\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)")
+ 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_ON\npublic static final int STATE_OFF\npublic static final int STATE_UNDEFINED\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 int mDayOfWeek\nprivate @android.annotation.Size @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange 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
private void __metadata() {}
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index e3567044d361..3ab34452f9fc 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.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -253,8 +253,8 @@ public class SampleWithCustomBuilder implements Parcelable {
}
@DataClass.Generated(
- time = 1603836846970L,
- codegenVersion = "1.0.18",
+ time = 1604522373190L,
+ codegenVersion = "1.0.20",
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]\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 []\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 07ec31ddc5e6..8901cac1cb1b 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.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -135,8 +135,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1603836851627L,
- codegenVersion = "1.0.18",
+ time = 1604522377998L,
+ codegenVersion = "1.0.20",
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.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -259,8 +259,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1603836851635L,
- codegenVersion = "1.0.18",
+ time = 1604522378007L,
+ codegenVersion = "1.0.20",
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.18.
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -373,8 +373,8 @@ public class SampleWithNestedDataClasses {
};
@DataClass.Generated(
- time = 1603836851640L,
- codegenVersion = "1.0.18",
+ time = 1604522378015L,
+ codegenVersion = "1.0.20",
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 5cbc6b30d1fc..ac776f3c2764 100644
--- a/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
+++ b/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java
@@ -15,8 +15,10 @@
*/
package com.android.codegentest;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.PackageManager;
import com.android.internal.util.DataClass;
@@ -57,9 +59,12 @@ public class StaleDataclassDetectorFalsePositivesTest {
/** Unrelated methods should be noted, without triggering staleness false positives */
public @NonNull String someMethod(int param) { return null; }
+ /** Inlined constants in annotation args should be fine */
+ private @IntRange(from = PackageManager.PERMISSION_GRANTED) void annotatedWithConstArg() {}
- // Code below generated by codegen v1.0.18.
+
+ // Code below generated by codegen v1.0.20.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -84,10 +89,10 @@ public class StaleDataclassDetectorFalsePositivesTest {
}
@DataClass.Generated(
- time = 1603836850677L,
- codegenVersion = "1.0.18",
+ time = 1604522377011L,
+ codegenVersion = "1.0.20",
sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/StaleDataclassDetectorFalsePositivesTest.java",
- inputSignatures = "private @android.annotation.Nullable java.util.List<java.util.Set<?>> mUsesWildcards\npublic @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)")
+ inputSignatures = "private @android.annotation.Nullable java.util.List<java.util.Set<?>> mUsesWildcards\npublic @android.annotation.NonNull java.lang.String someMethod(int)\nprivate @android.annotation.IntRange void annotatedWithConstArg()\nclass StaleDataclassDetectorFalsePositivesTest extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 6b974ff8eba3..a85e92c92093 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker
+import android.platform.helpers.IAppHelper
import com.android.server.wm.flicker.dsl.EventLogAssertion
import com.android.server.wm.flicker.dsl.LayersAssertion
import com.android.server.wm.flicker.dsl.WmAssertion
@@ -24,6 +25,7 @@ import com.android.server.wm.flicker.helpers.WindowUtils
const val NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar"
const val STATUS_BAR_WINDOW_TITLE = "StatusBar"
const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
+const val WALLPAPER_TITLE = "Wallpaper"
@JvmOverloads
fun WmAssertion.statusBarWindowIsAlwaysVisible(
@@ -45,6 +47,48 @@ fun WmAssertion.navBarWindowIsAlwaysVisible(
}
}
+fun WmAssertion.visibleWindowsShownMoreThanOneConsecutiveEntry(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("visibleWindowShownMoreThanOneConsecutiveEntry", bugId, enabled) {
+ this.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ }
+}
+
+fun WmAssertion.launcherReplacesAppWindowAsTopWindow(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("launcherReplacesAppWindowAsTopWindow", bugId, enabled) {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ .then()
+ .showsAppWindowOnTop("Launcher")
+ }
+}
+
+fun WmAssertion.wallpaperWindowBecomesVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("wallpaperWindowBecomesVisible", bugId, enabled) {
+ this.hidesBelowAppWindow(WALLPAPER_TITLE)
+ .then()
+ .showsBelowAppWindow(WALLPAPER_TITLE)
+ }
+}
+
+fun WmAssertion.windowAlwaysVisible(
+ packageName: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("windowAlwaysVisible", bugId, enabled) {
+ this.showsAppWindowOnTop(packageName)
+ }
+}
+
@JvmOverloads
fun LayersAssertion.noUncoveredRegions(
beginRotation: Int,
@@ -159,6 +203,37 @@ fun LayersAssertion.statusBarLayerRotatesScales(
}
}
+fun LayersAssertion.visibleLayersShownMoreThanOneConsecutiveEntry(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("visibleLayersShownMoreThanOneConsecutiveEntry", bugId, enabled) {
+ this.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+}
+
+fun LayersAssertion.wallpaperLayerReplacesAppLayer(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("appLayerReplacesWallpaperLayer", bugId, enabled) {
+ this.showsLayer(testApp.getPackage())
+ .then()
+ .replaceVisibleLayer(testApp.getPackage(), WALLPAPER_TITLE)
+ }
+}
+
+fun LayersAssertion.layerAlwaysVisible(
+ packageName: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("layerAlwaysVisible", bugId, enabled) {
+ this.showsLayer(packageName)
+ }
+}
+
fun EventLogAssertion.focusChanges(
vararg windows: String,
bugId: Int = 0,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
new file mode 100644
index 000000000000..a20f96d17278
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -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.server.wm.flicker.close
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.launcherReplacesAppWindowAsTopWindow
+import com.android.server.wm.flicker.wallpaperWindowBecomesVisible
+import com.android.server.wm.flicker.wallpaperLayerReplacesAppLayer
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.waitUntilGone
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test app closes by pressing back button
+ * To run this test: `atest FlickerTests:CloseAppBackButtonTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class CloseAppBackButtonTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ return FlickerTestRunnerFactory(instrumentation, repetitions = 10)
+ .buildTest { configuration ->
+ withTestName { buildTestTag("closeAppBackButton", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ this.setRotation(configuration.startRotation)
+ testApp.open()
+ }
+ }
+ transitions {
+ device.pressBack()
+ device.waitUntilGone(testApp.getPackage())
+ }
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ launcherReplacesAppWindowAsTopWindow(testApp)
+ wallpaperWindowBecomesVisible()
+ }
+
+ layersTrace {
+ noUncoveredRegions(configuration.startRotation,
+ Surface.ROTATION_0, bugId = 141361128)
+ navBarLayerRotatesAndScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ statusBarLayerRotatesScales(configuration.startRotation,
+ Surface.ROTATION_0)
+ navBarLayerIsAlwaysVisible(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
+ statusBarLayerIsAlwaysVisible(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
+ visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ wallpaperLayerReplacesAppLayer(testApp)
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
new file mode 100644
index 000000000000..b0a1565d9f54
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.close
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.helpers.waitUntilGone
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test app closes by pressing home button.
+ * To run this test: `atest FlickerTests:CloseAppHomeButtonTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class CloseAppHomeButtonTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ return FlickerTestRunnerFactory(instrumentation, repetitions = 10)
+ .buildTest { configuration ->
+ withTestName { buildTestTag("closeAppHomeButton", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ this.setRotation(configuration.startRotation)
+ testApp.open()
+ }
+ }
+ transitions {
+ device.pressHome()
+ device.waitUntilGone(testApp.getPackage())
+ }
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
index d31c4ba1f9f3..72efdb173d44 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -43,12 +43,12 @@ fun WmAssertion.appWindowReplacesLauncherAsTopWindow(
}
}
-fun LayersAssertion.wallpaperLayerBecomesInvisible(
+fun LayersAssertion.appLayerReplacesWallpaperLayer(
testApp: IAppHelper,
bugId: Int = 0,
enabled: Boolean = bugId == 0
) {
- all("wallpaperLayerBecomesInvisible", bugId, enabled) {
+ all("appLayerReplacesWallpaperLayer", bugId, enabled) {
this.showsLayer("Wallpaper")
.then()
.replaceVisibleLayer("Wallpaper", testApp.getPackage())
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index ad23d9f48568..1f03c4dc056d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -38,6 +38,8 @@ import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -87,6 +89,7 @@ class OpenAppColdTest(
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
appWindowReplacesLauncherAsTopWindow(testApp)
wallpaperWindowBecomesInvisible()
@@ -102,8 +105,10 @@ class OpenAppColdTest(
configuration.endRotation)
navBarLayerIsAlwaysVisible(enabled = false)
statusBarLayerIsAlwaysVisible(enabled = false)
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
- wallpaperLayerBecomesInvisible(testApp)
+ appLayerReplacesWallpaperLayer(testApp)
}
eventLog {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
new file mode 100644
index 000000000000..0c584f4973e8
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.hasWindow
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.repetitions
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Launch an app from the recents app view (the overview)
+ * To run this test: `atest FlickerTests:OpenAppFromOverviewTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenAppFromOverviewTest(
+ testName: String,
+ flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<Array<Any>> {
+ val instrumentation = InstrumentationRegistry.getInstrumentation()
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+ return FlickerTestRunnerFactory(instrumentation, repetitions = 10)
+ .buildTest { configuration ->
+ withTag { buildTestTag("openAppFromOverview", testApp, configuration) }
+ repeat { configuration.repetitions }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.open()
+ }
+ eachRun {
+ device.pressHome()
+ device.pressRecentApps()
+ this.setRotation(configuration.startRotation)
+ }
+ }
+ transitions {
+ device.reopenAppFromOverview()
+ device.hasWindow(testApp.getPackage())
+ }
+ teardown {
+ test {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ appWindowReplacesLauncherAsTopWindow(testApp)
+ wallpaperWindowBecomesInvisible()
+ }
+
+ layersTrace {
+ noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation,
+ bugId = 141361128)
+ navBarLayerRotatesAndScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0,
+ configuration.endRotation)
+ statusBarLayerIsAlwaysVisible(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
+ navBarLayerIsAlwaysVisible(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
+
+ appLayerReplacesWallpaperLayer(testApp)
+ }
+
+ eventLog {
+ focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 5886a61eed34..9b4223a0ea80 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -38,6 +38,8 @@ import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -91,9 +93,10 @@ class OpenAppWarmTest(
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
appWindowReplacesLauncherAsTopWindow(testApp)
- wallpaperWindowBecomesInvisible(enabled = false)
+ wallpaperWindowBecomesInvisible()
}
layersTrace {
@@ -106,8 +109,10 @@ class OpenAppWarmTest(
configuration.endRotation)
navBarLayerIsAlwaysVisible(enabled = false)
statusBarLayerIsAlwaysVisible(enabled = false)
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ enabled = Surface.ROTATION_0 == configuration.endRotation)
- wallpaperLayerBecomesInvisible(testApp)
+ appLayerReplacesWallpaperLayer(testApp)
}
eventLog {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 24ca31164ac9..0db064ab79c5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,8 +17,8 @@
package com.android.server.wm.flicker.rotation
import android.platform.test.annotations.Presubmit
-import androidx.test.filters.RequiresDevice
import android.view.Surface
+import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.Flicker
import com.android.server.wm.flicker.FlickerTestRunner
@@ -27,8 +27,8 @@ import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusDoesNotChange
import com.android.server.wm.flicker.helpers.StandardAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -36,6 +36,8 @@ import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
@@ -46,7 +48,7 @@ import org.junit.runners.Parameterized
/**
* Cycle through supported app rotations.
- * To run this test: `atest FlickerTest:ChangeAppRotationTest`
+ * To run this test: `atest FlickerTests:ChangeAppRotationTest`
*/
@Presubmit
@RequiresDevice
@@ -96,6 +98,7 @@ class ChangeAppRotationTest(
windowManagerTrace {
navBarWindowIsAlwaysVisible()
statusBarWindowIsAlwaysVisible()
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
}
layersTrace {
@@ -107,6 +110,7 @@ class ChangeAppRotationTest(
configuration.endRotation)
statusBarLayerRotatesScales(configuration.startRotation,
configuration.endRotation)
+ visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 140855415)
}
layersTrace {
@@ -128,7 +132,7 @@ class ChangeAppRotationTest(
.then()
.showsLayer(SCREENSHOT_LAYER)
.then()
- showsLayer(testApp.getPackage())
+ .showsLayer(testApp.getPackage())
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index d100383bc9f7..a1a7102f71e6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -30,6 +30,8 @@ import com.android.server.wm.flicker.FlickerTestRunner
import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusDoesNotChange
+import com.android.server.wm.flicker.windowAlwaysVisible
+import com.android.server.wm.flicker.layerAlwaysVisible
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.helpers.setRotation
@@ -39,6 +41,8 @@ import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
@@ -141,6 +145,8 @@ class SeamlessAppRotationTest(
windowManagerTrace {
navBarWindowIsAlwaysVisible(bugId = 140855415)
statusBarWindowIsAlwaysVisible(bugId = 140855415)
+ visibleWindowsShownMoreThanOneConsecutiveEntry()
+ windowAlwaysVisible(configuration.intentPackageName)
}
layersTrace {
@@ -152,6 +158,9 @@ class SeamlessAppRotationTest(
configuration.endRotation)
statusBarLayerRotatesScales(configuration.startRotation,
configuration.endRotation, enabled = false)
+ visibleLayersShownMoreThanOneConsecutiveEntry(
+ enabled = configuration.startRotation == configuration.endRotation)
+ layerAlwaysVisible(configuration.intentPackageName)
}
layersTrace {
diff --git a/tests/GamePerformance/Android.bp b/tests/GamePerformance/Android.bp
index 648fd8151b4e..02908d3a4cd4 100644
--- a/tests/GamePerformance/Android.bp
+++ b/tests/GamePerformance/Android.bp
@@ -22,7 +22,7 @@ android_test_helper_app {
enabled: false,
},
srcs: ["src/**/*.java"],
- static_libs: ["android-support-test"],
+ static_libs: ["androidx.test.rules"],
libs: [
"android.test.base",
"android.test.runner",
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index 0e9f723d6063..a8aab2a899fb 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -6,7 +6,6 @@ android_test {
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
- "android-support-test",
"ub-uiautomator",
],
test_suites: ["device-tests"],
diff --git a/tests/NullHomeTest/Android.bp b/tests/NullHomeTest/Android.bp
index 99248bfe1da1..fc71d0deaac6 100644
--- a/tests/NullHomeTest/Android.bp
+++ b/tests/NullHomeTest/Android.bp
@@ -17,6 +17,6 @@ android_test {
srcs: ["src/**/*.java"],
certificate: "platform",
platform_apis: true,
- static_libs: ["android-support-test"],
+ static_libs: ["androidx.test.rules"],
test_suites: ["device-tests"],
}
diff --git a/tests/NullHomeTest/AndroidManifest.xml b/tests/NullHomeTest/AndroidManifest.xml
index dc6402e03b5a..6f77781c7a29 100644
--- a/tests/NullHomeTest/AndroidManifest.xml
+++ b/tests/NullHomeTest/AndroidManifest.xml
@@ -21,7 +21,7 @@
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
<instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.test.nullhome"
android:label="Check if no null Home exists/is enabled" />
diff --git a/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java b/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
index 1d77cdc51187..3ec3ef2f8fea 100644
--- a/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
+++ b/tests/NullHomeTest/src/com/android/test/nullhome/NullHomeTest.java
@@ -18,9 +18,10 @@ package com.android.test.nullhome;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.support.test.InstrumentationRegistry;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index ae93a81f274e..fa0574a503f1 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -376,7 +376,7 @@ public class PackageWatchdogTest {
TestObserver observer = new TestObserver(OBSERVER_NAME_1) {
@Override
public int onHealthCheckFailed(VersionedPackage versionedPackage,
- int failureReason) {
+ int failureReason, int mitigationCount) {
if (versionedPackage.getVersionCode() == VERSION_CODE) {
// Only rollback for specific versionCode
return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
@@ -1146,6 +1146,45 @@ public class PackageWatchdogTest {
assertThat(observer.mMitigatedPackages).isEqualTo(List.of(APP_A));
}
+ /**
+ * Ensure that the sliding window logic results in the correct mitigation count being sent to
+ * an observer.
+ */
+ @Test
+ public void testMitigationSlidingWindow() {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observer = new TestObserver(OBSERVER_NAME_1);
+ watchdog.startObservingHealth(observer, List.of(APP_A),
+ PackageWatchdog.DEFAULT_OBSERVING_DURATION_MS * 2);
+
+
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ moveTimeForwardAndDispatch(TimeUnit.MINUTES.toMillis(10));
+
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS);
+
+ // The first failure will be outside the threshold.
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ moveTimeForwardAndDispatch(TimeUnit.MINUTES.toMillis(20));
+
+ // The next 2 failures will also be outside the threshold.
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+ raiseFatalFailureAndDispatch(watchdog, Arrays.asList(new VersionedPackage(APP_A,
+ VERSION_CODE)), PackageWatchdog.FAILURE_REASON_UNKNOWN);
+
+ assertThat(observer.mMitigationCounts).isEqualTo(List.of(1, 2, 3, 3, 2, 3));
+ }
+
private void adoptShellPermissions(String... permissions) {
InstrumentationRegistry
.getInstrumentation()
@@ -1227,6 +1266,7 @@ public class PackageWatchdogTest {
private boolean mMitigatedBootLoop = false;
final List<String> mHealthCheckFailedPackages = new ArrayList<>();
final List<String> mMitigatedPackages = new ArrayList<>();
+ final List<Integer> mMitigationCounts = new ArrayList<>();
TestObserver(String name) {
mName = name;
@@ -1238,13 +1278,16 @@ public class PackageWatchdogTest {
mImpact = impact;
}
- public int onHealthCheckFailed(VersionedPackage versionedPackage, int failureReason) {
+ public int onHealthCheckFailed(VersionedPackage versionedPackage, int failureReason,
+ int mitigationCount) {
mHealthCheckFailedPackages.add(versionedPackage.getPackageName());
return mImpact;
}
- public boolean execute(VersionedPackage versionedPackage, int failureReason) {
+ public boolean execute(VersionedPackage versionedPackage, int failureReason,
+ int mitigationCount) {
mMitigatedPackages.add(versionedPackage.getPackageName());
+ mMitigationCounts.add(mitigationCount);
mLastFailureReason = failureReason;
return true;
}
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 11a83ebf6dd7..6b7ea66df233 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -359,7 +359,7 @@ public class NetworkCapabilitiesTest {
assertFalse(nr.satisfiedByNetworkCapabilities(new NetworkCapabilities()));
}
- @Test
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
public void testOemPrivate() {
NetworkCapabilities nc = new NetworkCapabilities();
// By default OEM_PRIVATE is neither in the unwanted or required lists and the network is
diff --git a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
new file mode 100644
index 000000000000..b77ed6ab5a29
--- /dev/null
+++ b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.net;
+
+import static com.android.testutils.MiscAsserts.assertThrows;
+import static com.android.testutils.ParcelUtils.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.util.SparseArray;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class OemNetworkPreferencesTest {
+
+ private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_DEFAULT;
+ private static final String TEST_PACKAGE = "com.google.apps.contacts";
+
+ private final List<String> mPackages = new ArrayList<>();
+ private final OemNetworkPreferences.Builder mBuilder = new OemNetworkPreferences.Builder();
+
+ @Before
+ public void beforeEachTestMethod() {
+ mPackages.add(TEST_PACKAGE);
+ }
+
+ @Test
+ public void builderAddNetworkPreferenceRequiresNonNullPackages() {
+ assertThrows(NullPointerException.class,
+ () -> mBuilder.addNetworkPreference(TEST_PREF, null));
+ }
+
+ @Test
+ public void getNetworkPreferencesReturnsCorrectValue() {
+ final int expectedNumberOfMappings = 1;
+ mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+
+ final SparseArray<List<String>> networkPreferences =
+ mBuilder.build().getNetworkPreferences();
+
+ assertEquals(expectedNumberOfMappings, networkPreferences.size());
+ assertEquals(mPackages.size(), networkPreferences.get(TEST_PREF).size());
+ assertEquals(mPackages.get(0), networkPreferences.get(TEST_PREF).get(0));
+ }
+
+ @Test
+ public void getNetworkPreferencesReturnsUnmodifiableValue() {
+ final String newPackage = "new.com.google.apps.contacts";
+ mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+
+ final SparseArray<List<String>> networkPreferences =
+ mBuilder.build().getNetworkPreferences();
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> networkPreferences.get(TEST_PREF).set(mPackages.size() - 1, newPackage));
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> networkPreferences.get(TEST_PREF).add(newPackage));
+ }
+
+ @Test
+ public void toStringReturnsCorrectValue() {
+ mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+
+ final String networkPreferencesString = mBuilder.build().getNetworkPreferences().toString();
+
+ assertTrue(networkPreferencesString.contains(Integer.toString(TEST_PREF)));
+ assertTrue(networkPreferencesString.contains(TEST_PACKAGE));
+ }
+
+ @Test
+ public void testOemNetworkPreferencesParcelable() {
+ mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+
+ final OemNetworkPreferences prefs = mBuilder.build();
+
+ assertParcelSane(prefs, 1 /* fieldCount */);
+ }
+}
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 91c9a2a38036..6de31f6b4be1 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -22,11 +22,11 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.net.util.MacAddressUtils;
-
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.net.module.util.MacAddressUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
index de1028cd2303..c53462cfb0b2 100644
--- a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -34,6 +34,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -53,6 +54,7 @@ import android.net.NetworkTemplate;
import android.net.StringNetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
import android.os.Handler;
+import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
@@ -91,6 +93,7 @@ public class MultipathPolicyTrackerTest {
private static final int POLICY_SNOOZED = -100;
@Mock private Context mContext;
+ @Mock private Context mUserAllContext;
@Mock private Resources mResources;
@Mock private Handler mHandler;
@Mock private MultipathPolicyTracker.Dependencies mDeps;
@@ -127,8 +130,11 @@ public class MultipathPolicyTrackerTest {
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
- when(mContext.registerReceiverAsUser(mConfigChangeReceiverCaptor.capture(),
- any(), argThat(f -> f.hasAction(ACTION_CONFIGURATION_CHANGED)), any(), any()))
+ doReturn(UserHandle.ALL.getIdentifier()).when(mUserAllContext).getUserId();
+ when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt()))
+ .thenReturn(mUserAllContext);
+ when(mUserAllContext.registerReceiver(mConfigChangeReceiverCaptor.capture(),
+ argThat(f -> f.hasAction(ACTION_CONFIGURATION_CHANGED)), any(), any()))
.thenReturn(null);
when(mDeps.getClock()).thenReturn(mClock);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index e3ba3e106e14..1dcc07c6db81 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -241,7 +241,7 @@ public class VpnTest {
doNothing().when(mNetService).registerObserver(any());
// Deny all appops by default.
- when(mAppOps.noteOpNoThrow(anyInt(), anyInt(), anyString()))
+ when(mAppOps.noteOpNoThrow(anyString(), anyInt(), anyString(), any(), any()))
.thenReturn(AppOpsManager.MODE_IGNORED);
// Setup IpSecService
@@ -729,26 +729,27 @@ public class VpnTest {
assertEquals(expected, vpn.getProfileNameForPackage(TEST_VPN_PKG));
}
- private Vpn createVpnAndSetupUidChecks(int... grantedOps) throws Exception {
+ private Vpn createVpnAndSetupUidChecks(String... grantedOps) throws Exception {
return createVpnAndSetupUidChecks(primaryUser, grantedOps);
}
- private Vpn createVpnAndSetupUidChecks(UserInfo user, int... grantedOps) throws Exception {
+ private Vpn createVpnAndSetupUidChecks(UserInfo user, String... grantedOps) throws Exception {
final Vpn vpn = createVpn(user.id);
setMockedUsers(user);
when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
.thenReturn(Process.myUid());
- for (final int op : grantedOps) {
- when(mAppOps.noteOpNoThrow(op, Process.myUid(), TEST_VPN_PKG))
+ for (final String opStr : grantedOps) {
+ when(mAppOps.noteOpNoThrow(opStr, Process.myUid(), TEST_VPN_PKG,
+ null /* attributionTag */, null /* message */))
.thenReturn(AppOpsManager.MODE_ALLOWED);
}
return vpn;
}
- private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, int... checkedOps) {
+ private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps) {
assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore));
// The profile should always be stored, whether or not consent has been previously granted.
@@ -759,8 +760,9 @@ public class VpnTest {
eq(Process.SYSTEM_UID),
eq(0));
- for (final int checkedOp : checkedOps) {
- verify(mAppOps).noteOpNoThrow(checkedOp, Process.myUid(), TEST_VPN_PKG);
+ for (final String checkedOpStr : checkedOps) {
+ verify(mAppOps).noteOpNoThrow(checkedOpStr, Process.myUid(), TEST_VPN_PKG,
+ null /* attributionTag */, null /* message */);
}
}
@@ -768,11 +770,11 @@ public class VpnTest {
public void testProvisionVpnProfileNoIpsecTunnels() throws Exception {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
.thenReturn(false);
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
checkProvisionVpnProfile(
- vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
fail("Expected exception due to missing feature");
} catch (UnsupportedOperationException expected) {
}
@@ -780,10 +782,10 @@ public class VpnTest {
@Test
public void testProvisionVpnProfilePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
checkProvisionVpnProfile(
- vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
}
@Test
@@ -793,19 +795,19 @@ public class VpnTest {
// Expect that both the ACTIVATE_VPN and ACTIVATE_PLATFORM_VPN were tried, but the caller
// had neither.
checkProvisionVpnProfile(vpn, false /* expectedResult */,
- AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, AppOpsManager.OP_ACTIVATE_VPN);
+ AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN, AppOpsManager.OPSTR_ACTIVATE_VPN);
}
@Test
public void testProvisionVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
- checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_VPN);
+ checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_VPN);
}
@Test
public void testProvisionVpnProfileTooLarge() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
final VpnProfile bigProfile = new VpnProfile("");
bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]);
@@ -821,7 +823,7 @@ public class VpnTest {
public void testProvisionVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore);
@@ -844,7 +846,7 @@ public class VpnTest {
public void testDeleteVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore);
@@ -867,7 +869,7 @@ public class VpnTest {
@Test
public void testStartVpnProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
@@ -877,14 +879,16 @@ public class VpnTest {
verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
verify(mAppOps)
.noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
- eq(TEST_VPN_PKG));
+ eq(TEST_VPN_PKG),
+ eq(null) /* attributionTag */,
+ eq(null) /* message */);
}
@Test
public void testStartVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
@@ -892,7 +896,8 @@ public class VpnTest {
vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
// Verify that the the ACTIVATE_VPN appop was checked, but no error was thrown.
- verify(mAppOps).noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Process.myUid(), TEST_VPN_PKG);
+ verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
+ TEST_VPN_PKG, null /* attributionTag */, null /* message */);
}
@Test
@@ -908,10 +913,13 @@ public class VpnTest {
// Verify both appops were checked.
verify(mAppOps)
.noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
- eq(TEST_VPN_PKG));
- verify(mAppOps).noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Process.myUid(), TEST_VPN_PKG);
+ eq(TEST_VPN_PKG),
+ eq(null) /* attributionTag */,
+ eq(null) /* message */);
+ verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
+ TEST_VPN_PKG, null /* attributionTag */, null /* message */);
// Keystore should never have been accessed.
verify(mKeyStore, never()).get(any());
@@ -919,7 +927,7 @@ public class VpnTest {
@Test
public void testStartVpnProfileMissingProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
@@ -932,16 +940,18 @@ public class VpnTest {
verify(mKeyStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
verify(mAppOps)
.noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
- eq(TEST_VPN_PKG));
+ eq(TEST_VPN_PKG),
+ eq(null) /* attributionTag */,
+ eq(null) /* message */);
}
@Test
public void testStartVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
@@ -954,7 +964,7 @@ public class VpnTest {
public void testStopVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.stopVpnProfile(TEST_VPN_PKG);
@@ -970,7 +980,7 @@ public class VpnTest {
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_SERVICE));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_ALLOWED));
@@ -983,7 +993,7 @@ public class VpnTest {
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_PLATFORM));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_ALLOWED));
@@ -996,13 +1006,13 @@ public class VpnTest {
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_NONE));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_IGNORED));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_IGNORED));
@@ -1059,7 +1069,7 @@ public class VpnTest {
verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
verify(mAppOps).setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_ALLOWED));
verify(mSystemServices).settingsSecurePutStringForUser(
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 7abe1893dd9e..cd9406cf3481 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -35,7 +35,6 @@ import static android.net.NetworkStats.ROAMING_YES;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.STATS_PER_IFACE;
import static android.net.NetworkStats.STATS_PER_UID;
import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
@@ -994,7 +993,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
public void testTethering() throws Exception {
// pretend first mobile network comes online
expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
+ final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
@@ -1004,23 +1003,39 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
incrementCurrentTime(HOUR_IN_MILLIS);
expectDefaultSettings();
+ // Register custom provider and retrieve callback.
+ final TestableNetworkStatsProviderBinder provider =
+ new TestableNetworkStatsProviderBinder();
+ final INetworkStatsProviderCallback cb =
+ mService.registerNetworkStatsProvider("TEST-TETHERING-OFFLOAD", provider);
+ assertNotNull(cb);
+ final long now = getElapsedRealtime();
+
// Traffic seen by kernel counters (includes software tethering).
- final NetworkStats ifaceStats = new NetworkStats(getElapsedRealtime(), 1)
+ final NetworkStats swIfaceStats = new NetworkStats(now, 1)
.insertEntry(TEST_IFACE, 1536L, 12L, 384L, 3L);
// Hardware tethering traffic, not seen by kernel counters.
- final NetworkStats tetherStatsHardware = new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 512L, 4L, 128L, 1L);
+ final NetworkStats tetherHwIfaceStats = new NetworkStats(now, 1)
+ .insertEntry(new NetworkStats.Entry(TEST_IFACE, UID_ALL, SET_DEFAULT,
+ TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
+ 512L, 4L, 128L, 1L, 0L));
+ final NetworkStats tetherHwUidStats = new NetworkStats(now, 1)
+ .insertEntry(new NetworkStats.Entry(TEST_IFACE, UID_TETHERING, SET_DEFAULT,
+ TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
+ 512L, 4L, 128L, 1L, 0L));
+ cb.notifyStatsUpdated(0 /* unused */, tetherHwIfaceStats, tetherHwUidStats);
- // Traffic for UID_RED.
- final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1)
+ // Fake some traffic done by apps on the device (as opposed to tethering), and record it
+ // into UID stats (as opposed to iface stats).
+ final NetworkStats localUidStats = new NetworkStats(now, 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
- // All tethering traffic, both hardware and software.
- final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L,
+ // Software per-uid tethering traffic.
+ final NetworkStats tetherSwUidStats = new NetworkStats(now, 1)
+ .insertEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1408L, 10L, 256L, 1L,
0L);
- expectNetworkStatsSummary(ifaceStats, tetherStatsHardware);
- expectNetworkStatsUidDetail(uidStats, tetherStats);
+ expectNetworkStatsSummary(swIfaceStats);
+ expectNetworkStatsUidDetail(localUidStats, tetherSwUidStats);
forcePollAndWaitForIdle();
// verify service recorded history
@@ -1362,12 +1377,6 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
}
private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
- expectNetworkStatsSummary(summary, new NetworkStats(0L, 0));
- }
-
- private void expectNetworkStatsSummary(NetworkStats summary, NetworkStats tetherStats)
- throws Exception {
- expectNetworkStatsTethering(STATS_PER_IFACE, tetherStats);
expectNetworkStatsSummaryDev(summary.clone());
expectNetworkStatsSummaryXt(summary.clone());
}
@@ -1380,11 +1389,6 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
when(mStatsFactory.readNetworkStatsSummaryXt()).thenReturn(summary);
}
- private void expectNetworkStatsTethering(int how, NetworkStats stats)
- throws Exception {
- when(mNetManager.getNetworkStatsTethering(how)).thenReturn(stats);
- }
-
private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
expectNetworkStatsUidDetail(detail, new NetworkStats(0L, 0));
}
diff --git a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
index f80af034fa2b..84448333a8c6 100644
--- a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
+++ b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
@@ -16,6 +16,7 @@
package com.android.internal.util.test;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -140,6 +141,24 @@ public class SystemPreparer extends ExternalResource {
return this;
}
+ /** Stages multiple APEXs within the host test jar onto the device. */
+ public SystemPreparer stageMultiplePackages(String[] resourcePaths, String[] packageNames)
+ throws DeviceNotAvailableException, IOException {
+ assertEquals(resourcePaths.length, packageNames.length);
+ final ITestDevice device = mDeviceProvider.getDevice();
+ final String[] adbCommandLine = new String[resourcePaths.length + 2];
+ adbCommandLine[0] = "install-multi-package";
+ adbCommandLine[1] = "--staged";
+ for (int i = 0; i < resourcePaths.length; i++) {
+ final File tmpFile = copyResourceToTemp(resourcePaths[i]);
+ adbCommandLine[i + 2] = tmpFile.getAbsolutePath();
+ mInstalledPackages.add(packageNames[i]);
+ }
+ final String output = device.executeAdbCommand(adbCommandLine);
+ assertTrue(output.contains("Success. Reboot device to apply staged session"));
+ return this;
+ }
+
/** Sets the enable state of an overlay package. */
public SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
throws DeviceNotAvailableException {
@@ -210,11 +229,29 @@ public class SystemPreparer extends ExternalResource {
return this;
}
+ private static @Nullable String getFileExtension(@Nullable String path) {
+ if (path == null) {
+ return null;
+ }
+ final int lastDot = path.lastIndexOf('.');
+ if (lastDot >= 0) {
+ return path.substring(lastDot + 1);
+ } else {
+ return null;
+ }
+ }
+
/** Copies a file within the host test jar to a temporary file on the host machine. */
private File copyResourceToTemp(String resourcePath) throws IOException {
- final File tempFile = mHostTempFolder.newFile();
+ final String ext = getFileExtension(resourcePath);
+ final File tempFile;
+ if (ext != null) {
+ tempFile = File.createTempFile("junit", "." + ext, mHostTempFolder.getRoot());
+ } else {
+ tempFile = mHostTempFolder.newFile();
+ }
final ClassLoader classLoader = getClass().getClassLoader();
- try (InputStream assetIs = classLoader.getResource(resourcePath).openStream();
+ try (InputStream assetIs = classLoader.getResourceAsStream(resourcePath);
FileOutputStream assetOs = new FileOutputStream(tempFile)) {
if (assetIs == null) {
throw new IllegalStateException("Failed to find resource " + resourcePath);
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
new file mode 100644
index 000000000000..f967bf0d8f6b
--- /dev/null
+++ b/tests/vcn/Android.bp
@@ -0,0 +1,27 @@
+//########################################################################
+// Build FrameworksVcnTests package
+//########################################################################
+
+android_test {
+ name: "FrameworksVcnTests",
+ srcs: [
+ "java/**/*.java",
+ "java/**/*.kt",
+ ],
+ platform_apis: true,
+ test_suites: ["device-tests"],
+ certificate: "platform",
+ static_libs: [
+ "androidx.test.rules",
+ "frameworks-base-testutils",
+ "framework-protos",
+ "mockito-target-minus-junit4",
+ "platform-test-annotations",
+ "services.core",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+}
diff --git a/packages/CarSystemUI/res/anim/car_user_switcher_close_icon_animation.xml b/tests/vcn/AndroidManifest.xml
index 9f8c12ef16b5..2ad9aac67029 100644
--- a/packages/CarSystemUI/res/anim/car_user_switcher_close_icon_animation.xml
+++ b/tests/vcn/AndroidManifest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2018 The Android Open Source Project
+<?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.
@@ -12,13 +13,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android">
- <objectAnimator
- android:duration="167"
- android:propertyName="rotation"
- android:valueType="floatType"
- android:valueFrom="180"
- android:valueTo="0"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set> \ No newline at end of file
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.tests.vcn">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.tests.vcn"
+ android:label="Frameworks VCN Tests" />
+</manifest>
diff --git a/tests/vcn/AndroidTest.xml b/tests/vcn/AndroidTest.xml
new file mode 100644
index 000000000000..dc521fd7bcd9
--- /dev/null
+++ b/tests/vcn/AndroidTest.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.
+-->
+<configuration description="Runs VCN Tests.">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="FrameworksVcnTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-tag" value="FrameworksVcnTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.frameworks.tests.vcn" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/tests/vcn/TEST_MAPPING b/tests/vcn/TEST_MAPPING
new file mode 100644
index 000000000000..54fa411e3570
--- /dev/null
+++ b/tests/vcn/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksVcnTests"
+ }
+ ]
+} \ No newline at end of file
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index ab6dced5b67d..dd3ebdbdea09 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -519,7 +519,7 @@ static int validateAttr(const String8& path, const ResTable& table,
String8(parser.getElementName(&len)).string(), attr);
return ATTR_NOT_FOUND;
}
- if ((str=pool->stringAt(value.data, &len)) == NULL) {
+ if ((str = UnpackOptionalString(pool->stringAt(value.data), &len)) == NULL) {
fprintf(stderr, "%s:%d: Tag <%s> attribute %s has corrupt string value.\n",
path.string(), parser.getLineNumber(),
String8(parser.getElementName(&len)).string(), attr);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index d02f44edaa4c..257e96b6e51a 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -3066,7 +3066,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
for (size_t ti=0; ti<N; ti++) {
// Retrieve them in the same order as the type string block.
size_t len;
- String16 typeName(p->getTypeStrings().stringAt(ti, &len));
+ String16 typeName(UnpackOptionalString(p->getTypeStrings().stringAt(ti), &len));
sp<Type> t = p->getTypes().valueFor(typeName);
LOG_ALWAYS_FATAL_IF(t == NULL && typeName != String16("<empty>"),
"Type name %s not found",
@@ -4169,7 +4169,7 @@ status_t ResourceTable::Package::setStrings(const sp<AaptFile>& data,
const size_t N = strings->size();
for (size_t i=0; i<N; i++) {
size_t len;
- mappings->add(String16(strings->stringAt(i, &len)), i);
+ mappings->add(String16(UnpackOptionalString(strings->stringAt(i), &len)), i);
}
}
return err;
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 37b61bfdffbd..6cacd32eb91d 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -52,9 +52,9 @@ void printStringPool(const ResStringPool* pool)
for (size_t i=0; i<N; i++) {
size_t len;
if (pool->isUTF8()) {
- uniqueStrings.add(pool->string8At(i, &len));
+ uniqueStrings.add(UnpackOptionalString(pool->string8At(i), &len));
} else {
- uniqueStrings.add(pool->stringAt(i, &len));
+ uniqueStrings.add(UnpackOptionalString(pool->stringAt(i), &len));
}
}
@@ -66,8 +66,8 @@ void printStringPool(const ResStringPool* pool)
const size_t NS = pool->size();
for (size_t s=0; s<NS; s++) {
- String8 str = pool->string8ObjectAt(s);
- printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string());
+ auto str = pool->string8ObjectAt(s);
+ printf("String #" ZD ": %s\n", (ZD_TYPE) s, (str.has_value() ? str->string() : ""));
}
}
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 439f231193df..82da24959521 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -436,9 +436,9 @@ void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer*
for (size_t i=0; i<N; i++) {
size_t len;
if (pool->isUTF8()) {
- uniqueStrings.add(pool->string8At(i, &len));
+ uniqueStrings.add(UnpackOptionalString(pool->string8At(i), &len));
} else {
- uniqueStrings.add(pool->stringAt(i, &len));
+ uniqueStrings.add(UnpackOptionalString(pool->stringAt(i), &len));
}
}
@@ -450,8 +450,8 @@ void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer*
const size_t NS = pool->size();
for (size_t s=0; s<NS; s++) {
- String8 str = pool->string8ObjectAt(s);
- printer->Print(StringPrintf("String #%zd : %s\n", s, str.string()));
+ auto str = pool->string8ObjectAt(s);
+ printer->Print(StringPrintf("String #%zd : %s\n", s, str.has_value() ? str->string() : ""));
}
}
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 7dfc983b54ba..5b43df6f0935 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -751,10 +751,12 @@ std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const Config
switch (res_value.dataType) {
case android::Res_value::TYPE_STRING: {
const std::string str = util::GetString(src_pool, data);
- const android::ResStringPool_span* spans = src_pool.styleAt(data);
+ auto spans_result = src_pool.styleAt(data);
// Check if the string has a valid style associated with it.
- if (spans != nullptr && spans->name.index != android::ResStringPool_span::END) {
+ if (spans_result.has_value() &&
+ (*spans_result)->name.index != android::ResStringPool_span::END) {
+ const android::ResStringPool_span* spans = spans_result->unsafe_ptr();
StyleString style_str = {str};
while (spans->name.index != android::ResStringPool_span::END) {
style_str.spans.push_back(Span{util::GetString(src_pool, spans->name.index),
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index 9a7238b584ba..6e5200bca44c 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -223,11 +223,11 @@ TEST(StringPoolTest, FlattenOddCharactersUtf16) {
std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
ResStringPool test;
ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
- size_t len = 0;
- const char16_t* str = test.stringAt(0, &len);
- EXPECT_THAT(len, Eq(1u));
- EXPECT_THAT(str, Pointee(Eq(u'\u093f')));
- EXPECT_THAT(str[1], Eq(0u));
+ auto str = test.stringAt(0);
+ ASSERT_TRUE(str.has_value());
+ EXPECT_THAT(str->size(), Eq(1u));
+ EXPECT_THAT(str->data(), Pointee(Eq(u'\u093f')));
+ EXPECT_THAT(str->data()[1], Eq(0u));
}
constexpr const char* sLongString =
@@ -278,14 +278,15 @@ TEST(StringPoolTest, Flatten) {
EXPECT_THAT(util::GetString(test, 3), Eq(sLongString));
EXPECT_THAT(util::GetString16(test, 3), Eq(util::Utf8ToUtf16(sLongString)));
- size_t len;
- EXPECT_TRUE(test.stringAt(4, &len) != nullptr || test.string8At(4, &len) != nullptr);
+ EXPECT_TRUE(test.stringAt(4).has_value() || test.string8At(4).has_value());
EXPECT_THAT(util::GetString(test, 0), Eq("style"));
EXPECT_THAT(util::GetString16(test, 0), Eq(u"style"));
- const ResStringPool_span* span = test.styleAt(0);
- ASSERT_THAT(span, NotNull());
+ auto span_result = test.styleAt(0);
+ ASSERT_TRUE(span_result.has_value());
+
+ const ResStringPool_span* span = span_result->unsafe_ptr();
EXPECT_THAT(util::GetString(test, span->name.index), Eq("b"));
EXPECT_THAT(util::GetString16(test, span->name.index), Eq(u"b"));
EXPECT_THAT(span->firstChar, Eq(0u));
@@ -318,16 +319,17 @@ TEST(StringPoolTest, ModifiedUTF8) {
// Check that the codepoints are encoded using two three-byte surrogate pairs
ResStringPool test;
ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
- size_t len;
- const char* str = test.string8At(0, &len);
- ASSERT_THAT(str, NotNull());
- EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80"));
- str = test.string8At(1, &len);
- ASSERT_THAT(str, NotNull());
- EXPECT_THAT(std::string(str, len), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
- str = test.string8At(2, &len);
- ASSERT_THAT(str, NotNull());
- EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
+ auto str = test.string8At(0);
+ ASSERT_TRUE(str.has_value());
+ EXPECT_THAT(str->to_string(), Eq("\xED\xA0\x81\xED\xB0\x80"));
+
+ str = test.string8At(1);
+ ASSERT_TRUE(str.has_value());
+ EXPECT_THAT(str->to_string(), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
+
+ str = test.string8At(2);
+ ASSERT_TRUE(str.has_value());
+ EXPECT_THAT(str->to_string(), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
// Check that retrieving the strings returns the original UTF-8 character bytes
EXPECT_THAT(util::GetString(test, 0), Eq("\xF0\x90\x90\x80"));
diff --git a/tools/aapt2/cmd/Compile_test.cpp b/tools/aapt2/cmd/Compile_test.cpp
index 0aab94d3299f..8cbd998f2ae2 100644
--- a/tools/aapt2/cmd/Compile_test.cpp
+++ b/tools/aapt2/cmd/Compile_test.cpp
@@ -314,8 +314,10 @@ TEST_F(CompilerTest, RelativePathTest) {
ASSERT_NE(content_values.find(relative_path_values_colors), -1);
ASSERT_EQ(content_values.find(path_values_colors), -1);
- Link({"-o", apk_path, "--manifest", GetDefaultManifest(), "--proto-format"},
- compiled_files_dir, &diag);
+ ASSERT_TRUE(Link({"-o", apk_path,
+ "--manifest", GetDefaultManifest(),
+ "--proto-format"},
+ compiled_files_dir, &diag));
std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(apk_path, &diag);
ResourceTable* resource_table = apk.get()->GetResourceTable();
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 118a76ff73a8..f92c602fd761 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -732,22 +732,6 @@ static bool LoadStableIdMap(IDiagnostics* diag, const std::string& path,
return true;
}
-static android::ApkAssetsCookie FindFrameworkAssetManagerCookie(
- const android::AssetManager2& assets) {
- using namespace android;
-
- // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so
- // we're looking for the first attribute resource in the system package.
- Res_value val{};
- ResTable_config config{};
- uint32_t type_spec_flags;
- ApkAssetsCookie idx = assets.GetResource(0x01010000, true /** may_be_bag */,
- 0 /** density_override */, &val, &config,
- &type_spec_flags);
-
- return idx;
-}
-
class Linker {
public:
Linker(LinkContext* context, const LinkOptions& options)
@@ -760,8 +744,12 @@ class Linker {
void ExtractCompileSdkVersions(android::AssetManager2* assets) {
using namespace android;
- android::ApkAssetsCookie cookie = FindFrameworkAssetManagerCookie(*assets);
- if (cookie == android::kInvalidCookie) {
+ // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so
+ // we're looking for the first attribute resource in the system package.
+ android::ApkAssetsCookie cookie;
+ if (auto value = assets->GetResource(0x01010000, true /** may_be_bag */); value.has_value()) {
+ cookie = value->cookie;
+ } else {
// No Framework assets loaded. Not a failure.
return;
}
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 6932baf76c75..f8b8a1c4e35b 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -189,16 +189,16 @@ TEST_F(TableFlattenerTest, FlattenFullyLinkedTable) {
ResTable_config::CONFIG_VERSION));
std::u16string foo_str = u"foo";
- ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
- ASSERT_GE(idx, 0);
+ auto idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:string/test", ResourceId(0x7f040000), {},
- Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
std::u16string bar_path = u"res/layout/bar.xml";
idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
- ASSERT_GE(idx, 0);
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/bar", ResourceId(0x7f050000), {},
- Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
}
TEST_F(TableFlattenerTest, FlattenEntriesWithGapsInIds) {
@@ -603,16 +603,16 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesNoNameCollapseExemptionsSucce
2u, ResTable_config::CONFIG_VERSION));
std::u16string foo_str = u"foo";
- ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
- ASSERT_GE(idx, 0);
+ auto idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:string/0_resource_name_obfuscated",
- ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
std::u16string bar_path = u"res/layout/bar.xml";
idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
- ASSERT_GE(idx, 0);
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated",
- ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
}
TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSucceeds) {
@@ -659,16 +659,16 @@ TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSuc
2u, ResTable_config::CONFIG_VERSION));
std::u16string foo_str = u"foo";
- ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
- ASSERT_GE(idx, 0);
+ auto idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:string/test", ResourceId(0x7f040000), {},
- Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
std::u16string bar_path = u"res/layout/bar.xml";
idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
- ASSERT_GE(idx, 0);
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated",
- ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
}
TEST_F(TableFlattenerTest, FlattenOverlayable) {
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 897fa80ffedb..ad716c78d65d 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -265,21 +265,22 @@ bool AssetManagerSymbolSource::IsPackageDynamic(uint32_t packageId,
static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable(
android::AssetManager2& am, ResourceId id) {
+ using namespace android;
if (am.GetApkAssets().empty()) {
return {};
}
- const android::ResolvedBag* bag = am.GetBag(id.id);
- if (bag == nullptr) {
+ auto bag_result = am.GetBag(id.id);
+ if (!bag_result.has_value()) {
return nullptr;
}
// We found a resource.
std::unique_ptr<SymbolTable::Symbol> s = util::make_unique<SymbolTable::Symbol>(id);
-
+ const ResolvedBag* bag = *bag_result;
const size_t count = bag->entry_count;
for (uint32_t i = 0; i < count; i++) {
- if (bag->entries[i].key == android::ResTable_map::ATTR_TYPE) {
+ if (bag->entries[i].key == ResTable_map::ATTR_TYPE) {
s->attribute = std::make_shared<Attribute>(bag->entries[i].value.data);
break;
}
@@ -287,25 +288,25 @@ static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable(
if (s->attribute) {
for (size_t i = 0; i < count; i++) {
- const android::ResolvedBag::Entry& map_entry = bag->entries[i];
+ const ResolvedBag::Entry& map_entry = bag->entries[i];
if (Res_INTERNALID(map_entry.key)) {
switch (map_entry.key) {
- case android::ResTable_map::ATTR_MIN:
+ case ResTable_map::ATTR_MIN:
s->attribute->min_int = static_cast<int32_t>(map_entry.value.data);
break;
- case android::ResTable_map::ATTR_MAX:
+ case ResTable_map::ATTR_MAX:
s->attribute->max_int = static_cast<int32_t>(map_entry.value.data);
break;
}
continue;
}
- android::AssetManager2::ResourceName name;
- if (!am.GetResourceName(map_entry.key, &name)) {
+ auto name = am.GetResourceName(map_entry.key);
+ if (!name.has_value()) {
return nullptr;
}
- Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(name);
+ Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(*name);
if (!parsed_name) {
return nullptr;
}
@@ -328,7 +329,7 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName(
bool found = false;
ResourceId res_id = 0;
- uint32_t type_spec_flags;
+ uint32_t type_spec_flags = 0;
ResourceName real_name;
// There can be mangled resources embedded within other packages. Here we will
@@ -340,8 +341,19 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName(
real_name.package = package_name;
}
- res_id = asset_manager_.GetResourceId(real_name.to_string());
- if (res_id.is_valid_static() && asset_manager_.GetResourceFlags(res_id.id, &type_spec_flags)) {
+ auto real_res_id = asset_manager_.GetResourceId(real_name.to_string());
+ if (!real_res_id.has_value()) {
+ return true;
+ }
+
+ res_id.id = *real_res_id;
+ if (!res_id.is_valid_static()) {
+ return true;
+ }
+
+ auto value = asset_manager_.GetResource(res_id.id, true /* may_be_bag */);
+ if (value.has_value()) {
+ type_spec_flags = value->flags;
found = true;
return false;
}
@@ -371,11 +383,11 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindByName(
static Maybe<ResourceName> GetResourceName(android::AssetManager2& am,
ResourceId id) {
- android::AssetManager2::ResourceName name;
- if (!am.GetResourceName(id.id, &name)) {
+ auto name = am.GetResourceName(id.id);
+ if (!name.has_value()) {
return {};
}
- return ResourceUtils::ToResourceName(name);
+ return ResourceUtils::ToResourceName(*name);
}
std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById(
@@ -394,9 +406,8 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById(
return {};
}
-
- uint32_t type_spec_flags = 0;
- if (!asset_manager_.GetResourceFlags(id.id, &type_spec_flags)) {
+ auto value = asset_manager_.GetResource(id.id, true /* may_be_bag */);
+ if (!value.has_value()) {
return {};
}
@@ -411,7 +422,7 @@ std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById(
}
if (s) {
- s->is_public = (type_spec_flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+ s->is_public = (value->flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
return s;
}
return {};
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index 37ce65e4fe5b..ef33c3463a81 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -531,19 +531,15 @@ bool ExtractResFilePathParts(const StringPiece& path, StringPiece* out_prefix,
}
StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx) {
- size_t len;
- const char16_t* str = pool.stringAt(idx, &len);
- if (str != nullptr) {
- return StringPiece16(str, len);
+ if (auto str = pool.stringAt(idx)) {
+ return *str;
}
return StringPiece16();
}
std::string GetString(const android::ResStringPool& pool, size_t idx) {
- size_t len;
- const char* str = pool.string8At(idx, &len);
- if (str != nullptr) {
- return ModifiedUtf8ToUtf8(std::string(str, len));
+ if (auto str = pool.string8At(idx)) {
+ return ModifiedUtf8ToUtf8(str->to_string());
}
return Utf16ToUtf8(GetString16(pool, idx));
}
diff --git a/tools/codegen/src/com/android/codegen/ClassInfo.kt b/tools/codegen/src/com/android/codegen/ClassInfo.kt
index bf95a2eb2193..056898c9eca1 100644
--- a/tools/codegen/src/com/android/codegen/ClassInfo.kt
+++ b/tools/codegen/src/com/android/codegen/ClassInfo.kt
@@ -1,12 +1,14 @@
package com.android.codegen
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
+import com.github.javaparser.ast.body.TypeDeclaration
open class ClassInfo(val classAst: ClassOrInterfaceDeclaration, val fileInfo: FileInfo) {
val fileAst = fileInfo.fileAst
val nestedClasses = classAst.members.filterIsInstance<ClassOrInterfaceDeclaration>()
+ val nestedTypes = classAst.members.filterIsInstance<TypeDeclaration<*>>()
val superInterfaces = classAst.implementedTypes.map { it.asString() }
val superClass = classAst.extendedTypes.getOrNull(0)
diff --git a/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
index 69ff18d3f6ab..83108e5ae109 100644
--- a/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
+++ b/tools/codegen/src/com/android/codegen/InputSignaturesComputation.kt
@@ -63,6 +63,7 @@ private fun ClassPrinter.annotationToString(ann: AnnotationExpr?): String {
append("@")
append(getFullClassName(ann.nameAsString))
if (ann is MarkerAnnotationExpr) return@buildString
+ if (!ann.nameAsString.startsWith("DataClass")) return@buildString
append("(")
@@ -128,7 +129,7 @@ private fun ClassPrinter.getFullClassName(className: String): String {
if (classAst.nameAsString == className) return thisPackagePrefix + classAst.nameAsString
- nestedClasses.find {
+ nestedTypes.find {
it.nameAsString == className
}?.let { return thisClassPrefix + it.nameAsString }
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index ca658a972209..2e176c3d3bec 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.18"
+const val CODEGEN_VERSION = "1.0.20"
const val CANONICAL_BUILDER_CLASS = "Builder"
const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
index 51faa49a86cc..1aec9b812e61 100644
--- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
+++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
@@ -98,8 +98,10 @@ class StaleDataclassProcessor: AbstractProcessor() {
private fun elemToString(elem: Element): String {
return buildString {
- append(elem.modifiers.joinToString(" ") { it.name.toLowerCase() }).append(" ")
- append(elem.annotationMirrors.joinToString(" ")).append(" ")
+ append(elem.modifiers.joinToString(" ") { it.name.toLowerCase() })
+ append(" ")
+ append(elem.annotationMirrors.joinToString(" ", transform = { annotationToString(it) }))
+ append(" ")
if (elem is Symbol) {
if (elem.type is Type.MethodType) {
append((elem.type as Type.MethodType).returnType)
@@ -112,6 +114,14 @@ class StaleDataclassProcessor: AbstractProcessor() {
}
}
+ private fun annotationToString(ann: AnnotationMirror): String {
+ return if (ann.annotationType.toString().startsWith("com.android.internal.util.DataClass")) {
+ ann.toString()
+ } else {
+ ann.toString().substringBefore("(")
+ }
+ }
+
private fun processSingleFile(elementAnnotatedWithGenerated: Element) {
val classElement = elementAnnotatedWithGenerated.enclosingElement
diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp
index d3eb012a80e9..e6966db0aa00 100644
--- a/tools/split-select/Main.cpp
+++ b/tools/split-select/Main.cpp
@@ -182,14 +182,18 @@ static bool getAppInfo(const String8& path, AppInfo& outInfo) {
if (type >= Res_value::TYPE_FIRST_INT && type <= Res_value::TYPE_LAST_INT) {
outInfo.minSdkVersion = xml.getAttributeData(idx);
} else if (type == Res_value::TYPE_STRING) {
- String8 minSdk8(xml.getStrings().string8ObjectAt(idx));
- char* endPtr;
- int minSdk = strtol(minSdk8.string(), &endPtr, 10);
- if (endPtr != minSdk8.string() + minSdk8.size()) {
- fprintf(stderr, "warning: failed to parse android:minSdkVersion '%s'\n",
- minSdk8.string());
+ auto minSdk8 = xml.getStrings().string8ObjectAt(idx);
+ if (!minSdk8.has_value()) {
+ fprintf(stderr, "warning: failed to retrieve android:minSdkVersion.\n");
} else {
- outInfo.minSdkVersion = minSdk;
+ char *endPtr;
+ int minSdk = strtol(minSdk8->string(), &endPtr, 10);
+ if (endPtr != minSdk8->string() + minSdk8->size()) {
+ fprintf(stderr, "warning: failed to parse android:minSdkVersion '%s'\n",
+ minSdk8->string());
+ } else {
+ outInfo.minSdkVersion = minSdk;
+ }
}
} else {
fprintf(stderr, "warning: unrecognized value for android:minSdkVersion.\n");
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 43387fc054b5..ab8702b79ab5 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -142,6 +142,9 @@ cc_library {
"libstatspull",
],
},
+ darwin: {
+ enabled: false,
+ },
},
}
diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp
index 2759e29d1620..15b8b4105713 100644
--- a/tools/validatekeymaps/Android.bp
+++ b/tools/validatekeymaps/Android.bp
@@ -16,18 +16,25 @@ cc_binary_host {
static_libs: [
"libbase",
- "libbinder",
"libinput",
"libutils",
"libcutils",
"liblog",
"libui-types",
],
+ target: {
+ linux_glibc: {
+ static_libs: [
+ // libbinder is only available for linux
+ "libbinder",
+ ],
+ },
+ },
// This tool is prebuilt if we're doing an app-only build.
product_variables: {
unbundled_build: {
- enabled: false,
+ enabled: false,
},
},
}
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 0af6266d1642..950473d223fd 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -26,15 +26,15 @@
using namespace android;
-static const char* kProgName = "validatekeymaps";
+static const char* PROG_NAME = "validatekeymaps";
static bool gQuiet = false;
-enum FileType {
- FILETYPE_UNKNOWN,
- FILETYPE_KEYLAYOUT,
- FILETYPE_KEYCHARACTERMAP,
- FILETYPE_VIRTUALKEYDEFINITION,
- FILETYPE_INPUTDEVICECONFIGURATION,
+enum class FileType {
+ UNKNOWN,
+ KEY_LAYOUT,
+ KEY_CHARACTER_MAP,
+ VIRTUAL_KEY_DEFINITION,
+ INPUT_DEVICE_CONFIGURATION,
};
static void log(const char* fmt, ...) {
@@ -57,33 +57,32 @@ static void error(const char* fmt, ...) {
static void usage() {
error("Keymap Validation Tool\n\n");
error("Usage:\n");
- error(
- " %s [-q] [*.kl] [*.kcm] [*.idc] [virtualkeys.*] [...]\n"
- " Validates the specified key layouts, key character maps, \n"
- " input device configurations, or virtual key definitions.\n\n"
- " -q Quiet; do not write anything to standard out.\n",
- kProgName);
+ error(" %s [-q] [*.kl] [*.kcm] [*.idc] [virtualkeys.*] [...]\n"
+ " Validates the specified key layouts, key character maps, \n"
+ " input device configurations, or virtual key definitions.\n\n"
+ " -q Quiet; do not write anything to standard out.\n",
+ PROG_NAME);
}
static FileType getFileType(const char* filename) {
const char *extension = strrchr(filename, '.');
if (extension) {
if (strcmp(extension, ".kl") == 0) {
- return FILETYPE_KEYLAYOUT;
+ return FileType::KEY_LAYOUT;
}
if (strcmp(extension, ".kcm") == 0) {
- return FILETYPE_KEYCHARACTERMAP;
+ return FileType::KEY_CHARACTER_MAP;
}
if (strcmp(extension, ".idc") == 0) {
- return FILETYPE_INPUTDEVICECONFIGURATION;
+ return FileType::INPUT_DEVICE_CONFIGURATION;
}
}
if (strstr(filename, "virtualkeys.")) {
- return FILETYPE_VIRTUALKEYDEFINITION;
+ return FileType::VIRTUAL_KEY_DEFINITION;
}
- return FILETYPE_UNKNOWN;
+ return FileType::UNKNOWN;
}
static bool validateFile(const char* filename) {
@@ -91,48 +90,49 @@ static bool validateFile(const char* filename) {
FileType fileType = getFileType(filename);
switch (fileType) {
- case FILETYPE_UNKNOWN:
- error("Supported file types: *.kl, *.kcm, virtualkeys.*\n\n");
- return false;
-
- case FILETYPE_KEYLAYOUT: {
- base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(filename);
- if (!ret) {
- error("Error %s parsing key layout file.\n\n", ret.error().message().c_str());
+ case FileType::UNKNOWN:
+ error("Supported file types: *.kl, *.kcm, virtualkeys.*\n\n");
return false;
+
+ case FileType::KEY_LAYOUT: {
+ base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(filename);
+ if (!ret) {
+ error("Error %s parsing key layout file.\n\n", ret.error().message().c_str());
+ return false;
+ }
+ break;
}
- break;
- }
- case FILETYPE_KEYCHARACTERMAP: {
- base::Result<std::shared_ptr<KeyCharacterMap>> ret = KeyCharacterMap::load(filename,
- KeyCharacterMap::FORMAT_ANY);
- if (!ret) {
- error("Error %s parsing key character map file.\n\n", ret.error().message().c_str());
- return false;
+ case FileType::KEY_CHARACTER_MAP: {
+ base::Result<std::shared_ptr<KeyCharacterMap>> ret =
+ KeyCharacterMap::load(filename, KeyCharacterMap::Format::ANY);
+ if (!ret) {
+ error("Error %s parsing key character map file.\n\n",
+ ret.error().message().c_str());
+ return false;
+ }
+ break;
}
- break;
- }
- case FILETYPE_INPUTDEVICECONFIGURATION: {
- android::base::Result<std::unique_ptr<PropertyMap>> propertyMap =
- PropertyMap::load(String8(filename));
- if (!propertyMap.ok()) {
- error("Error %d parsing input device configuration file.\n\n",
- propertyMap.error().code());
- return false;
+ case FileType::INPUT_DEVICE_CONFIGURATION: {
+ android::base::Result<std::unique_ptr<PropertyMap>> propertyMap =
+ PropertyMap::load(String8(filename));
+ if (!propertyMap.ok()) {
+ error("Error %d parsing input device configuration file.\n\n",
+ propertyMap.error().code());
+ return false;
+ }
+ break;
}
- break;
- }
- case FILETYPE_VIRTUALKEYDEFINITION: {
- std::unique_ptr<VirtualKeyMap> map = VirtualKeyMap::load(filename);
- if (!map) {
- error("Error while parsing virtual key definition file.\n\n");
- return false;
+ case FileType::VIRTUAL_KEY_DEFINITION: {
+ std::unique_ptr<VirtualKeyMap> map = VirtualKeyMap::load(filename);
+ if (!map) {
+ error("Error while parsing virtual key definition file.\n\n");
+ return false;
+ }
+ break;
}
- break;
- }
}
return true;
diff --git a/wifi/TEST_MAPPING b/wifi/TEST_MAPPING
index fde3a6aa993c..8c515109a309 100644
--- a/wifi/TEST_MAPPING
+++ b/wifi/TEST_MAPPING
@@ -8,5 +8,18 @@
}
]
}
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "FrameworksWifiApiTests[com.google.android.wifi.apex]"
+ },
+ {
+ "name": "CtsWifiTestCases[com.google.android.wifi.apex]",
+ "options": [
+ {
+ "exclude-annotation": "android.net.wifi.cts.VirtualDeviceNotSupported"
+ }
+ ]
+ }
]
}
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index d5ef703253cb..f418eb6fc74b 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -105,6 +105,8 @@ package android.net.wifi {
field @Deprecated public String FQDN;
field @Deprecated public static final int SECURITY_TYPE_EAP = 3; // 0x3
field @Deprecated public static final int SECURITY_TYPE_EAP_SUITE_B = 5; // 0x5
+ field @Deprecated public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE = 9; // 0x9
+ field @Deprecated public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT = 5; // 0x5
field @Deprecated public static final int SECURITY_TYPE_OPEN = 0; // 0x0
field @Deprecated public static final int SECURITY_TYPE_OWE = 6; // 0x6
field @Deprecated public static final int SECURITY_TYPE_PSK = 2; // 0x2
@@ -321,6 +323,7 @@ package android.net.wifi {
method public android.net.DhcpInfo getDhcpInfo();
method public int getMaxNumberOfNetworkSuggestionsPerApp();
method @IntRange(from=0) public int getMaxSignalLevel();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getNetworkSuggestionUserApprovalStatus();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
@@ -342,6 +345,7 @@ package android.net.wifi {
method public boolean isWapiSupported();
method public boolean isWifiEnabled();
method public boolean isWifiStandardSupported(int);
+ method public boolean isWpa3ApValidationSupported();
method public boolean isWpa3SaeSupported();
method public boolean isWpa3SuiteBSupported();
method @Deprecated public boolean pingSupplicant();
@@ -390,6 +394,11 @@ package android.net.wifi {
field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL = 1; // 0x1
field public static final int STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID = 5; // 0x5
field public static final int STATUS_NETWORK_SUGGESTIONS_SUCCESS = 0; // 0x0
+ field public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE = 4; // 0x4
+ field public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER = 2; // 0x2
+ field public static final int STATUS_SUGGESTION_APPROVAL_PENDING = 1; // 0x1
+ field public static final int STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER = 3; // 0x3
+ field public static final int STATUS_SUGGESTION_APPROVAL_UNKNOWN = 0; // 0x0
field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_ASSOCIATION = 1; // 0x1
field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_AUTHENTICATION = 2; // 0x2
field public static final int STATUS_SUGGESTION_CONNECTION_FAILURE_IP_PROVISIONING = 3; // 0x3
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index edbd46300191..5eef6f80ac16 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -321,6 +321,7 @@ package android.net.wifi {
method @Deprecated @NonNull public android.net.IpConfiguration getIpConfiguration();
method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus getNetworkSelectionStatus();
method @Deprecated @NonNull public String getPrintableSsid();
+ method @Deprecated @NonNull public String getProfileKey();
method @Deprecated public int getRecentFailureReason();
method @Deprecated public boolean hasNoInternetAccess();
method @Deprecated public boolean isEphemeral();
diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt
index ff06a180b8c1..d235c80220ca 100644
--- a/wifi/jarjar-rules.txt
+++ b/wifi/jarjar-rules.txt
@@ -114,8 +114,6 @@ rule fi.iki.elonen.** com.android.wifi.x.@0
## used by both framework-wifi and service-wifi ##
rule android.content.pm.BaseParceledListSlice* com.android.wifi.x.@0
rule android.content.pm.ParceledListSlice* com.android.wifi.x.@0
-rule android.net.util.MacAddressUtils* com.android.wifi.x.@0
-rule android.net.util.nsd.DnsSdTxtRecord* com.android.wifi.x.@0
rule android.os.HandlerExecutor* com.android.wifi.x.@0
rule android.telephony.Annotation* com.android.wifi.x.@0
rule com.android.internal.util.AsyncChannel* com.android.wifi.x.@0
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 7329c16d68d0..48e23125e03c 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -275,4 +275,6 @@ interface IWifiManager
void setAutoWakeupEnabled(boolean enable);
boolean isAutoWakeupEnabled();
+
+ int getNetworkSuggestionUserApprovalStatus(String packageName);
}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 73c52ab0ab1b..034defb083de 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -173,7 +173,7 @@ public class RttManager {
/** @deprecated Use the new {@link android.net.wifi.RttManager#getRttCapabilities()} API.*/
@Deprecated
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public Capabilities getCapabilities() {
throw new UnsupportedOperationException(
"getCapabilities is not supported in the adaptation layer");
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index c0f6e7a20f95..e9d1a008eb5f 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -1026,9 +1026,17 @@ public final class SoftApConfiguration implements Parcelable {
+ channels.size() + ") configured");
}
for (int i = 0; i < channels.size(); i++) {
- if (!isChannelBandPairValid(channels.valueAt(i), channels.keyAt(i))) {
- throw new IllegalArgumentException("Invalid channel(" + channels.valueAt(i)
- + ") & band (" + channels.keyAt(i) + ") configured");
+ int channel = channels.valueAt(i);
+ int band = channels.keyAt(i);
+ if (channel == 0) {
+ if (!isBandValid(band)) {
+ throw new IllegalArgumentException("Invalid band type: " + band);
+ }
+ } else {
+ if (!isChannelBandPairValid(channel, band)) {
+ throw new IllegalArgumentException("Invalid channel(" + channel
+ + ") & band (" + band + ") configured");
+ }
}
}
mChannels = channels.clone();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 9298c1ea7836..e1e9757e0f6c 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -29,7 +29,6 @@ import android.net.NetworkSpecifier;
import android.net.ProxyInfo;
import android.net.StaticIpConfiguration;
import android.net.Uri;
-import android.net.util.MacAddressUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -43,6 +42,7 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.MacAddressUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -439,14 +439,27 @@ public class WifiConfiguration implements Parcelable {
public static final int SECURITY_TYPE_EAP = 3;
/** Security type for an SAE network. */
public static final int SECURITY_TYPE_SAE = 4;
- /** Security type for an EAP Suite B network. */
- public static final int SECURITY_TYPE_EAP_SUITE_B = 5;
+ /**
+ * Security type for a WPA3-Enterprise in 192-bit security network.
+ * This is the same as {@link #SECURITY_TYPE_EAP_SUITE_B} and uses the same value.
+ */
+ public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT = 5;
+ /**
+ * Security type for a WPA3-Enterprise in 192-bit security network.
+ * @deprecated Use the {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT} constant
+ * (which is the same value).
+ */
+ @Deprecated
+ public static final int SECURITY_TYPE_EAP_SUITE_B =
+ SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT;
/** Security type for an OWE network. */
public static final int SECURITY_TYPE_OWE = 6;
/** Security type for a WAPI PSK network. */
public static final int SECURITY_TYPE_WAPI_PSK = 7;
/** Security type for a WAPI Certificate network. */
public static final int SECURITY_TYPE_WAPI_CERT = 8;
+ /** Security type for a WPA3-Enterprise network. */
+ public static final int SECURITY_TYPE_EAP_WPA3_ENTERPRISE = 9;
/**
* Security types we support.
@@ -462,7 +475,9 @@ public class WifiConfiguration implements Parcelable {
SECURITY_TYPE_EAP_SUITE_B,
SECURITY_TYPE_OWE,
SECURITY_TYPE_WAPI_PSK,
- SECURITY_TYPE_WAPI_CERT
+ SECURITY_TYPE_WAPI_CERT,
+ SECURITY_TYPE_EAP_WPA3_ENTERPRISE,
+ SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
})
public @interface SecurityType {}
@@ -478,8 +493,10 @@ public class WifiConfiguration implements Parcelable {
* {@link #SECURITY_TYPE_SAE},
* {@link #SECURITY_TYPE_EAP_SUITE_B},
* {@link #SECURITY_TYPE_OWE},
- * {@link #SECURITY_TYPE_WAPI_PSK}, or
- * {@link #SECURITY_TYPE_WAPI_CERT}
+ * {@link #SECURITY_TYPE_WAPI_PSK},
+ * {@link #SECURITY_TYPE_WAPI_CERT},
+ * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE},
+ * {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}
*/
public void setSecurityParams(@SecurityType int securityType) {
// Clear all the bitsets.
@@ -518,7 +535,10 @@ public class WifiConfiguration implements Parcelable {
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
requirePmf = true;
break;
- case SECURITY_TYPE_EAP_SUITE_B:
+ // The value of {@link SECURITY_TYPE_EAP_SUITE_B} is the same as
+ // {@link SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}, remove it to avoid
+ // duplicate case label errors.
+ case SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT:
allowedProtocols.set(WifiConfiguration.Protocol.RSN);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
@@ -555,6 +575,16 @@ public class WifiConfiguration implements Parcelable {
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.SMS4);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.SMS4);
break;
+ case SECURITY_TYPE_EAP_WPA3_ENTERPRISE:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
+ requirePmf = true;
+ break;
default:
throw new IllegalArgumentException("unknown security type " + securityType);
}
@@ -2706,17 +2736,18 @@ public class WifiConfiguration implements Parcelable {
}
/**
- * Get a key for this WifiConfig to generate Persist random Mac Address.
+ * Get a unique key which represent this Wi-Fi network. If two profiles are for
+ * the same Wi-Fi network, but from different provider, they would have the same key.
* @hide
*/
- public String getMacRandomKey() {
+ public String getNetworkKey() {
// Passpoint ephemeral networks have their unique identifier set. Return it as is to be
// able to match internally.
if (mPasspointUniqueId != null) {
return mPasspointUniqueId;
}
- String key = getSsidAndSecurityTypeString();
+ String key = SSID + getDefaultSecurityType();
if (!shared) {
key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
}
@@ -3186,4 +3217,56 @@ public class WifiConfiguration implements Parcelable {
|| allowedKeyManagement.get(KeyMgmt.WAPI_PSK);
}
+ /**
+ * Get a unique key which represent this Wi-Fi configuration profile. If two profiles are for
+ * the same Wi-Fi network, but from different providers (apps, carriers, or data subscriptions),
+ * they would have different keys.
+ * @return a unique key which represent this profile.
+ * @hide
+ */
+ @SystemApi
+ @NonNull public String getProfileKey() {
+ if (mPasspointUniqueId != null) {
+ return mPasspointUniqueId;
+ }
+
+ String key = SSID + getDefaultSecurityType();
+ if (!shared) {
+ key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
+ }
+ if (fromWifiNetworkSuggestion) {
+ key += "_" + creatorName + "-" + carrierId + "-" + subscriptionId;
+ }
+
+ return key;
+ }
+
+ private String getDefaultSecurityType() {
+ String key;
+ if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+ key = KeyMgmt.strings[KeyMgmt.WPA_PSK];
+ } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)
+ || allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+ key = KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ } else if (wepTxKeyIndex >= 0 && wepTxKeyIndex < wepKeys.length
+ && wepKeys[wepTxKeyIndex] != null) {
+ key = "WEP";
+ } else if (allowedKeyManagement.get(KeyMgmt.OWE)) {
+ key = KeyMgmt.strings[KeyMgmt.OWE];
+ } else if (allowedKeyManagement.get(KeyMgmt.SAE)) {
+ key = KeyMgmt.strings[KeyMgmt.SAE];
+ } else if (allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) {
+ key = KeyMgmt.strings[KeyMgmt.SUITE_B_192];
+ } else if (allowedKeyManagement.get(KeyMgmt.WAPI_PSK)) {
+ key = KeyMgmt.strings[KeyMgmt.WAPI_PSK];
+ } else if (allowedKeyManagement.get(KeyMgmt.WAPI_CERT)) {
+ key = KeyMgmt.strings[KeyMgmt.WAPI_CERT];
+ } else if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
+ key = KeyMgmt.strings[KeyMgmt.OSEN];
+ } else {
+ key = KeyMgmt.strings[KeyMgmt.NONE];
+ }
+ return key;
+ }
+
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 8ee08f1610d6..7e04d8ff117d 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -53,6 +53,7 @@ import android.os.Looper;
import android.os.RemoteException;
import android.os.WorkSource;
import android.os.connectivity.WifiActivityEnergyInfo;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.CloseGuard;
import android.util.Log;
@@ -264,6 +265,44 @@ public class WifiManager {
public @interface SuggestionConnectionStatusCode {}
/**
+ * Status code if suggestion approval status is unknown, an App which hasn't made any
+ * suggestions will get this code.
+ */
+ public static final int STATUS_SUGGESTION_APPROVAL_UNKNOWN = 0;
+
+ /**
+ * Status code if the calling app is still pending user approval for suggestions.
+ */
+ public static final int STATUS_SUGGESTION_APPROVAL_PENDING = 1;
+
+ /**
+ * Status code if the calling app got the user approval for suggestions.
+ */
+ public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER = 2;
+
+ /**
+ * Status code if the calling app suggestions were rejected by the user.
+ */
+ public static final int STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER = 3;
+
+ /**
+ * Status code if the calling app was approved by virtue of being a carrier privileged app.
+ * @see TelephonyManager#hasCarrierPrivileges().
+ */
+ public static final int STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE = 4;
+
+ /** @hide */
+ @IntDef(prefix = {"STATUS_SUGGESTION_APPROVAL_"},
+ value = {STATUS_SUGGESTION_APPROVAL_UNKNOWN,
+ STATUS_SUGGESTION_APPROVAL_PENDING,
+ STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER,
+ STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER,
+ STATUS_SUGGESTION_APPROVAL_APPROVED_BY_CARRIER_PRIVILEGE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SuggestionUserApprovalStatus {}
+
+ /**
* Broadcast intent action indicating whether Wi-Fi scanning is currently available.
* Available extras:
* - {@link #EXTRA_SCAN_AVAILABLE}
@@ -2010,6 +2049,26 @@ public class WifiManager {
}
/**
+ * Get the Suggestion approval status of the calling app. When an app makes suggestions using
+ * the {@link #addNetworkSuggestions(List)} API they may trigger a user approval flow. This API
+ * provides the current approval status.
+ *
+ * @return Status code for the user approval. One of the STATUS_SUGGESTION_APPROVAL_ values.
+ * @throws {@link SecurityException} if the caller is missing required permissions.
+ */
+ @RequiresPermission(ACCESS_WIFI_STATE)
+ public @SuggestionUserApprovalStatus int getNetworkSuggestionUserApprovalStatus() {
+ if (!SdkLevel.isAtLeastS()) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return mService.getNetworkSuggestionUserApprovalStatus(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
* Add or update a Passpoint configuration. The configuration provides a credential
* for connecting to Passpoint networks that are operated by the Passpoint
* service provider specified in the configuration.
@@ -2425,6 +2484,9 @@ public class WifiManager {
/** @hide */
public static final long WIFI_FEATURE_FILS_SHA384 = 0x8000000000L; // FILS-SHA384
+ /** @hide */
+ public static final long WIFI_FEATURE_SAE_PK = 0x10000000000L; // SAE-PK
+
private long getSupportedFeatures() {
try {
return mService.getSupportedFeatures();
@@ -5330,6 +5392,13 @@ public class WifiManager {
}
/**
+ * @return true if this device supports WPA3 AP validation.
+ */
+ public boolean isWpa3ApValidationSupported() {
+ return isFeatureSupported(WIFI_FEATURE_SAE_PK);
+ }
+
+ /**
* Gets the factory Wi-Fi MAC addresses.
* @return Array of String representing Wi-Fi MAC addresses sorted lexically or an empty Array
* if failed.
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index 35853c0862c3..be3b45d8c82a 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -367,20 +367,16 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
&& WifiEnterpriseConfig.isSuiteBCipherCert(
mWpa3EnterpriseConfig.getCaCertificate())) {
// WPA3-Enterprise in 192-bit security mode
- configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
+ configuration.setSecurityParams(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
} else if (mWpa3EnterpriseType == WPA3_ENTERPRISE_192_BIT) {
// WPA3-Enterprise in 192-bit security mode
- configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
+ configuration.setSecurityParams(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
} else {
// WPA3-Enterprise
- configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
- configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
- configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
- configuration.allowedPairwiseCiphers.set(
- WifiConfiguration.PairwiseCipher.GCMP_256);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
- configuration.requirePmf = true;
+ configuration.setSecurityParams(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
}
configuration.enterpriseConfig = mWpa3EnterpriseConfig;
} else if (mIsEnhancedOpen) { // OWE network
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index dc6ec907ab95..61831ea9c502 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -796,20 +796,16 @@ public final class WifiNetworkSuggestion implements Parcelable {
&& WifiEnterpriseConfig.isSuiteBCipherCert(
mWpa3EnterpriseConfig.getCaCertificate())) {
// WPA3-Enterprise in 192-bit security mode
- configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
+ configuration.setSecurityParams(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
} else if (mWpa3EnterpriseType == WPA3_ENTERPRISE_192_BIT) {
// WPA3-Enterprise in 192-bit security mode
- configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
+ configuration.setSecurityParams(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
} else {
// WPA3-Enterprise
- configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
- configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
- configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
- configuration.allowedPairwiseCiphers.set(
- WifiConfiguration.PairwiseCipher.GCMP_256);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
- configuration.requirePmf = true;
+ configuration.setSecurityParams(
+ WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
}
configuration.enterpriseConfig = mWpa3EnterpriseConfig;
} else if (mIsEnhancedOpen) { // OWE network
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 41d0857214f3..7c051f0962c4 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -1267,7 +1267,7 @@ public class WifiScanner {
* @param bssidInfos access points to watch
*/
@Deprecated
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void configureWifiChange(
int rssiSampleSize, /* sample size for RSSI averaging */
int lostApSampleSize, /* samples to confirm AP's loss */
@@ -1301,7 +1301,7 @@ public class WifiScanner {
* provided on {@link #stopTrackingWifiChange}
*/
@Deprecated
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void startTrackingWifiChange(WifiChangeListener listener) {
throw new UnsupportedOperationException();
}
@@ -1312,7 +1312,7 @@ public class WifiScanner {
* #stopTrackingWifiChange}
*/
@Deprecated
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void stopTrackingWifiChange(WifiChangeListener listener) {
throw new UnsupportedOperationException();
}
@@ -1320,7 +1320,7 @@ public class WifiScanner {
/** @hide */
@SystemApi
@Deprecated
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void configureWifiChange(WifiChangeSettings settings) {
throw new UnsupportedOperationException();
}
@@ -1376,7 +1376,7 @@ public class WifiScanner {
* also be provided on {@link #stopTrackingBssids}
*/
@Deprecated
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void startTrackingBssids(BssidInfo[] bssidInfos,
int apLostThreshold, BssidListener listener) {
throw new UnsupportedOperationException();
@@ -1387,7 +1387,7 @@ public class WifiScanner {
* @param listener same object provided in {@link #startTrackingBssids}
*/
@Deprecated
- @SuppressLint("Doclava125")
+ @SuppressLint("RequiresPermission")
public void stopTrackingBssids(BssidListener listener) {
throw new UnsupportedOperationException();
}
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
index dad431c1ca2c..e2f40cfa058c 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
@@ -17,10 +17,11 @@
package android.net.wifi.p2p.nsd;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.nsd.DnsSdTxtRecord;
import android.os.Build;
import android.text.TextUtils;
+import com.android.net.module.util.DnsSdTxtRecord;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
index b710a1492d8c..7272e146f4f8 100644
--- a/wifi/tests/Android.bp
+++ b/wifi/tests/Android.bp
@@ -45,7 +45,7 @@ android_test {
],
test_suites: [
- "device-tests",
+ "general-tests",
"mts",
],
diff --git a/wifi/tests/AndroidTest.xml b/wifi/tests/AndroidTest.xml
index 34e2e3af9cda..2cdaddb59018 100644
--- a/wifi/tests/AndroidTest.xml
+++ b/wifi/tests/AndroidTest.xml
@@ -20,6 +20,8 @@
<option name="test-suite-tag" value="apct" />
<option name="test-tag" value="FrameworksWifiApiTests" />
+ <option name="config-descriptor:metadata" key="mainline-param"
+ value="com.google.android.wifi.apex" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.net.wifi.test" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 4a94f1f47962..ad0fdd3bce26 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -398,6 +398,21 @@ public class SoftApConfigurationTest {
assertThat(dual_channels_config.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
assertTrue(dual_channels.toString().equals(dual_channels_config.getChannels().toString()));
assertThat(dual_channels_config.getChannel()).isEqualTo(2);
+
+ // Test different parameters.
+ dual_channels.clear();
+ dual_channels.put(SoftApConfiguration.BAND_5GHZ, 149);
+ dual_channels.put(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ, 0);
+ expected_dual_bands[0] = SoftApConfiguration.BAND_5GHZ;
+ expected_dual_bands[1] = SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ;
+ dual_channels_config = new SoftApConfiguration.Builder()
+ .setSsid("ssid")
+ .setChannels(dual_channels)
+ .build();
+ assertTrue(Arrays.equals(expected_dual_bands, dual_channels_config.getBands()));
+ assertThat(dual_channels_config.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
+ assertTrue(dual_channels.toString().equals(dual_channels_config.getChannels().toString()));
+ assertThat(dual_channels_config.getChannel()).isEqualTo(149);
}
@Test
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index f09c37d811f9..c88132493e67 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -17,7 +17,8 @@
package android.net.wifi;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP;
-import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OPEN;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE;
import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK;
@@ -33,13 +34,14 @@ import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import android.net.MacAddress;
-import android.net.util.MacAddressUtils;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
+import com.android.net.module.util.MacAddressUtils;
+
import org.junit.Before;
import org.junit.Test;
@@ -49,6 +51,9 @@ import org.junit.Test;
@SmallTest
public class WifiConfigurationTest {
private static final String TEST_PASSPOINT_UNIQUE_ID = "uniqueId";
+ private static final int TEST_CARRIER_ID = 1234;
+ private static final int TEST_SUB_ID = 3;
+ private static final String TEST_PACKAGE_NAME = "google.com";
@Before
public void setUp() {
@@ -421,11 +426,11 @@ public class WifiConfigurationTest {
}
/**
- * Verifies that getMacRandomKey returns the correct String for networks of
+ * Verifies that getNetworkKey returns the correct String for networks of
* various different security types, the result should be stable.
*/
@Test
- public void testGetMacRandomKeyString() {
+ public void testGetNetworkKeyString() {
WifiConfiguration config = new WifiConfiguration();
final String mSsid = "TestAP";
config.SSID = mSsid;
@@ -433,23 +438,23 @@ public class WifiConfigurationTest {
// Test various combinations
config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WPA_PSK],
- config.getMacRandomKey());
+ config.getNetworkKey());
config.allowedKeyManagement.clear();
config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WPA_EAP],
- config.getMacRandomKey());
+ config.getNetworkKey());
config.wepKeys[0] = "TestWep";
config.allowedKeyManagement.clear();
- assertEquals(mSsid + "WEP", config.getMacRandomKey());
+ assertEquals(mSsid + "WEP", config.getNetworkKey());
// set WEP key and give a valid index.
config.wepKeys[0] = null;
config.wepKeys[2] = "TestWep";
config.wepTxKeyIndex = 2;
config.allowedKeyManagement.clear();
- assertEquals(mSsid + "WEP", config.getMacRandomKey());
+ assertEquals(mSsid + "WEP", config.getNetworkKey());
// set WEP key but does not give a valid index.
config.wepKeys[0] = null;
@@ -457,40 +462,40 @@ public class WifiConfigurationTest {
config.wepTxKeyIndex = 0;
config.allowedKeyManagement.clear();
config.allowedKeyManagement.set(KeyMgmt.OWE);
- assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getMacRandomKey());
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getNetworkKey());
config.wepKeys[0] = null;
config.wepTxKeyIndex = 0;
config.allowedKeyManagement.clear();
config.allowedKeyManagement.set(KeyMgmt.OWE);
- assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getMacRandomKey());
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getNetworkKey());
config.allowedKeyManagement.clear();
config.allowedKeyManagement.set(KeyMgmt.SAE);
- assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SAE], config.getMacRandomKey());
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SAE], config.getNetworkKey());
config.allowedKeyManagement.clear();
config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SUITE_B_192],
- config.getMacRandomKey());
+ config.getNetworkKey());
config.allowedKeyManagement.clear();
config.allowedKeyManagement.set(KeyMgmt.NONE);
- assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.NONE], config.getMacRandomKey());
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.NONE], config.getNetworkKey());
config.allowedKeyManagement.clear();
config.allowedKeyManagement.set(KeyMgmt.WAPI_PSK);
assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_PSK],
- config.getMacRandomKey());
+ config.getNetworkKey());
config.allowedKeyManagement.clear();
config.allowedKeyManagement.set(KeyMgmt.WAPI_CERT);
assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_CERT],
- config.getMacRandomKey());
+ config.getNetworkKey());
config.allowedKeyManagement.clear();
config.setPasspointUniqueId(TEST_PASSPOINT_UNIQUE_ID);
- assertEquals(TEST_PASSPOINT_UNIQUE_ID, config.getMacRandomKey());
+ assertEquals(TEST_PASSPOINT_UNIQUE_ID, config.getNetworkKey());
}
/**
@@ -568,7 +573,7 @@ public class WifiConfigurationTest {
public void testSetSecurityParamsForSuiteB() throws Exception {
WifiConfiguration config = new WifiConfiguration();
- config.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
+ config.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192));
assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
@@ -581,6 +586,26 @@ public class WifiConfigurationTest {
}
/**
+ * Ensure that {@link WifiConfiguration#setSecurityParams(int)} sets up the
+ * {@link WifiConfiguration} object correctly for WPA3 Enterprise security type.
+ * @throws Exception
+ */
+ @Test
+ public void testSetSecurityParamsForWpa3Enterprise() throws Exception {
+ WifiConfiguration config = new WifiConfiguration();
+
+ config.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
+ assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
+ assertTrue(config.requirePmf);
+ }
+
+ /**
* Test that the NetworkSelectionStatus Builder returns the same values that was set, and that
* calling build multiple times returns different instances.
*/
@@ -641,7 +666,10 @@ public class WifiConfigurationTest {
configuration.setSecurityParams(SECURITY_TYPE_EAP);
assertFalse(configuration.needsPreSharedKey());
- configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
+ configuration.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+ assertFalse(configuration.needsPreSharedKey());
+
+ configuration.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
assertFalse(configuration.needsPreSharedKey());
}
@@ -667,7 +695,10 @@ public class WifiConfigurationTest {
configuration.setSecurityParams(SECURITY_TYPE_EAP);
assertEquals(KeyMgmt.WPA_EAP, configuration.getAuthType());
- configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
+ configuration.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+ assertEquals(KeyMgmt.WPA_EAP, configuration.getAuthType());
+
+ configuration.setSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
assertEquals(KeyMgmt.SUITE_B_192, configuration.getAuthType());
configuration.setSecurityParams(SECURITY_TYPE_WAPI_CERT);
@@ -692,4 +723,142 @@ public class WifiConfigurationTest {
configuration.allowedKeyManagement.set(KeyMgmt.SAE);
configuration.getAuthType();
}
+
+ /**
+ * Verifies that getProfileKey returns the correct String for networks of
+ * various different security types, the result should be stable.
+ */
+ @Test
+ public void testGetProfileKeyString() {
+ WifiConfiguration config = new WifiConfiguration();
+ final String mSsid = "TestAP";
+ config.SSID = mSsid;
+ config.carrierId = TEST_CARRIER_ID;
+ config.subscriptionId = TEST_SUB_ID;
+ config.creatorName = TEST_PACKAGE_NAME;
+
+
+ // Test various combinations
+ config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+ config.fromWifiNetworkSuggestion = false;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WPA_PSK], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+ config.fromWifiNetworkSuggestion = true;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WPA_PSK], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+ config.fromWifiNetworkSuggestion = false;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WPA_EAP], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+ config.fromWifiNetworkSuggestion = true;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WPA_EAP], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+ config.wepKeys[0] = "TestWep";
+ config.allowedKeyManagement.clear();
+ config.fromWifiNetworkSuggestion = false;
+ assertEquals(createProfileKey(mSsid, "WEP", TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+ config.fromWifiNetworkSuggestion = true;
+ assertEquals(createProfileKey(mSsid, "WEP", TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+ // set WEP key and give a valid index.
+ config.wepKeys[0] = null;
+ config.wepKeys[2] = "TestWep";
+ config.wepTxKeyIndex = 2;
+ config.allowedKeyManagement.clear();
+ config.fromWifiNetworkSuggestion = false;
+ assertEquals(createProfileKey(mSsid, "WEP", TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+ config.fromWifiNetworkSuggestion = true;
+ assertEquals(createProfileKey(mSsid, "WEP", TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+ // set WEP key but does not give a valid index.
+ config.wepKeys[0] = null;
+ config.wepKeys[2] = "TestWep";
+ config.wepTxKeyIndex = 0;
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.OWE);
+ config.fromWifiNetworkSuggestion = false;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.OWE], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+ config.fromWifiNetworkSuggestion = true;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.OWE], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+ config.wepKeys[0] = null;
+ config.wepTxKeyIndex = 0;
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.OWE);
+ config.fromWifiNetworkSuggestion = false;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.OWE], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+ config.fromWifiNetworkSuggestion = true;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.OWE], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.SAE);
+ config.fromWifiNetworkSuggestion = false;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.SAE], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+ config.fromWifiNetworkSuggestion = true;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.SAE], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
+ config.fromWifiNetworkSuggestion = false;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.SUITE_B_192],
+ TEST_PACKAGE_NAME, TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+ config.fromWifiNetworkSuggestion = true;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.SUITE_B_192],
+ TEST_PACKAGE_NAME, TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.NONE);
+ config.fromWifiNetworkSuggestion = false;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.NONE], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+ config.fromWifiNetworkSuggestion = true;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.NONE], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.WAPI_PSK);
+ config.fromWifiNetworkSuggestion = false;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WAPI_PSK], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+ config.fromWifiNetworkSuggestion = true;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WAPI_PSK], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.WAPI_CERT);
+ config.fromWifiNetworkSuggestion = false;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WAPI_CERT], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, false), config.getProfileKey());
+ config.fromWifiNetworkSuggestion = true;
+ assertEquals(createProfileKey(mSsid, KeyMgmt.strings[KeyMgmt.WAPI_CERT], TEST_PACKAGE_NAME,
+ TEST_CARRIER_ID, TEST_SUB_ID, true), config.getProfileKey());
+
+ config.allowedKeyManagement.clear();
+ config.setPasspointUniqueId(TEST_PASSPOINT_UNIQUE_ID);
+ assertEquals(TEST_PASSPOINT_UNIQUE_ID, config.getProfileKey());
+ }
+
+ private String createProfileKey(String ssid, String keyMgmt, String providerName,
+ int carrierId, int subId, boolean isFromSuggestion) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(ssid).append(keyMgmt);
+ if (isFromSuggestion) {
+ sb.append("_").append(providerName).append('-')
+ .append(carrierId).append('-').append(subId);
+ }
+ return sb.toString();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 7340b145e8b2..572924757226 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -2415,4 +2415,13 @@ public class WifiManagerTest {
assertFalse(mWifiManager.isScanAlwaysAvailable());
verify(mWifiService).isScanAlwaysAvailable();
}
+
+ @Test
+ public void testGetNetworkSuggestionUserApprovalStatus() throws Exception {
+ when(mWifiService.getNetworkSuggestionUserApprovalStatus(TEST_PACKAGE_NAME))
+ .thenReturn(WifiManager.STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER);
+ assertEquals(WifiManager.STATUS_SUGGESTION_APPROVAL_APPROVED_BY_USER,
+ mWifiManager.getNetworkSuggestionUserApprovalStatus());
+ verify(mWifiService).getNetworkSuggestionUserApprovalStatus(TEST_PACKAGE_NAME);
+ }
}